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 }