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  }