github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/usermem/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 usermem governs access to user memory. 16 package usermem 17 18 import ( 19 "bytes" 20 "errors" 21 "io" 22 "strconv" 23 24 "github.com/SagerNet/gvisor/pkg/context" 25 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 26 "github.com/SagerNet/gvisor/pkg/gohacks" 27 "github.com/SagerNet/gvisor/pkg/hostarch" 28 "github.com/SagerNet/gvisor/pkg/safemem" 29 "github.com/SagerNet/gvisor/pkg/syserror" 30 ) 31 32 // IO provides access to the contents of a virtual memory space. 33 type IO interface { 34 // CopyOut copies len(src) bytes from src to the memory mapped at addr. It 35 // returns the number of bytes copied. If the number of bytes copied is < 36 // len(src), it returns a non-nil error explaining why. 37 // 38 // Preconditions: The caller must not hold mm.MemoryManager.mappingMu or 39 // any following locks in the lock order. 40 // 41 // Postconditions: CopyOut does not retain src. 42 CopyOut(ctx context.Context, addr hostarch.Addr, src []byte, opts IOOpts) (int, error) 43 44 // CopyIn copies len(dst) bytes from the memory mapped at addr to dst. 45 // It returns the number of bytes copied. If the number of bytes copied is 46 // < len(dst), it returns a non-nil error explaining why. 47 // 48 // Preconditions: The caller must not hold mm.MemoryManager.mappingMu or 49 // any following locks in the lock order. 50 // 51 // Postconditions: CopyIn does not retain dst. 52 CopyIn(ctx context.Context, addr hostarch.Addr, dst []byte, opts IOOpts) (int, error) 53 54 // ZeroOut sets toZero bytes to 0, starting at addr. It returns the number 55 // of bytes zeroed. If the number of bytes zeroed is < toZero, it returns a 56 // non-nil error explaining why. 57 // 58 // Preconditions: 59 // * The caller must not hold mm.MemoryManager.mappingMu or any 60 // following locks in the lock order. 61 // * toZero >= 0. 62 ZeroOut(ctx context.Context, addr hostarch.Addr, toZero int64, opts IOOpts) (int64, error) 63 64 // CopyOutFrom copies ars.NumBytes() bytes from src to the memory mapped at 65 // ars. It returns the number of bytes copied, which may be less than the 66 // number of bytes read from src if copying fails. CopyOutFrom may return a 67 // partial copy without an error iff src.ReadToBlocks returns a partial 68 // read without an error. 69 // 70 // CopyOutFrom calls src.ReadToBlocks at most once. 71 // 72 // Preconditions: 73 // * The caller must not hold mm.MemoryManager.mappingMu or any 74 // following locks in the lock order. 75 // * src.ReadToBlocks must not block on mm.MemoryManager.activeMu or 76 // any preceding locks in the lock order. 77 CopyOutFrom(ctx context.Context, ars hostarch.AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) 78 79 // CopyInTo copies ars.NumBytes() bytes from the memory mapped at ars to 80 // dst. It returns the number of bytes copied. CopyInTo may return a 81 // partial copy without an error iff dst.WriteFromBlocks returns a partial 82 // write without an error. 83 // 84 // CopyInTo calls dst.WriteFromBlocks at most once. 85 // 86 // Preconditions: 87 // * The caller must not hold mm.MemoryManager.mappingMu or any 88 // following locks in the lock order. 89 // * dst.WriteFromBlocks must not block on mm.MemoryManager.activeMu or 90 // any preceding locks in the lock order. 91 CopyInTo(ctx context.Context, ars hostarch.AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) 92 93 // TODO(jamieliu): The requirement that CopyOutFrom/CopyInTo call src/dst 94 // at most once, which is unnecessary in most cases, forces implementations 95 // to gather safemem.Blocks into a single slice to pass to src/dst. Add 96 // CopyOutFromIter/CopyInToIter, which relaxes this restriction, to avoid 97 // this allocation. 98 99 // SwapUint32 atomically sets the uint32 value at addr to new and 100 // returns the previous value. 101 // 102 // Preconditions: 103 // * The caller must not hold mm.MemoryManager.mappingMu or any 104 // following locks in the lock order. 105 // * addr must be aligned to a 4-byte boundary. 106 SwapUint32(ctx context.Context, addr hostarch.Addr, new uint32, opts IOOpts) (uint32, error) 107 108 // CompareAndSwapUint32 atomically compares the uint32 value at addr to 109 // old; if they are equal, the value in memory is replaced by new. In 110 // either case, the previous value stored in memory is returned. 111 // 112 // Preconditions: 113 // * The caller must not hold mm.MemoryManager.mappingMu or any 114 // following locks in the lock order. 115 // * addr must be aligned to a 4-byte boundary. 116 CompareAndSwapUint32(ctx context.Context, addr hostarch.Addr, old, new uint32, opts IOOpts) (uint32, error) 117 118 // LoadUint32 atomically loads the uint32 value at addr and returns it. 119 // 120 // Preconditions: 121 // * The caller must not hold mm.MemoryManager.mappingMu or any 122 // following locks in the lock order. 123 // * addr must be aligned to a 4-byte boundary. 124 LoadUint32(ctx context.Context, addr hostarch.Addr, opts IOOpts) (uint32, error) 125 } 126 127 // IOOpts contains options applicable to all IO methods. 128 type IOOpts struct { 129 // If IgnorePermissions is true, application-defined memory protections set 130 // by mmap(2) or mprotect(2) will be ignored. (Memory protections required 131 // by the target of the mapping are never ignored.) 132 IgnorePermissions bool 133 134 // If AddressSpaceActive is true, the IO implementation may assume that it 135 // has an active AddressSpace and can therefore use AddressSpace copying 136 // without performing activation. See mm/io.go for details. 137 AddressSpaceActive bool 138 } 139 140 // IOReadWriter is an io.ReadWriter that reads from / writes to addresses 141 // starting at addr in IO. The preconditions that apply to IO.CopyIn and 142 // IO.CopyOut also apply to IOReadWriter.Read and IOReadWriter.Write 143 // respectively. 144 type IOReadWriter struct { 145 Ctx context.Context 146 IO IO 147 Addr hostarch.Addr 148 Opts IOOpts 149 } 150 151 // Read implements io.Reader.Read. 152 // 153 // Note that an address space does not have an "end of file", so Read can only 154 // return io.EOF if IO.CopyIn returns io.EOF. Attempts to read unmapped or 155 // unreadable memory, or beyond the end of the address space, should return 156 // EFAULT. 157 func (rw *IOReadWriter) Read(dst []byte) (int, error) { 158 n, err := rw.IO.CopyIn(rw.Ctx, rw.Addr, dst, rw.Opts) 159 end, ok := rw.Addr.AddLength(uint64(n)) 160 if ok { 161 rw.Addr = end 162 } else { 163 // Disallow wraparound. 164 rw.Addr = ^hostarch.Addr(0) 165 if err != nil { 166 err = syserror.EFAULT 167 } 168 } 169 return n, err 170 } 171 172 // Write implements io.Writer.Write. 173 func (rw *IOReadWriter) Write(src []byte) (int, error) { 174 n, err := rw.IO.CopyOut(rw.Ctx, rw.Addr, src, rw.Opts) 175 end, ok := rw.Addr.AddLength(uint64(n)) 176 if ok { 177 rw.Addr = end 178 } else { 179 // Disallow wraparound. 180 rw.Addr = ^hostarch.Addr(0) 181 if err != nil { 182 err = syserror.EFAULT 183 } 184 } 185 return n, err 186 } 187 188 // CopyStringIn tuning parameters, defined outside that function for tests. 189 const ( 190 copyStringIncrement = 64 191 copyStringMaxInitBufLen = 256 192 ) 193 194 // CopyStringIn copies a NUL-terminated string of unknown length from the 195 // memory mapped at addr in uio and returns it as a string (not including the 196 // trailing NUL). If the length of the string, including the terminating NUL, 197 // would exceed maxlen, CopyStringIn returns the string truncated to maxlen and 198 // ENAMETOOLONG. 199 // 200 // Preconditions: Same as IO.CopyFromUser, plus: 201 // * maxlen >= 0. 202 func CopyStringIn(ctx context.Context, uio IO, addr hostarch.Addr, maxlen int, opts IOOpts) (string, error) { 203 initLen := maxlen 204 if initLen > copyStringMaxInitBufLen { 205 initLen = copyStringMaxInitBufLen 206 } 207 buf := make([]byte, initLen) 208 var done int 209 for done < maxlen { 210 // Read up to copyStringIncrement bytes at a time. 211 readlen := copyStringIncrement 212 if readlen > maxlen-done { 213 readlen = maxlen - done 214 } 215 end, ok := addr.AddLength(uint64(readlen)) 216 if !ok { 217 return gohacks.StringFromImmutableBytes(buf[:done]), syserror.EFAULT 218 } 219 // Shorten the read to avoid crossing page boundaries, since faulting 220 // in a page unnecessarily is expensive. This also ensures that partial 221 // copies up to the end of application-mappable memory succeed. 222 if addr.RoundDown() != end.RoundDown() { 223 end = end.RoundDown() 224 readlen = int(end - addr) 225 } 226 // Ensure that our buffer is large enough to accommodate the read. 227 if done+readlen > len(buf) { 228 newBufLen := len(buf) * 2 229 if newBufLen > maxlen { 230 newBufLen = maxlen 231 } 232 buf = append(buf, make([]byte, newBufLen-len(buf))...) 233 } 234 n, err := uio.CopyIn(ctx, addr, buf[done:done+readlen], opts) 235 // Look for the terminating zero byte, which may have occurred before 236 // hitting err. 237 if i := bytes.IndexByte(buf[done:done+n], byte(0)); i >= 0 { 238 return gohacks.StringFromImmutableBytes(buf[:done+i]), nil 239 } 240 241 done += n 242 if err != nil { 243 return gohacks.StringFromImmutableBytes(buf[:done]), err 244 } 245 addr = end 246 } 247 return gohacks.StringFromImmutableBytes(buf), linuxerr.ENAMETOOLONG 248 } 249 250 // CopyOutVec copies bytes from src to the memory mapped at ars in uio. The 251 // maximum number of bytes copied is ars.NumBytes() or len(src), whichever is 252 // less. CopyOutVec returns the number of bytes copied; if this is less than 253 // the maximum, it returns a non-nil error explaining why. 254 // 255 // Preconditions: Same as IO.CopyOut. 256 func CopyOutVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, src []byte, opts IOOpts) (int, error) { 257 var done int 258 for !ars.IsEmpty() && done < len(src) { 259 ar := ars.Head() 260 cplen := len(src) - done 261 if hostarch.Addr(cplen) >= ar.Length() { 262 cplen = int(ar.Length()) 263 } 264 n, err := uio.CopyOut(ctx, ar.Start, src[done:done+cplen], opts) 265 done += n 266 if err != nil { 267 return done, err 268 } 269 ars = ars.DropFirst(n) 270 } 271 return done, nil 272 } 273 274 // CopyInVec copies bytes from the memory mapped at ars in uio to dst. The 275 // maximum number of bytes copied is ars.NumBytes() or len(dst), whichever is 276 // less. CopyInVec returns the number of bytes copied; if this is less than the 277 // maximum, it returns a non-nil error explaining why. 278 // 279 // Preconditions: Same as IO.CopyIn. 280 func CopyInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dst []byte, opts IOOpts) (int, error) { 281 var done int 282 for !ars.IsEmpty() && done < len(dst) { 283 ar := ars.Head() 284 cplen := len(dst) - done 285 if hostarch.Addr(cplen) >= ar.Length() { 286 cplen = int(ar.Length()) 287 } 288 n, err := uio.CopyIn(ctx, ar.Start, dst[done:done+cplen], opts) 289 done += n 290 if err != nil { 291 return done, err 292 } 293 ars = ars.DropFirst(n) 294 } 295 return done, nil 296 } 297 298 // ZeroOutVec writes zeroes to the memory mapped at ars in uio. The maximum 299 // number of bytes written is ars.NumBytes() or toZero, whichever is less. 300 // ZeroOutVec returns the number of bytes written; if this is less than the 301 // maximum, it returns a non-nil error explaining why. 302 // 303 // Preconditions: Same as IO.ZeroOut. 304 func ZeroOutVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, toZero int64, opts IOOpts) (int64, error) { 305 var done int64 306 for !ars.IsEmpty() && done < toZero { 307 ar := ars.Head() 308 cplen := toZero - done 309 if hostarch.Addr(cplen) >= ar.Length() { 310 cplen = int64(ar.Length()) 311 } 312 n, err := uio.ZeroOut(ctx, ar.Start, cplen, opts) 313 done += n 314 if err != nil { 315 return done, err 316 } 317 ars = ars.DropFirst64(n) 318 } 319 return done, nil 320 } 321 322 func isASCIIWhitespace(b byte) bool { 323 // Compare Linux include/linux/ctype.h, lib/ctype.c. 324 // 9 => horizontal tab '\t' 325 // 10 => line feed '\n' 326 // 11 => vertical tab '\v' 327 // 12 => form feed '\c' 328 // 13 => carriage return '\r' 329 return b == ' ' || (b >= 9 && b <= 13) 330 } 331 332 // CopyInt32StringsInVec copies up to len(dsts) whitespace-separated decimal 333 // strings from the memory mapped at ars in uio and converts them to int32 334 // values in dsts. It returns the number of bytes read. 335 // 336 // CopyInt32StringsInVec shares the following properties with Linux's 337 // kernel/sysctl.c:proc_dointvec(write=1): 338 // 339 // - If any read value overflows the range of int32, or any invalid characters 340 // are encountered during the read, CopyInt32StringsInVec returns EINVAL. 341 // 342 // - If, upon reaching the end of ars, fewer than len(dsts) values have been 343 // read, CopyInt32StringsInVec returns no error if at least 1 value was read 344 // and EINVAL otherwise. 345 // 346 // - Trailing whitespace after the last successfully read value is counted in 347 // the number of bytes read. 348 // 349 // Unlike proc_dointvec(): 350 // 351 // - CopyInt32StringsInVec does not implicitly limit ars.NumBytes() to 352 // PageSize-1; callers that require this must do so explicitly. 353 // 354 // - CopyInt32StringsInVec returns EINVAL if ars.NumBytes() == 0. 355 // 356 // Preconditions: Same as CopyInVec. 357 func CopyInt32StringsInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dsts []int32, opts IOOpts) (int64, error) { 358 if len(dsts) == 0 { 359 return 0, nil 360 } 361 362 buf := make([]byte, ars.NumBytes()) 363 n, cperr := CopyInVec(ctx, uio, ars, buf, opts) 364 buf = buf[:n] 365 366 var i, j int 367 for ; j < len(dsts); j++ { 368 // Skip leading whitespace. 369 for i < len(buf) && isASCIIWhitespace(buf[i]) { 370 i++ 371 } 372 if i == len(buf) { 373 break 374 } 375 376 // Find the end of the value to be parsed (next whitespace or end of string). 377 nextI := i + 1 378 for nextI < len(buf) && !isASCIIWhitespace(buf[nextI]) { 379 nextI++ 380 } 381 382 // Parse a single value. 383 val, err := strconv.ParseInt(string(buf[i:nextI]), 10, 32) 384 if err != nil { 385 return int64(i), linuxerr.EINVAL 386 } 387 dsts[j] = int32(val) 388 389 i = nextI 390 } 391 392 // Skip trailing whitespace. 393 for i < len(buf) && isASCIIWhitespace(buf[i]) { 394 i++ 395 } 396 397 if cperr != nil { 398 return int64(i), cperr 399 } 400 if j == 0 { 401 return int64(i), linuxerr.EINVAL 402 } 403 return int64(i), nil 404 } 405 406 // CopyInt32StringInVec is equivalent to CopyInt32StringsInVec, but copies at 407 // most one int32. 408 func CopyInt32StringInVec(ctx context.Context, uio IO, ars hostarch.AddrRangeSeq, dst *int32, opts IOOpts) (int64, error) { 409 dsts := [1]int32{*dst} 410 n, err := CopyInt32StringsInVec(ctx, uio, ars, dsts[:], opts) 411 *dst = dsts[0] 412 return n, err 413 } 414 415 // IOSequence holds arguments to IO methods. 416 type IOSequence struct { 417 IO IO 418 Addrs hostarch.AddrRangeSeq 419 Opts IOOpts 420 } 421 422 // NumBytes returns s.Addrs.NumBytes(). 423 // 424 // Note that NumBytes() may return 0 even if !s.Addrs.IsEmpty(), since 425 // s.Addrs may contain a non-zero number of zero-length AddrRanges. 426 // Many clients of 427 // IOSequence currently do something like: 428 // 429 // if ioseq.NumBytes() == 0 { 430 // return 0, nil 431 // } 432 // if f.availableBytes == 0 { 433 // return 0, syserror.ErrWouldBlock 434 // } 435 // return ioseq.CopyOutFrom(..., reader) 436 // 437 // In such cases, using s.Addrs.IsEmpty() will cause them to have the wrong 438 // behavior for zero-length I/O. However, using s.NumBytes() == 0 instead means 439 // that we will return success for zero-length I/O in cases where Linux would 440 // return EFAULT due to a failed access_ok() check, so in the long term we 441 // should move checks for ErrWouldBlock etc. into the body of 442 // reader.ReadToBlocks and use s.Addrs.IsEmpty() instead. 443 func (s IOSequence) NumBytes() int64 { 444 return s.Addrs.NumBytes() 445 } 446 447 // DropFirst returns a copy of s with s.Addrs.DropFirst(n). 448 // 449 // Preconditions: Same as hostarch.AddrRangeSeq.DropFirst. 450 func (s IOSequence) DropFirst(n int) IOSequence { 451 return IOSequence{s.IO, s.Addrs.DropFirst(n), s.Opts} 452 } 453 454 // DropFirst64 returns a copy of s with s.Addrs.DropFirst64(n). 455 // 456 // Preconditions: Same as hostarch.AddrRangeSeq.DropFirst64. 457 func (s IOSequence) DropFirst64(n int64) IOSequence { 458 return IOSequence{s.IO, s.Addrs.DropFirst64(n), s.Opts} 459 } 460 461 // TakeFirst returns a copy of s with s.Addrs.TakeFirst(n). 462 // 463 // Preconditions: Same as hostarch.AddrRangeSeq.TakeFirst. 464 func (s IOSequence) TakeFirst(n int) IOSequence { 465 return IOSequence{s.IO, s.Addrs.TakeFirst(n), s.Opts} 466 } 467 468 // TakeFirst64 returns a copy of s with s.Addrs.TakeFirst64(n). 469 // 470 // Preconditions: Same as hostarch.AddrRangeSeq.TakeFirst64. 471 func (s IOSequence) TakeFirst64(n int64) IOSequence { 472 return IOSequence{s.IO, s.Addrs.TakeFirst64(n), s.Opts} 473 } 474 475 // CopyOut invokes CopyOutVec over s.Addrs. 476 // 477 // As with CopyOutVec, if s.NumBytes() < len(src), the copy will be truncated 478 // to s.NumBytes(), and a nil error will be returned. 479 // 480 // Preconditions: Same as CopyOutVec. 481 func (s IOSequence) CopyOut(ctx context.Context, src []byte) (int, error) { 482 return CopyOutVec(ctx, s.IO, s.Addrs, src, s.Opts) 483 } 484 485 // CopyIn invokes CopyInVec over s.Addrs. 486 // 487 // As with CopyInVec, if s.NumBytes() < len(dst), the copy will be truncated to 488 // s.NumBytes(), and a nil error will be returned. 489 // 490 // Preconditions: Same as CopyInVec. 491 func (s IOSequence) CopyIn(ctx context.Context, dst []byte) (int, error) { 492 return CopyInVec(ctx, s.IO, s.Addrs, dst, s.Opts) 493 } 494 495 // ZeroOut invokes ZeroOutVec over s.Addrs. 496 // 497 // As with ZeroOutVec, if s.NumBytes() < toZero, the write will be truncated 498 // to s.NumBytes(), and a nil error will be returned. 499 // 500 // Preconditions: Same as ZeroOutVec. 501 func (s IOSequence) ZeroOut(ctx context.Context, toZero int64) (int64, error) { 502 return ZeroOutVec(ctx, s.IO, s.Addrs, toZero, s.Opts) 503 } 504 505 // CopyOutFrom invokes s.CopyOutFrom over s.Addrs. 506 // 507 // Preconditions: Same as IO.CopyOutFrom. 508 func (s IOSequence) CopyOutFrom(ctx context.Context, src safemem.Reader) (int64, error) { 509 return s.IO.CopyOutFrom(ctx, s.Addrs, src, s.Opts) 510 } 511 512 // CopyInTo invokes s.CopyInTo over s.Addrs. 513 // 514 // Preconditions: Same as IO.CopyInTo. 515 func (s IOSequence) CopyInTo(ctx context.Context, dst safemem.Writer) (int64, error) { 516 return s.IO.CopyInTo(ctx, s.Addrs, dst, s.Opts) 517 } 518 519 // Reader returns an io.Reader that reads from s. Reads beyond the end of s 520 // return io.EOF. The preconditions that apply to s.CopyIn also apply to the 521 // returned io.Reader.Read. 522 func (s IOSequence) Reader(ctx context.Context) *IOSequenceReadWriter { 523 return &IOSequenceReadWriter{ctx, s} 524 } 525 526 // Writer returns an io.Writer that writes to s. Writes beyond the end of s 527 // return ErrEndOfIOSequence. The preconditions that apply to s.CopyOut also 528 // apply to the returned io.Writer.Write. 529 func (s IOSequence) Writer(ctx context.Context) *IOSequenceReadWriter { 530 return &IOSequenceReadWriter{ctx, s} 531 } 532 533 // ErrEndOfIOSequence is returned by IOSequence.Writer().Write() when 534 // attempting to write beyond the end of the IOSequence. 535 var ErrEndOfIOSequence = errors.New("write beyond end of IOSequence") 536 537 // IOSequenceReadWriter implements io.Reader and io.Writer for an IOSequence. 538 type IOSequenceReadWriter struct { 539 ctx context.Context 540 s IOSequence 541 } 542 543 // Read implements io.Reader.Read. 544 func (rw *IOSequenceReadWriter) Read(dst []byte) (int, error) { 545 n, err := rw.s.CopyIn(rw.ctx, dst) 546 rw.s = rw.s.DropFirst(n) 547 if err == nil && rw.s.NumBytes() == 0 { 548 err = io.EOF 549 } 550 return n, err 551 } 552 553 // Len implements tcpip.Payloader. 554 func (rw *IOSequenceReadWriter) Len() int { 555 return int(rw.s.NumBytes()) 556 } 557 558 // Write implements io.Writer.Write. 559 func (rw *IOSequenceReadWriter) Write(src []byte) (int, error) { 560 n, err := rw.s.CopyOut(rw.ctx, src) 561 rw.s = rw.s.DropFirst(n) 562 if err == nil && n < len(src) { 563 err = ErrEndOfIOSequence 564 } 565 return n, err 566 }