github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/vfs2/execve.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 vfs2
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    20  	"github.com/SagerNet/gvisor/pkg/fspath"
    21  	"github.com/SagerNet/gvisor/pkg/hostarch"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/fsbridge"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/loader"
    26  	slinux "github.com/SagerNet/gvisor/pkg/sentry/syscalls/linux"
    27  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    28  	"github.com/SagerNet/gvisor/pkg/syserror"
    29  )
    30  
    31  // Execve implements linux syscall execve(2).
    32  func Execve(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    33  	pathnameAddr := args[0].Pointer()
    34  	argvAddr := args[1].Pointer()
    35  	envvAddr := args[2].Pointer()
    36  	return execveat(t, linux.AT_FDCWD, pathnameAddr, argvAddr, envvAddr, 0 /* flags */)
    37  }
    38  
    39  // Execveat implements linux syscall execveat(2).
    40  func Execveat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    41  	dirfd := args[0].Int()
    42  	pathnameAddr := args[1].Pointer()
    43  	argvAddr := args[2].Pointer()
    44  	envvAddr := args[3].Pointer()
    45  	flags := args[4].Int()
    46  	return execveat(t, dirfd, pathnameAddr, argvAddr, envvAddr, flags)
    47  }
    48  
    49  func execveat(t *kernel.Task, dirfd int32, pathnameAddr, argvAddr, envvAddr hostarch.Addr, flags int32) (uintptr, *kernel.SyscallControl, error) {
    50  	if flags&^(linux.AT_EMPTY_PATH|linux.AT_SYMLINK_NOFOLLOW) != 0 {
    51  		return 0, nil, linuxerr.EINVAL
    52  	}
    53  
    54  	pathname, err := t.CopyInString(pathnameAddr, linux.PATH_MAX)
    55  	if err != nil {
    56  		return 0, nil, err
    57  	}
    58  	var argv, envv []string
    59  	if argvAddr != 0 {
    60  		var err error
    61  		argv, err = t.CopyInVector(argvAddr, slinux.ExecMaxElemSize, slinux.ExecMaxTotalSize)
    62  		if err != nil {
    63  			return 0, nil, err
    64  		}
    65  	}
    66  	if envvAddr != 0 {
    67  		var err error
    68  		envv, err = t.CopyInVector(envvAddr, slinux.ExecMaxElemSize, slinux.ExecMaxTotalSize)
    69  		if err != nil {
    70  			return 0, nil, err
    71  		}
    72  	}
    73  
    74  	root := t.FSContext().RootDirectoryVFS2()
    75  	defer root.DecRef(t)
    76  	var executable fsbridge.File
    77  	closeOnExec := false
    78  	if path := fspath.Parse(pathname); dirfd != linux.AT_FDCWD && !path.Absolute {
    79  		// We must open the executable ourselves since dirfd is used as the
    80  		// starting point while resolving path, but the task working directory
    81  		// is used as the starting point while resolving interpreters (Linux:
    82  		// fs/binfmt_script.c:load_script() => fs/exec.c:open_exec() =>
    83  		// do_open_execat(fd=AT_FDCWD)), and the loader package is currently
    84  		// incapable of handling this correctly.
    85  		if !path.HasComponents() && flags&linux.AT_EMPTY_PATH == 0 {
    86  			return 0, nil, syserror.ENOENT
    87  		}
    88  		dirfile, dirfileFlags := t.FDTable().GetVFS2(dirfd)
    89  		if dirfile == nil {
    90  			return 0, nil, linuxerr.EBADF
    91  		}
    92  		start := dirfile.VirtualDentry()
    93  		start.IncRef()
    94  		dirfile.DecRef(t)
    95  		closeOnExec = dirfileFlags.CloseOnExec
    96  		file, err := t.Kernel().VFS().OpenAt(t, t.Credentials(), &vfs.PathOperation{
    97  			Root:               root,
    98  			Start:              start,
    99  			Path:               path,
   100  			FollowFinalSymlink: flags&linux.AT_SYMLINK_NOFOLLOW == 0,
   101  		}, &vfs.OpenOptions{
   102  			Flags:    linux.O_RDONLY,
   103  			FileExec: true,
   104  		})
   105  		start.DecRef(t)
   106  		if err != nil {
   107  			return 0, nil, err
   108  		}
   109  		defer file.DecRef(t)
   110  		executable = fsbridge.NewVFSFile(file)
   111  	}
   112  
   113  	// Load the new TaskImage.
   114  	mntns := t.MountNamespaceVFS2()
   115  	wd := t.FSContext().WorkingDirectoryVFS2()
   116  	defer wd.DecRef(t)
   117  	remainingTraversals := uint(linux.MaxSymlinkTraversals)
   118  	loadArgs := loader.LoadArgs{
   119  		Opener:              fsbridge.NewVFSLookup(mntns, root, wd),
   120  		RemainingTraversals: &remainingTraversals,
   121  		ResolveFinal:        flags&linux.AT_SYMLINK_NOFOLLOW == 0,
   122  		Filename:            pathname,
   123  		File:                executable,
   124  		CloseOnExec:         closeOnExec,
   125  		Argv:                argv,
   126  		Envv:                envv,
   127  		Features:            t.Arch().FeatureSet(),
   128  	}
   129  
   130  	image, se := t.Kernel().LoadTaskImage(t, loadArgs)
   131  	if se != nil {
   132  		return 0, nil, se.ToError()
   133  	}
   134  
   135  	ctrl, err := t.Execve(image)
   136  	return 0, ctrl, err
   137  }