From 5d93fed3d27f1e2bab58bad13b180a7a81d0b378 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 7 Dec 2016 15:05:51 -0800 Subject: [PATCH] Set init processes as non-dumpable This sets the init processes that join and setup the container's namespaces as non-dumpable before they setns to the container's pid (or any other ) namespace. This settings is automatically reset to the default after the Exec in the container so that it does not change functionality for the applications that are running inside, just our init processes. This prevents parent processes, the pid 1 of the container, to ptrace the init process before it drops caps and other sets LSMs. This patch also ensures that the stateDirFD being used is still closed prior to exec, even though it is set as O_CLOEXEC, because of the order in the kernel. https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318 The order during the exec syscall is that the process is set back to dumpable before O_CLOEXEC are processed. Signed-off-by: Michael Crosby --- libcontainer/init_linux.go | 5 +++-- libcontainer/nsenter/nsexec.c | 5 +++++ libcontainer/setns_init_linux.go | 9 +++++++-- libcontainer/standard_init_linux.go | 3 +++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index 01f32f506..9d5f06802 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -77,8 +77,9 @@ func newContainerInit(t initType, pipe *os.File, stateDirFD int) (initer, error) switch t { case initSetns: return &linuxSetnsInit{ - pipe: pipe, - config: config, + pipe: pipe, + config: config, + stateDirFD: stateDirFD, }, nil case initStandard: return &linuxStandardInit{ diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c index 5c6b95e1a..7d15aeb5a 100644 --- a/libcontainer/nsenter/nsexec.c +++ b/libcontainer/nsenter/nsexec.c @@ -424,6 +424,11 @@ void nsexec(void) if (pipenum == -1) return; + /* make the process non-dumpable */ + if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) != 0) { + bail("failed to set process as non-dumpable"); + } + /* Parse all of the netlink configuration. */ nl_parse(pipenum, &config); diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go index 2e80450d6..372dfd357 100644 --- a/libcontainer/setns_init_linux.go +++ b/libcontainer/setns_init_linux.go @@ -5,6 +5,7 @@ package libcontainer import ( "fmt" "os" + "syscall" "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/keys" @@ -16,8 +17,9 @@ import ( // linuxSetnsInit performs the container's initialization for running a new process // inside an existing container. type linuxSetnsInit struct { - pipe *os.File - config *initConfig + pipe *os.File + config *initConfig + stateDirFD int } func (l *linuxSetnsInit) getSessionRingName() string { @@ -58,5 +60,8 @@ func (l *linuxSetnsInit) Init() error { if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { return err } + // close the statedir fd before exec because the kernel resets dumpable in the wrong order + // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318 + syscall.Close(l.stateDirFD) return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) } diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index 588077b5d..7b68458e6 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -179,6 +179,9 @@ func (l *linuxStandardInit) Init() error { return newSystemErrorWithCause(err, "init seccomp") } } + // close the statedir fd before exec because the kernel resets dumpable in the wrong order + // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318 + syscall.Close(l.stateDirFD) if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil { return newSystemErrorWithCause(err, "exec user process") }