github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/kernel/task_usermem.go (about) 1 // Copyright 2018 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 kernel 16 17 import ( 18 "math" 19 20 "github.com/SagerNet/gvisor/pkg/abi/linux" 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 23 "github.com/SagerNet/gvisor/pkg/hostarch" 24 "github.com/SagerNet/gvisor/pkg/sentry/mm" 25 "github.com/SagerNet/gvisor/pkg/syserror" 26 "github.com/SagerNet/gvisor/pkg/usermem" 27 ) 28 29 // MAX_RW_COUNT is the maximum size in bytes of a single read or write. 30 // Reads and writes that exceed this size may be silently truncated. 31 // (Linux: include/linux/fs.h:MAX_RW_COUNT) 32 var MAX_RW_COUNT = int(hostarch.Addr(math.MaxInt32).RoundDown()) 33 34 // Activate ensures that the task has an active address space. 35 func (t *Task) Activate() { 36 if mm := t.MemoryManager(); mm != nil { 37 if err := mm.Activate(t); err != nil { 38 panic("unable to activate mm: " + err.Error()) 39 } 40 } 41 } 42 43 // Deactivate relinquishes the task's active address space. 44 func (t *Task) Deactivate() { 45 if mm := t.MemoryManager(); mm != nil { 46 mm.Deactivate() 47 } 48 } 49 50 // CopyInBytes is a fast version of CopyIn if the caller can serialize the 51 // data without reflection and pass in a byte slice. 52 // 53 // This Task's AddressSpace must be active. 54 func (t *Task) CopyInBytes(addr hostarch.Addr, dst []byte) (int, error) { 55 return t.MemoryManager().CopyIn(t, addr, dst, usermem.IOOpts{ 56 AddressSpaceActive: true, 57 }) 58 } 59 60 // CopyOutBytes is a fast version of CopyOut if the caller can serialize the 61 // data without reflection and pass in a byte slice. 62 // 63 // This Task's AddressSpace must be active. 64 func (t *Task) CopyOutBytes(addr hostarch.Addr, src []byte) (int, error) { 65 return t.MemoryManager().CopyOut(t, addr, src, usermem.IOOpts{ 66 AddressSpaceActive: true, 67 }) 68 } 69 70 // CopyInString copies a NUL-terminated string of length at most maxlen in from 71 // the task's memory. The copy will fail with syscall.EFAULT if it traverses 72 // user memory that is unmapped or not readable by the user. 73 // 74 // This Task's AddressSpace must be active. 75 func (t *Task) CopyInString(addr hostarch.Addr, maxlen int) (string, error) { 76 return usermem.CopyStringIn(t, t.MemoryManager(), addr, maxlen, usermem.IOOpts{ 77 AddressSpaceActive: true, 78 }) 79 } 80 81 // CopyInVector copies a NULL-terminated vector of strings from the task's 82 // memory. The copy will fail with syscall.EFAULT if it traverses 83 // user memory that is unmapped or not readable by the user. 84 // 85 // maxElemSize is the maximum size of each individual element. 86 // 87 // maxTotalSize is the maximum total length of all elements plus the total 88 // number of elements. For example, the following strings correspond to 89 // the following set of sizes: 90 // 91 // { "a", "b", "c" } => 6 (3 for lengths, 3 for elements) 92 // { "abc" } => 4 (3 for length, 1 for elements) 93 // 94 // This Task's AddressSpace must be active. 95 func (t *Task) CopyInVector(addr hostarch.Addr, maxElemSize, maxTotalSize int) ([]string, error) { 96 var v []string 97 for { 98 argAddr := t.Arch().Native(0) 99 if _, err := argAddr.CopyIn(t, addr); err != nil { 100 return v, err 101 } 102 if t.Arch().Value(argAddr) == 0 { 103 break 104 } 105 // Each string has a zero terminating byte counted, so copying out a string 106 // requires at least one byte of space. Also, see the calculation below. 107 if maxTotalSize <= 0 { 108 return nil, syserror.ENOMEM 109 } 110 thisMax := maxElemSize 111 if maxTotalSize < thisMax { 112 thisMax = maxTotalSize 113 } 114 arg, err := t.CopyInString(hostarch.Addr(t.Arch().Value(argAddr)), thisMax) 115 if err != nil { 116 return v, err 117 } 118 v = append(v, arg) 119 addr += hostarch.Addr(t.Arch().Width()) 120 maxTotalSize -= len(arg) + 1 121 } 122 return v, nil 123 } 124 125 // CopyOutIovecs converts src to an array of struct iovecs and copies it to the 126 // memory mapped at addr. 127 // 128 // Preconditions: Same as usermem.IO.CopyOut, plus: 129 // * The caller must be running on the task goroutine. 130 // * t's AddressSpace must be active. 131 func (t *Task) CopyOutIovecs(addr hostarch.Addr, src hostarch.AddrRangeSeq) error { 132 switch t.Arch().Width() { 133 case 8: 134 const itemLen = 16 135 if _, ok := addr.AddLength(uint64(src.NumRanges()) * itemLen); !ok { 136 return syserror.EFAULT 137 } 138 139 b := t.CopyScratchBuffer(itemLen) 140 for ; !src.IsEmpty(); src = src.Tail() { 141 ar := src.Head() 142 hostarch.ByteOrder.PutUint64(b[0:8], uint64(ar.Start)) 143 hostarch.ByteOrder.PutUint64(b[8:16], uint64(ar.Length())) 144 if _, err := t.CopyOutBytes(addr, b); err != nil { 145 return err 146 } 147 addr += itemLen 148 } 149 150 default: 151 return syserror.ENOSYS 152 } 153 154 return nil 155 } 156 157 // CopyInIovecs copies an array of numIovecs struct iovecs from the memory 158 // mapped at addr, converts them to hostarch.AddrRanges, and returns them as a 159 // hostarch.AddrRangeSeq. 160 // 161 // CopyInIovecs shares the following properties with Linux's 162 // lib/iov_iter.c:import_iovec() => fs/read_write.c:rw_copy_check_uvector(): 163 // 164 // - If the length of any AddrRange would exceed the range of an ssize_t, 165 // CopyInIovecs returns EINVAL. 166 // 167 // - If the length of any AddrRange would cause its end to overflow, 168 // CopyInIovecs returns EFAULT. 169 // 170 // - If any AddrRange would include addresses outside the application address 171 // range, CopyInIovecs returns EFAULT. 172 // 173 // - The combined length of all AddrRanges is limited to MAX_RW_COUNT. If the 174 // combined length of all AddrRanges would otherwise exceed this amount, ranges 175 // beyond MAX_RW_COUNT are silently truncated. 176 // 177 // Preconditions: Same as usermem.IO.CopyIn, plus: 178 // * The caller must be running on the task goroutine. 179 // * t's AddressSpace must be active. 180 func (t *Task) CopyInIovecs(addr hostarch.Addr, numIovecs int) (hostarch.AddrRangeSeq, error) { 181 if numIovecs == 0 { 182 return hostarch.AddrRangeSeq{}, nil 183 } 184 185 var dst []hostarch.AddrRange 186 if numIovecs > 1 { 187 dst = make([]hostarch.AddrRange, 0, numIovecs) 188 } 189 190 switch t.Arch().Width() { 191 case 8: 192 const itemLen = 16 193 if _, ok := addr.AddLength(uint64(numIovecs) * itemLen); !ok { 194 return hostarch.AddrRangeSeq{}, syserror.EFAULT 195 } 196 197 b := t.CopyScratchBuffer(itemLen) 198 for i := 0; i < numIovecs; i++ { 199 if _, err := t.CopyInBytes(addr, b); err != nil { 200 return hostarch.AddrRangeSeq{}, err 201 } 202 203 base := hostarch.Addr(hostarch.ByteOrder.Uint64(b[0:8])) 204 length := hostarch.ByteOrder.Uint64(b[8:16]) 205 if length > math.MaxInt64 { 206 return hostarch.AddrRangeSeq{}, linuxerr.EINVAL 207 } 208 ar, ok := t.MemoryManager().CheckIORange(base, int64(length)) 209 if !ok { 210 return hostarch.AddrRangeSeq{}, syserror.EFAULT 211 } 212 213 if numIovecs == 1 { 214 // Special case to avoid allocating dst. 215 return hostarch.AddrRangeSeqOf(ar).TakeFirst(MAX_RW_COUNT), nil 216 } 217 dst = append(dst, ar) 218 219 addr += itemLen 220 } 221 222 default: 223 return hostarch.AddrRangeSeq{}, syserror.ENOSYS 224 } 225 226 // Truncate to MAX_RW_COUNT. 227 var total uint64 228 for i := range dst { 229 dstlen := uint64(dst[i].Length()) 230 if rem := uint64(MAX_RW_COUNT) - total; rem < dstlen { 231 dst[i].End -= hostarch.Addr(dstlen - rem) 232 dstlen = rem 233 } 234 total += dstlen 235 } 236 237 return hostarch.AddrRangeSeqFromSlice(dst), nil 238 } 239 240 // SingleIOSequence returns a usermem.IOSequence representing [addr, 241 // addr+length) in t's address space. If this contains addresses outside the 242 // application address range, it returns EFAULT. If length exceeds 243 // MAX_RW_COUNT, the range is silently truncated. 244 // 245 // SingleIOSequence is analogous to Linux's 246 // lib/iov_iter.c:import_single_range(). (Note that the non-vectorized read and 247 // write syscalls in Linux do not use import_single_range(). However they check 248 // access_ok() in fs/read_write.c:vfs_read/vfs_write, and overflowing address 249 // ranges are truncated to MAX_RW_COUNT by fs/read_write.c:rw_verify_area().) 250 func (t *Task) SingleIOSequence(addr hostarch.Addr, length int, opts usermem.IOOpts) (usermem.IOSequence, error) { 251 if length > MAX_RW_COUNT { 252 length = MAX_RW_COUNT 253 } 254 ar, ok := t.MemoryManager().CheckIORange(addr, int64(length)) 255 if !ok { 256 return usermem.IOSequence{}, syserror.EFAULT 257 } 258 return usermem.IOSequence{ 259 IO: t.MemoryManager(), 260 Addrs: hostarch.AddrRangeSeqOf(ar), 261 Opts: opts, 262 }, nil 263 } 264 265 // IovecsIOSequence returns a usermem.IOSequence representing the array of 266 // iovcnt struct iovecs at addr in t's address space. opts applies to the 267 // returned IOSequence, not the reading of the struct iovec array. 268 // 269 // IovecsIOSequence is analogous to Linux's lib/iov_iter.c:import_iovec(). 270 // 271 // Preconditions: Same as Task.CopyInIovecs. 272 func (t *Task) IovecsIOSequence(addr hostarch.Addr, iovcnt int, opts usermem.IOOpts) (usermem.IOSequence, error) { 273 if iovcnt < 0 || iovcnt > linux.UIO_MAXIOV { 274 return usermem.IOSequence{}, linuxerr.EINVAL 275 } 276 ars, err := t.CopyInIovecs(addr, iovcnt) 277 if err != nil { 278 return usermem.IOSequence{}, err 279 } 280 return usermem.IOSequence{ 281 IO: t.MemoryManager(), 282 Addrs: ars, 283 Opts: opts, 284 }, nil 285 } 286 287 type taskCopyContext struct { 288 ctx context.Context 289 t *Task 290 opts usermem.IOOpts 291 } 292 293 // CopyContext returns a marshal.CopyContext that copies to/from t's address 294 // space using opts. 295 func (t *Task) CopyContext(ctx context.Context, opts usermem.IOOpts) *taskCopyContext { 296 return &taskCopyContext{ 297 ctx: ctx, 298 t: t, 299 opts: opts, 300 } 301 } 302 303 // CopyScratchBuffer implements marshal.CopyContext.CopyScratchBuffer. 304 func (cc *taskCopyContext) CopyScratchBuffer(size int) []byte { 305 if ctxTask, ok := cc.ctx.(*Task); ok { 306 return ctxTask.CopyScratchBuffer(size) 307 } 308 return make([]byte, size) 309 } 310 311 func (cc *taskCopyContext) getMemoryManager() (*mm.MemoryManager, error) { 312 cc.t.mu.Lock() 313 tmm := cc.t.MemoryManager() 314 cc.t.mu.Unlock() 315 if !tmm.IncUsers() { 316 return nil, syserror.EFAULT 317 } 318 return tmm, nil 319 } 320 321 // CopyInBytes implements marshal.CopyContext.CopyInBytes. 322 func (cc *taskCopyContext) CopyInBytes(addr hostarch.Addr, dst []byte) (int, error) { 323 tmm, err := cc.getMemoryManager() 324 if err != nil { 325 return 0, err 326 } 327 defer tmm.DecUsers(cc.ctx) 328 return tmm.CopyIn(cc.ctx, addr, dst, cc.opts) 329 } 330 331 // CopyOutBytes implements marshal.CopyContext.CopyOutBytes. 332 func (cc *taskCopyContext) CopyOutBytes(addr hostarch.Addr, src []byte) (int, error) { 333 tmm, err := cc.getMemoryManager() 334 if err != nil { 335 return 0, err 336 } 337 defer tmm.DecUsers(cc.ctx) 338 return tmm.CopyOut(cc.ctx, addr, src, cc.opts) 339 } 340 341 type ownTaskCopyContext struct { 342 t *Task 343 opts usermem.IOOpts 344 } 345 346 // OwnCopyContext returns a marshal.CopyContext that copies to/from t's address 347 // space using opts. The returned CopyContext may only be used by t's task 348 // goroutine. 349 // 350 // Since t already implements marshal.CopyContext, this is only needed to 351 // override the usermem.IOOpts used for the copy. 352 func (t *Task) OwnCopyContext(opts usermem.IOOpts) *ownTaskCopyContext { 353 return &ownTaskCopyContext{ 354 t: t, 355 opts: opts, 356 } 357 } 358 359 // CopyScratchBuffer implements marshal.CopyContext.CopyScratchBuffer. 360 func (cc *ownTaskCopyContext) CopyScratchBuffer(size int) []byte { 361 return cc.t.CopyScratchBuffer(size) 362 } 363 364 // CopyInBytes implements marshal.CopyContext.CopyInBytes. 365 func (cc *ownTaskCopyContext) CopyInBytes(addr hostarch.Addr, dst []byte) (int, error) { 366 return cc.t.MemoryManager().CopyIn(cc.t, addr, dst, cc.opts) 367 } 368 369 // CopyOutBytes implements marshal.CopyContext.CopyOutBytes. 370 func (cc *ownTaskCopyContext) CopyOutBytes(addr hostarch.Addr, src []byte) (int, error) { 371 return cc.t.MemoryManager().CopyOut(cc.t, addr, src, cc.opts) 372 }