From f2628a707d46edcd93e9b75912f0d5aed5a170e0 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 19 Feb 2018 14:31:34 -0800 Subject: [PATCH 1/4] utils_linux: Avoid panic when process is unset As it can be since opencontainers/runtime-spec@c41ea83d (config: Make process optional, 2017-02-27, opencontainers/runtime-spec#701). Signed-off-by: W. Trevor King --- utils_linux.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/utils_linux.go b/utils_linux.go index 84731c844f0..99e72052f6e 100644 --- a/utils_linux.go +++ b/utils_linux.go @@ -97,7 +97,10 @@ func getDefaultImagePath(context *cli.Context) string { // newProcess returns a new libcontainer Process with the arguments from the // spec and stdio from the current process. -func newProcess(p specs.Process) (*libcontainer.Process, error) { +func newProcess(p *specs.Process) (*libcontainer.Process, error) { + if p == nil { + return &libcontainer.Process{}, nil + } lp := &libcontainer.Process{ Args: p.Args, Env: p.Env, @@ -261,7 +264,7 @@ func (r *runner) run(config *specs.Process) (int, error) { r.destroy() return -1, err } - process, err := newProcess(*config) + process, err := newProcess(config) if err != nil { r.destroy() return -1, err @@ -291,7 +294,8 @@ func (r *runner) run(config *specs.Process) (int, error) { // with detaching containers, and then we get a tty after the container has // started. handler := newSignalHandler(r.enableSubreaper, r.notifySocket) - tty, err := setupIO(process, rootuid, rootgid, config.Terminal, detach, r.consoleSocket) + terminal := config != nil && config.Terminal + tty, err := setupIO(process, rootuid, rootgid, terminal, detach, r.consoleSocket) if err != nil { r.destroy() return -1, err @@ -353,17 +357,21 @@ func (r *runner) terminate(p *libcontainer.Process) { func (r *runner) checkTerminal(config *specs.Process) error { detach := r.detach || (r.action == CT_ACT_CREATE) + terminal := config != nil && config.Terminal // Check command-line for sanity. - if detach && config.Terminal && r.consoleSocket == "" { + if detach && terminal && r.consoleSocket == "" { return fmt.Errorf("cannot allocate tty if runc will detach without setting console socket") } - if (!detach || !config.Terminal) && r.consoleSocket != "" { + if (!detach || !terminal) && r.consoleSocket != "" { return fmt.Errorf("cannot use console socket if runc will not detach or allocate tty") } return nil } func validateProcessSpec(spec *specs.Process) error { + if spec == nil { + return nil + } if spec.Cwd == "" { return fmt.Errorf("Cwd property must not be empty") } From e32d0d9e99d26baf39144d0bc581aa08fc1f6b75 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 19 Feb 2018 14:35:56 -0800 Subject: [PATCH 2/4] libcontainer/specconv/spec_linux: Avoid panic when Process is unset As it can be since opencontainers/runtime-spec@c41ea83d (config: Make process optional, 2017-02-27, opencontainers/runtime-spec#701). Signed-off-by: W. Trevor King --- libcontainer/specconv/spec_linux.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go index 01809d0f2e6..5126eac19e2 100644 --- a/libcontainer/specconv/spec_linux.go +++ b/libcontainer/specconv/spec_linux.go @@ -238,19 +238,21 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) { config.Seccomp = seccomp } } - if spec.Process.SelinuxLabel != "" { - config.ProcessLabel = spec.Process.SelinuxLabel - } - if spec.Process != nil && spec.Process.OOMScoreAdj != nil { - config.OomScoreAdj = *spec.Process.OOMScoreAdj - } - if spec.Process.Capabilities != nil { - config.Capabilities = &configs.Capabilities{ - Bounding: spec.Process.Capabilities.Bounding, - Effective: spec.Process.Capabilities.Effective, - Permitted: spec.Process.Capabilities.Permitted, - Inheritable: spec.Process.Capabilities.Inheritable, - Ambient: spec.Process.Capabilities.Ambient, + if spec.Process != nil { + if spec.Process.SelinuxLabel != "" { + config.ProcessLabel = spec.Process.SelinuxLabel + } + if spec.Process.OOMScoreAdj != nil { + config.OomScoreAdj = *spec.Process.OOMScoreAdj + } + if spec.Process.Capabilities != nil { + config.Capabilities = &configs.Capabilities{ + Bounding: spec.Process.Capabilities.Bounding, + Effective: spec.Process.Capabilities.Effective, + Permitted: spec.Process.Capabilities.Permitted, + Inheritable: spec.Process.Capabilities.Inheritable, + Ambient: spec.Process.Capabilities.Ambient, + } } } createHooks(spec, config) From ed4b83c0bd933cfdfb3c9039ac8fb8802caec355 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 19 Feb 2018 14:37:51 -0800 Subject: [PATCH 3/4] libcontainer/specconv/spec_linux: Avoid panic when Linux is unset As it can be since at least opencontainers/runtime-spec@b373a155 (config: Split platform-specific configuration into its own section, 2016-05-02, opencontainers/runtime-spec#414). Signed-off-by: W. Trevor King --- libcontainer/specconv/spec_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go index 5126eac19e2..e79b89eff73 100644 --- a/libcontainer/specconv/spec_linux.go +++ b/libcontainer/specconv/spec_linux.go @@ -257,7 +257,7 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) { } createHooks(spec, config) config.Version = specs.Version - if spec.Linux.IntelRdt != nil { + if spec.Linux != nil && spec.Linux.IntelRdt != nil { config.IntelRdt = &configs.IntelRdt{} if spec.Linux.IntelRdt.L3CacheSchema != "" { config.IntelRdt.L3CacheSchema = spec.Linux.IntelRdt.L3CacheSchema From 0cd9a7e2f5eed7e798fab92eb90dae9ffc64d55a Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Mon, 19 Feb 2018 16:43:13 -0800 Subject: [PATCH 4/4] libcontainer/standard_init_linux: Move LookPath to post-wait This avoids a panic for containers that do not set Process. And even if Process was set, there is no reason to require the executable to be available *at create time* [1]. Subsequent activity could be scheduled to get a binary in place at the configured location before 'start' is called. [1]: https://github.com/opencontainers/runc/pull/827#discussion_r63464201 Signed-off-by: W. Trevor King --- libcontainer/standard_init_linux.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index 02ea753eda3..5b579235c25 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -3,6 +3,7 @@ package libcontainer import ( + "errors" "fmt" "os" "os/exec" @@ -152,12 +153,6 @@ func (l *linuxStandardInit) Init() error { if unix.Getppid() != l.parentPid { return unix.Kill(unix.Getpid(), unix.SIGKILL) } - // Check for the arg before waiting to make sure it exists and it is - // returned as a create time error. - name, err := exec.LookPath(l.config.Args[0]) - if err != nil { - return err - } // Close the pipe to signal that we have completed our init. l.pipe.Close() // Wait for the FIFO to be opened on the other side before exec-ing the @@ -186,6 +181,13 @@ func (l *linuxStandardInit) Init() error { return newSystemErrorWithCause(err, "init seccomp") } } + if len(l.config.Args) == 0 { + return errors.New("no process arguments configured") + } + name, err := exec.LookPath(l.config.Args[0]) + if err != nil { + return err + } if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil { return newSystemErrorWithCause(err, "exec user process") }