summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/controller.go10
-rw-r--r--runsc/boot/filter/config.go5
-rw-r--r--runsc/boot/fs.go65
-rw-r--r--runsc/boot/loader.go31
4 files changed, 69 insertions, 42 deletions
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index fdb6be5b1..ec1110059 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -228,6 +228,16 @@ func (cm *containerManager) Start(args *StartArgs, _ *struct{}) error {
// Execute runs a command on a created or running sandbox.
func (cm *containerManager) Execute(e *control.ExecArgs, waitStatus *uint32) error {
log.Debugf("containerManager.Execute: %+v", *e)
+
+ if e.Filename == "" {
+ rootCtx := cm.l.rootProcArgs.NewContext(cm.l.k)
+ rootMns := cm.l.k.RootMountNamespace()
+ var err error
+ if e.Filename, err = getExecutablePath(rootCtx, rootMns, e.Argv[0], e.Envv); err != nil {
+ return fmt.Errorf("error getting executable path for %q: %v", e.Argv[0], err)
+ }
+ }
+
proc := control.Proc{Kernel: cm.l.k}
if err := proc.Exec(e, waitStatus); err != nil {
return fmt.Errorf("error executing: %+v: %v", e, err)
diff --git a/runsc/boot/filter/config.go b/runsc/boot/filter/config.go
index 113023bdd..f864b1f45 100644
--- a/runsc/boot/filter/config.go
+++ b/runsc/boot/filter/config.go
@@ -164,10 +164,7 @@ var allowedSyscalls = seccomp.SyscallRules{
seccomp.AllowAny{}, /* winsize struct */
},
},
- syscall.SYS_LSEEK: {},
- // TODO: Remove SYS_LSTAT when executable lookup moves
- // into the gofer.
- syscall.SYS_LSTAT: {},
+ syscall.SYS_LSEEK: {},
syscall.SYS_MADVISE: {},
syscall.SYS_MINCORE: {},
syscall.SYS_MMAP: []seccomp.Rule{
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go
index 20d0e42ef..4a11b30f1 100644
--- a/runsc/boot/fs.go
+++ b/runsc/boot/fs.go
@@ -701,13 +701,13 @@ func setFileSystemForProcess(procArgs *kernel.CreateProcessArgs, spec *specs.Spe
return nil
}
-// GetExecutablePathInternal traverses the *container's* filesystem to resolve
-// exec's absolute path. For example, if the container is being served files by
-// the fsgofer serving /foo/bar as the container root, it will search within
+// getExecutablePath traverses the *container's* filesystem to resolve exec's
+// absolute path. For example, if the container is being served files by the
+// fsgofer serving /foo/bar as the container root, it will search within
// /foo/bar, not the host root.
// TODO: Unit test this.
-func GetExecutablePathInternal(ctx context.Context, procArgs *kernel.CreateProcessArgs) (string, error) {
- exec := filepath.Clean(procArgs.Filename)
+func getExecutablePath(ctx context.Context, mns *fs.MountNamespace, filename string, env []string) (string, error) {
+ exec := filepath.Clean(filename)
// Don't search PATH if exec is a path to a file (absolute or relative).
if strings.IndexByte(exec, '/') >= 0 {
@@ -716,31 +716,52 @@ func GetExecutablePathInternal(ctx context.Context, procArgs *kernel.CreateProce
// Search the PATH for a file whose name matches the one we are looking
// for.
- pathDirs := specutils.GetPath(procArgs.Envv)
+ pathDirs := specutils.GetPath(env)
for _, p := range pathDirs {
- // Walk to the end of the path.
- curDir := procArgs.Root
- for _, pc := range strings.Split(p, "/") {
- var err error
- if curDir, err = curDir.Walk(ctx, curDir, pc); err != nil {
- break
- }
- }
- if curDir == nil {
+ // Try to find the binary inside path p.
+ binPath := path.Join(p, filename)
+ root := fs.RootFromContext(ctx)
+ defer root.DecRef()
+ d, err := mns.FindInode(ctx, root, nil, binPath, linux.MaxSymlinkTraversals)
+ if err == syserror.ENOENT || err == syserror.EACCES {
continue
}
- // Check for the executable in the path directory.
- dirent, err := curDir.Walk(ctx, curDir, exec)
if err != nil {
- continue
+ return "", fmt.Errorf("FindInode(%q) failed: %v", binPath, err)
}
- // Check whether we can read and execute the file in question.
- if err := dirent.Inode.CheckPermission(ctx, fs.PermMask{Read: true, Execute: true}); err != nil {
- log.Infof("Found executable at %q, but user cannot execute it: %v", path.Join(p, exec), err)
+ defer d.DecRef()
+
+ // Check whether we can read and execute the found file.
+ if err := d.Inode.CheckPermission(ctx, fs.PermMask{Read: true, Execute: true}); err != nil {
+ log.Infof("Found executable at %q, but user cannot execute it: %v", binPath, err)
continue
}
return path.Join("/", p, exec), nil
}
- return "", fmt.Errorf("could not find executable %s in path %v", exec, pathDirs)
+ return "", fmt.Errorf("could not find executable %q in path %v", exec, pathDirs)
+}
+
+// setExecutablePath sets the procArgs.Filename by searching the PATH for an
+// executable matching the procArgs.Argv[0].
+func setExecutablePath(ctx context.Context, mns *fs.MountNamespace, procArgs *kernel.CreateProcessArgs) error {
+ if procArgs.Filename != "" {
+ // Sanity check.
+ if !path.IsAbs(procArgs.Filename) {
+ return fmt.Errorf("filename must be absolute: %q", procArgs.Filename)
+ }
+ // Nothing to set.
+ return nil
+ }
+
+ if len(procArgs.Argv) == 0 {
+ return fmt.Errorf("Argv must not be empty")
+ }
+
+ f, err := getExecutablePath(ctx, mns, procArgs.Argv[0], procArgs.Envv)
+ if err != nil {
+ return err
+ }
+ procArgs.Filename = f
+ return nil
}
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 74d0c2534..2733c4d69 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -271,16 +271,8 @@ func newProcess(spec *specs.Spec, creds *auth.Credentials, utsns *kernel.UTSName
return kernel.CreateProcessArgs{}, fmt.Errorf("error creating limits: %v", err)
}
- // Get the executable path, which is a bit tricky because we have to
- // inspect the environment PATH which is relative to the root path.
- exec, err := specutils.GetExecutablePath(spec.Process.Args[0], spec.Root.Path, spec.Process.Env)
- if err != nil {
- return kernel.CreateProcessArgs{}, fmt.Errorf("error getting executable path: %v", err)
- }
-
// Create the process arguments.
procArgs := kernel.CreateProcessArgs{
- Filename: exec,
Argv: spec.Process.Args,
Envv: spec.Process.Env,
WorkingDirectory: spec.Process.Cwd, // Defaults to '/' if empty.
@@ -365,7 +357,7 @@ func (l *Loader) run() error {
// If we are restoring, we do not want to create a process.
// l.restore is set by the container manager when a restore call is made.
if !l.restore {
- err := setFileSystemForProcess(
+ if err := setFileSystemForProcess(
&l.rootProcArgs,
l.spec,
l.conf,
@@ -374,10 +366,16 @@ func (l *Loader) run() error {
l.rootProcArgs.Credentials,
l.rootProcArgs.Limits,
l.k,
- "" /* CID, which isn't needed for the root container */)
- if err != nil {
+ "" /* CID, which isn't needed for the root container */); err != nil {
return err
}
+
+ rootCtx := l.rootProcArgs.NewContext(l.k)
+ rootMns := l.k.RootMountNamespace()
+ if err := setExecutablePath(rootCtx, rootMns, &l.rootProcArgs); err != nil {
+ return fmt.Errorf("error setting executable path for %+v: %v", l.rootProcArgs, err)
+ }
+
// Create the root container init task.
if _, err := l.k.CreateProcess(l.rootProcArgs); err != nil {
return fmt.Errorf("failed to create init process: %v", err)
@@ -443,7 +441,7 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
ioFDs = append(ioFDs, fd)
}
- err = setFileSystemForProcess(
+ if err := setFileSystemForProcess(
&procArgs,
spec,
conf,
@@ -452,13 +450,14 @@ func (l *Loader) startContainer(k *kernel.Kernel, spec *specs.Spec, conf *Config
creds,
procArgs.Limits,
k,
- cid)
- if err != nil {
+ cid); err != nil {
return 0, fmt.Errorf("failed to create new process: %v", err)
}
- if procArgs.Filename, err = GetExecutablePathInternal(procArgs.NewContext(k), &procArgs); err != nil {
- return 0, err
+ ctx := procArgs.NewContext(l.k)
+ mns := k.RootMountNamespace()
+ if err := setExecutablePath(ctx, mns, &procArgs); err != nil {
+ return 0, fmt.Errorf("error setting executable path for %+v: %v", procArgs, err)
}
tg, err := l.k.CreateProcess(procArgs)