github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/fsimpl/fuse/request_response.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fuse 16 17 import ( 18 "golang.org/x/sys/unix" 19 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 20 "github.com/nicocha30/gvisor-ligolo/pkg/context" 21 "github.com/nicocha30/gvisor-ligolo/pkg/errors/linuxerr" 22 "github.com/nicocha30/gvisor-ligolo/pkg/hostarch" 23 "github.com/nicocha30/gvisor-ligolo/pkg/log" 24 "github.com/nicocha30/gvisor-ligolo/pkg/marshal" 25 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/kernel/auth" 26 ) 27 28 // fuseInitRes is a variable-length wrapper of linux.FUSEInitOut. The FUSE 29 // server may implement an older version of FUSE protocol, which contains a 30 // linux.FUSEInitOut with less attributes. 31 // 32 // +marshal dynamic 33 type fuseInitRes struct { 34 // initOut contains the response from the FUSE server. 35 initOut linux.FUSEInitOut 36 37 // initLen is the total length of bytes of the response. 38 initLen uint32 39 } 40 41 func (r *fuseInitRes) MarshalBytes(src []byte) []byte { 42 panic("Unimplemented, fuseInitRes should never be marshalled") 43 } 44 45 // UnmarshalBytes deserializes src to the initOut attribute in a fuseInitRes. 46 func (r *fuseInitRes) UnmarshalBytes(src []byte) []byte { 47 out := &r.initOut 48 49 // Introduced before FUSE kernel version 7.13. 50 out.Major = uint32(hostarch.ByteOrder.Uint32(src[:4])) 51 src = src[4:] 52 out.Minor = uint32(hostarch.ByteOrder.Uint32(src[:4])) 53 src = src[4:] 54 out.MaxReadahead = uint32(hostarch.ByteOrder.Uint32(src[:4])) 55 src = src[4:] 56 out.Flags = uint32(hostarch.ByteOrder.Uint32(src[:4])) 57 src = src[4:] 58 out.MaxBackground = uint16(hostarch.ByteOrder.Uint16(src[:2])) 59 src = src[2:] 60 out.CongestionThreshold = uint16(hostarch.ByteOrder.Uint16(src[:2])) 61 src = src[2:] 62 out.MaxWrite = uint32(hostarch.ByteOrder.Uint32(src[:4])) 63 src = src[4:] 64 65 // Introduced in FUSE kernel version 7.23. 66 if len(src) >= 4 { 67 out.TimeGran = uint32(hostarch.ByteOrder.Uint32(src[:4])) 68 src = src[4:] 69 } 70 // Introduced in FUSE kernel version 7.28. 71 if len(src) >= 2 { 72 out.MaxPages = uint16(hostarch.ByteOrder.Uint16(src[:2])) 73 src = src[2:] 74 } 75 return src 76 } 77 78 // SizeBytes is the size of the payload of the FUSE_INIT response. 79 func (r *fuseInitRes) SizeBytes() int { 80 return int(r.initLen) 81 } 82 83 // Ordinary requests have even IDs, while interrupts IDs are odd. 84 // Used to increment the unique ID for each FUSE request. 85 var reqIDStep uint64 = 2 86 87 // Request represents a FUSE operation request that hasn't been sent to the 88 // server yet. 89 // 90 // +stateify savable 91 type Request struct { 92 requestEntry 93 94 id linux.FUSEOpID 95 hdr *linux.FUSEHeaderIn 96 data []byte 97 98 // If this request is async. 99 async bool 100 // If we don't care its response. 101 // Manually set by the caller. 102 noReply bool 103 } 104 105 // NewRequest creates a new request that can be sent to the FUSE server. 106 func (conn *connection) NewRequest(creds *auth.Credentials, pid uint32, ino uint64, opcode linux.FUSEOpcode, payload marshal.Marshallable) *Request { 107 conn.fd.mu.Lock() 108 defer conn.fd.mu.Unlock() 109 conn.fd.nextOpID += linux.FUSEOpID(reqIDStep) 110 111 hdr := linux.FUSEHeaderIn{ 112 Len: linux.SizeOfFUSEHeaderIn + uint32(payload.SizeBytes()), 113 Opcode: opcode, 114 Unique: conn.fd.nextOpID, 115 NodeID: ino, 116 UID: uint32(creds.EffectiveKUID), 117 GID: uint32(creds.EffectiveKGID), 118 PID: pid, 119 } 120 121 buf := make([]byte, hdr.Len) 122 123 hdr.MarshalUnsafe(buf[:linux.SizeOfFUSEHeaderIn]) 124 payload.MarshalUnsafe(buf[linux.SizeOfFUSEHeaderIn:]) 125 126 return &Request{ 127 id: hdr.Unique, 128 hdr: &hdr, 129 data: buf, 130 } 131 } 132 133 // futureResponse represents an in-flight request, that may or may not have 134 // completed yet. Convert it to a resolved Response by calling Resolve, but note 135 // that this may block. 136 // 137 // +stateify savable 138 type futureResponse struct { 139 opcode linux.FUSEOpcode 140 ch chan struct{} 141 hdr *linux.FUSEHeaderOut 142 data []byte 143 144 // If this request is async. 145 async bool 146 } 147 148 // newFutureResponse creates a future response to a FUSE request. 149 func newFutureResponse(req *Request) *futureResponse { 150 return &futureResponse{ 151 opcode: req.hdr.Opcode, 152 ch: make(chan struct{}), 153 async: req.async, 154 } 155 } 156 157 // resolve blocks the task until the server responds to its corresponding request, 158 // then returns a resolved response. 159 func (f *futureResponse) resolve(b context.Blocker) (*Response, error) { 160 // Return directly for async requests. 161 if f.async { 162 return nil, nil 163 } 164 165 if err := b.Block(f.ch); err != nil { 166 return nil, err 167 } 168 169 return f.getResponse(), nil 170 } 171 172 // getResponse creates a Response from the data the futureResponse has. 173 func (f *futureResponse) getResponse() *Response { 174 return &Response{ 175 opcode: f.opcode, 176 hdr: *f.hdr, 177 data: f.data, 178 } 179 } 180 181 // Response represents an actual response from the server, including the 182 // response payload. 183 // 184 // +stateify savable 185 type Response struct { 186 opcode linux.FUSEOpcode 187 hdr linux.FUSEHeaderOut 188 data []byte 189 } 190 191 // Error returns the error of the FUSE call. 192 func (r *Response) Error() error { 193 errno := r.hdr.Error 194 if errno >= 0 { 195 return nil 196 } 197 198 sysErrNo := unix.Errno(-errno) 199 return error(sysErrNo) 200 } 201 202 // DataLen returns the size of the response without the header. 203 func (r *Response) DataLen() uint32 { 204 return r.hdr.Len - uint32(r.hdr.SizeBytes()) 205 } 206 207 // UnmarshalPayload unmarshals the response data into m. 208 func (r *Response) UnmarshalPayload(m marshal.Marshallable) error { 209 hdrLen := r.hdr.SizeBytes() 210 haveDataLen := r.hdr.Len - uint32(hdrLen) 211 wantDataLen := uint32(m.SizeBytes()) 212 213 if haveDataLen < wantDataLen { 214 log.Warningf("fusefs: Payload too small. Minimum data length required: %d, but got data length %d", wantDataLen, haveDataLen) 215 return linuxerr.EINVAL 216 217 } 218 219 // The response data is empty unless there is some payload. And so, doesn't 220 // need to be unmarshalled. 221 if r.data == nil { 222 return nil 223 } 224 225 m.UnmarshalUnsafe(r.data[hdrLen:]) 226 return nil 227 }