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  }