github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/loader/loader.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 loader loads an executable file into a MemoryManager.
    16  package loader
    17  
    18  import (
    19  	"bytes"
    20  	"fmt"
    21  	"io"
    22  	"path"
    23  
    24  	"github.com/SagerNet/gvisor/pkg/abi"
    25  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    26  	"github.com/SagerNet/gvisor/pkg/abi/linux/errno"
    27  	"github.com/SagerNet/gvisor/pkg/context"
    28  	"github.com/SagerNet/gvisor/pkg/cpuid"
    29  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    30  	"github.com/SagerNet/gvisor/pkg/hostarch"
    31  	"github.com/SagerNet/gvisor/pkg/rand"
    32  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    33  	"github.com/SagerNet/gvisor/pkg/sentry/fsbridge"
    34  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    35  	"github.com/SagerNet/gvisor/pkg/sentry/mm"
    36  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    37  	"github.com/SagerNet/gvisor/pkg/syserr"
    38  	"github.com/SagerNet/gvisor/pkg/syserror"
    39  	"github.com/SagerNet/gvisor/pkg/usermem"
    40  )
    41  
    42  // LoadArgs holds specifications for an executable file to be loaded.
    43  type LoadArgs struct {
    44  	// MemoryManager is the memory manager to load the executable into.
    45  	MemoryManager *mm.MemoryManager
    46  
    47  	// RemainingTraversals is the maximum number of symlinks to follow to
    48  	// resolve Filename. This counter is passed by reference to keep it
    49  	// updated throughout the call stack.
    50  	RemainingTraversals *uint
    51  
    52  	// ResolveFinal indicates whether the final link of Filename should be
    53  	// resolved, if it is a symlink.
    54  	ResolveFinal bool
    55  
    56  	// Filename is the path for the executable.
    57  	Filename string
    58  
    59  	// File is an open fs.File object of the executable. If File is not
    60  	// nil, then File will be loaded and Filename will be ignored.
    61  	//
    62  	// The caller is responsible for checking that the user can execute this file.
    63  	File fsbridge.File
    64  
    65  	// Opener is used to open the executable file when 'File' is nil.
    66  	Opener fsbridge.Lookup
    67  
    68  	// CloseOnExec indicates that the executable (or one of its parent
    69  	// directories) was opened with O_CLOEXEC. If the executable is an
    70  	// interpreter script, then cause an ENOENT error to occur, since the
    71  	// script would otherwise be inaccessible to the interpreter.
    72  	CloseOnExec bool
    73  
    74  	// Argv is the vector of arguments to pass to the executable.
    75  	Argv []string
    76  
    77  	// Envv is the vector of environment variables to pass to the
    78  	// executable.
    79  	Envv []string
    80  
    81  	// Features specifies the CPU feature set for the executable.
    82  	Features *cpuid.FeatureSet
    83  }
    84  
    85  // openPath opens args.Filename and checks that it is valid for loading.
    86  //
    87  // openPath returns an *fs.Dirent and *fs.File for args.Filename, which is not
    88  // installed in the Task FDTable. The caller takes ownership of both.
    89  //
    90  // args.Filename must be a readable, executable, regular file.
    91  func openPath(ctx context.Context, args LoadArgs) (fsbridge.File, error) {
    92  	if args.Filename == "" {
    93  		ctx.Infof("cannot open empty name")
    94  		return nil, syserror.ENOENT
    95  	}
    96  
    97  	// TODO(github.com/SagerNet/issue/160): Linux requires only execute permission,
    98  	// not read. However, our backing filesystems may prevent us from reading
    99  	// the file without read permission. Additionally, a task with a
   100  	// non-readable executable has additional constraints on access via
   101  	// ptrace and procfs.
   102  	opts := vfs.OpenOptions{
   103  		Flags:    linux.O_RDONLY,
   104  		FileExec: true,
   105  	}
   106  	return args.Opener.OpenPath(ctx, args.Filename, opts, args.RemainingTraversals, args.ResolveFinal)
   107  }
   108  
   109  // checkIsRegularFile prevents us from trying to execute a directory, pipe, etc.
   110  func checkIsRegularFile(ctx context.Context, file fsbridge.File, filename string) error {
   111  	t, err := file.Type(ctx)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	if t != linux.ModeRegular {
   116  		ctx.Infof("%q is not a regular file: %v", filename, t)
   117  		return linuxerr.EACCES
   118  	}
   119  	return nil
   120  }
   121  
   122  // allocStack allocates and maps a stack in to any available part of the address space.
   123  func allocStack(ctx context.Context, m *mm.MemoryManager, a arch.Context) (*arch.Stack, error) {
   124  	ar, err := m.MapStack(ctx)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return &arch.Stack{Arch: a, IO: m, Bottom: ar.End}, nil
   129  }
   130  
   131  const (
   132  	// maxLoaderAttempts is the maximum number of attempts to try to load
   133  	// an interpreter scripts, to prevent loops. 6 (initial + 5 changes) is
   134  	// what the Linux kernel allows (fs/exec.c:search_binary_handler).
   135  	maxLoaderAttempts = 6
   136  )
   137  
   138  // loadExecutable loads an executable that is pointed to by args.File. The
   139  // caller is responsible for checking that the user can execute this file.
   140  // If nil, the path args.Filename is resolved and loaded (check that the user
   141  // can execute this file is done here in this case). If the executable is an
   142  // interpreter script rather than an ELF, the binary of the corresponding
   143  // interpreter will be loaded.
   144  //
   145  // It returns:
   146  //  * loadedELF, description of the loaded binary
   147  //  * arch.Context matching the binary arch
   148  //  * fs.Dirent of the binary file
   149  //  * Possibly updated args.Argv
   150  func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, arch.Context, fsbridge.File, []string, error) {
   151  	for i := 0; i < maxLoaderAttempts; i++ {
   152  		if args.File == nil {
   153  			var err error
   154  			args.File, err = openPath(ctx, args)
   155  			if err != nil {
   156  				ctx.Infof("Error opening %s: %v", args.Filename, err)
   157  				return loadedELF{}, nil, nil, nil, err
   158  			}
   159  			// Ensure file is release in case the code loops or errors out.
   160  			defer args.File.DecRef(ctx)
   161  		} else {
   162  			if err := checkIsRegularFile(ctx, args.File, args.Filename); err != nil {
   163  				return loadedELF{}, nil, nil, nil, err
   164  			}
   165  		}
   166  
   167  		// Check the header. Is this an ELF or interpreter script?
   168  		var hdr [4]uint8
   169  		// N.B. We assume that reading from a regular file cannot block.
   170  		_, err := args.File.ReadFull(ctx, usermem.BytesIOSequence(hdr[:]), 0)
   171  		// Allow unexpected EOF, as a valid executable could be only three bytes
   172  		// (e.g., #!a).
   173  		if err != nil && err != io.ErrUnexpectedEOF {
   174  			if err == io.EOF {
   175  				err = syserror.ENOEXEC
   176  			}
   177  			return loadedELF{}, nil, nil, nil, err
   178  		}
   179  
   180  		switch {
   181  		case bytes.Equal(hdr[:], []byte(elfMagic)):
   182  			loaded, ac, err := loadELF(ctx, args)
   183  			if err != nil {
   184  				ctx.Infof("Error loading ELF: %v", err)
   185  				return loadedELF{}, nil, nil, nil, err
   186  			}
   187  			// An ELF is always terminal. Hold on to file.
   188  			args.File.IncRef()
   189  			return loaded, ac, args.File, args.Argv, err
   190  
   191  		case bytes.Equal(hdr[:2], []byte(interpreterScriptMagic)):
   192  			if args.CloseOnExec {
   193  				return loadedELF{}, nil, nil, nil, syserror.ENOENT
   194  			}
   195  			args.Filename, args.Argv, err = parseInterpreterScript(ctx, args.Filename, args.File, args.Argv)
   196  			if err != nil {
   197  				ctx.Infof("Error loading interpreter script: %v", err)
   198  				return loadedELF{}, nil, nil, nil, err
   199  			}
   200  			// Refresh the traversal limit for the interpreter.
   201  			*args.RemainingTraversals = linux.MaxSymlinkTraversals
   202  
   203  		default:
   204  			ctx.Infof("Unknown magic: %v", hdr)
   205  			return loadedELF{}, nil, nil, nil, syserror.ENOEXEC
   206  		}
   207  		// Set to nil in case we loop on a Interpreter Script.
   208  		args.File = nil
   209  	}
   210  
   211  	return loadedELF{}, nil, nil, nil, linuxerr.ELOOP
   212  }
   213  
   214  // Load loads args.File into a MemoryManager. If args.File is nil, the path
   215  // args.Filename is resolved and loaded instead.
   216  //
   217  // If Load returns ErrSwitchFile it should be called again with the returned
   218  // path and argv.
   219  //
   220  // Preconditions:
   221  // * The Task MemoryManager is empty.
   222  // * Load is called on the Task goroutine.
   223  func Load(ctx context.Context, args LoadArgs, extraAuxv []arch.AuxEntry, vdso *VDSO) (abi.OS, arch.Context, string, *syserr.Error) {
   224  	// Load the executable itself.
   225  	loaded, ac, file, newArgv, err := loadExecutable(ctx, args)
   226  	if err != nil {
   227  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("failed to load %s: %v", args.Filename, err), syserr.FromError(err).ToLinux())
   228  	}
   229  	defer file.DecRef(ctx)
   230  
   231  	// Load the VDSO.
   232  	vdsoAddr, err := loadVDSO(ctx, args.MemoryManager, vdso, loaded)
   233  	if err != nil {
   234  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("error loading VDSO: %v", err), syserr.FromError(err).ToLinux())
   235  	}
   236  
   237  	// Setup the heap. brk starts at the next page after the end of the
   238  	// executable. Userspace can assume that the remainer of the page after
   239  	// loaded.end is available for its use.
   240  	e, ok := loaded.end.RoundUp()
   241  	if !ok {
   242  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("brk overflows: %#x", loaded.end), errno.ENOEXEC)
   243  	}
   244  	args.MemoryManager.BrkSetup(ctx, e)
   245  
   246  	// Allocate our stack.
   247  	stack, err := allocStack(ctx, args.MemoryManager, ac)
   248  	if err != nil {
   249  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to allocate stack: %v", err), syserr.FromError(err).ToLinux())
   250  	}
   251  
   252  	// Push the original filename to the stack, for AT_EXECFN.
   253  	if _, err := stack.PushNullTerminatedByteSlice([]byte(args.Filename)); err != nil {
   254  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to push exec filename: %v", err), syserr.FromError(err).ToLinux())
   255  	}
   256  	execfn := stack.Bottom
   257  
   258  	// Push 16 random bytes on the stack which AT_RANDOM will point to.
   259  	var b [16]byte
   260  	if _, err := rand.Read(b[:]); err != nil {
   261  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to read random bytes: %v", err), syserr.FromError(err).ToLinux())
   262  	}
   263  	if _, err = stack.PushNullTerminatedByteSlice(b[:]); err != nil {
   264  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to push random bytes: %v", err), syserr.FromError(err).ToLinux())
   265  	}
   266  	random := stack.Bottom
   267  
   268  	c := auth.CredentialsFromContext(ctx)
   269  
   270  	// Add generic auxv entries.
   271  	auxv := append(loaded.auxv, arch.Auxv{
   272  		arch.AuxEntry{linux.AT_UID, hostarch.Addr(c.RealKUID.In(c.UserNamespace).OrOverflow())},
   273  		arch.AuxEntry{linux.AT_EUID, hostarch.Addr(c.EffectiveKUID.In(c.UserNamespace).OrOverflow())},
   274  		arch.AuxEntry{linux.AT_GID, hostarch.Addr(c.RealKGID.In(c.UserNamespace).OrOverflow())},
   275  		arch.AuxEntry{linux.AT_EGID, hostarch.Addr(c.EffectiveKGID.In(c.UserNamespace).OrOverflow())},
   276  		// The conditions that require AT_SECURE = 1 never arise. See
   277  		// kernel.Task.updateCredsForExecLocked.
   278  		arch.AuxEntry{linux.AT_SECURE, 0},
   279  		arch.AuxEntry{linux.AT_CLKTCK, linux.CLOCKS_PER_SEC},
   280  		arch.AuxEntry{linux.AT_EXECFN, execfn},
   281  		arch.AuxEntry{linux.AT_RANDOM, random},
   282  		arch.AuxEntry{linux.AT_PAGESZ, hostarch.PageSize},
   283  		arch.AuxEntry{linux.AT_SYSINFO_EHDR, vdsoAddr},
   284  	}...)
   285  	auxv = append(auxv, extraAuxv...)
   286  
   287  	sl, err := stack.Load(newArgv, args.Envv, auxv)
   288  	if err != nil {
   289  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to load stack: %v", err), syserr.FromError(err).ToLinux())
   290  	}
   291  
   292  	m := args.MemoryManager
   293  	m.SetArgvStart(sl.ArgvStart)
   294  	m.SetArgvEnd(sl.ArgvEnd)
   295  	m.SetEnvvStart(sl.EnvvStart)
   296  	m.SetEnvvEnd(sl.EnvvEnd)
   297  	m.SetAuxv(auxv)
   298  	m.SetExecutable(ctx, file)
   299  
   300  	symbolValue, err := getSymbolValueFromVDSO("rt_sigreturn")
   301  	if err != nil {
   302  		return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to find rt_sigreturn in vdso: %v", err), syserr.FromError(err).ToLinux())
   303  	}
   304  
   305  	// Found rt_sigretrun.
   306  	addr := uint64(vdsoAddr) + symbolValue - vdsoPrelink
   307  	m.SetVDSOSigReturn(addr)
   308  
   309  	ac.SetIP(uintptr(loaded.entry))
   310  	ac.SetStack(uintptr(stack.Bottom))
   311  
   312  	name := path.Base(args.Filename)
   313  	if len(name) > linux.TASK_COMM_LEN-1 {
   314  		name = name[:linux.TASK_COMM_LEN-1]
   315  	}
   316  
   317  	return loaded.os, ac, name, nil
   318  }