init: move close(stateDirFd) before seccomp apply

This further reduces the number of syscalls that a user needs to enable
in their seccomp profile.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
This commit is contained in:
Aleksa Sarai 2017-08-24 16:59:01 +10:00
parent 1c81e2a794
commit 3ddde27d7d
No known key found for this signature in database
GPG Key ID: 9E18AA267DDB8DB4
1 changed files with 24 additions and 16 deletions

View File

@ -30,15 +30,15 @@ func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) {
var newperms uint32 var newperms uint32
if l.config.Config.Namespaces.Contains(configs.NEWUSER) { if l.config.Config.Namespaces.Contains(configs.NEWUSER) {
// with user ns we need 'other' search permissions // With user ns we need 'other' search permissions.
newperms = 0x8 newperms = 0x8
} else { } else {
// without user ns we need 'UID' search permissions // Without user ns we need 'UID' search permissions.
newperms = 0x80000 newperms = 0x80000
} }
// create a unique per session container name that we can // Create a unique per session container name that we can join in setns;
// join in setns; however, other containers can also join it // However, other containers can also join it.
return fmt.Sprintf("_ses.%s", l.config.ContainerId), 0xffffffff, newperms return fmt.Sprintf("_ses.%s", l.config.ContainerId), 0xffffffff, newperms
} }
@ -46,12 +46,12 @@ func (l *linuxStandardInit) Init() error {
if !l.config.Config.NoNewKeyring { if !l.config.Config.NoNewKeyring {
ringname, keepperms, newperms := l.getSessionRingParams() ringname, keepperms, newperms := l.getSessionRingParams()
// do not inherit the parent's session keyring // Do not inherit the parent's session keyring.
sessKeyId, err := keys.JoinSessionKeyring(ringname) sessKeyId, err := keys.JoinSessionKeyring(ringname)
if err != nil { if err != nil {
return err return err
} }
// make session keyring searcheable // Make session keyring searcheable.
if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil { if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil {
return err return err
} }
@ -150,19 +150,20 @@ func (l *linuxStandardInit) Init() error {
if err := pdeath.Restore(); err != nil { if err := pdeath.Restore(); err != nil {
return err return err
} }
// compare the parent from the initial start of the init process and make sure that it did not change. // Compare the parent from the initial start of the init process and make
// if the parent changes that means it died and we were reparented to something else so we should // sure that it did not change. if the parent changes that means it died
// just kill ourself and not cause problems for someone else. // and we were reparented to something else so we should just kill ourself
// and not cause problems for someone else.
if unix.Getppid() != l.parentPid { if unix.Getppid() != l.parentPid {
return unix.Kill(unix.Getpid(), unix.SIGKILL) return unix.Kill(unix.Getpid(), unix.SIGKILL)
} }
// check for the arg before waiting to make sure it exists and it is returned // Check for the arg before waiting to make sure it exists and it is
// as a create time error. // returned as a create time error.
name, err := exec.LookPath(l.config.Args[0]) name, err := exec.LookPath(l.config.Args[0])
if err != nil { if err != nil {
return err return err
} }
// close the pipe to signal that we have completed our init. // Close the pipe to signal that we have completed our init.
l.pipe.Close() l.pipe.Close()
// Wait for the FIFO to be opened on the other side before exec-ing the // Wait for the FIFO to be opened on the other side before exec-ing the
// user process. We open it through /proc/self/fd/$fd, because the fd that // user process. We open it through /proc/self/fd/$fd, because the fd that
@ -170,19 +171,26 @@ func (l *linuxStandardInit) Init() error {
// re-open an O_PATH fd through /proc. // re-open an O_PATH fd through /proc.
fd, err := unix.Open(fmt.Sprintf("/proc/self/fd/%d", l.fifoFd), unix.O_WRONLY|unix.O_CLOEXEC, 0) fd, err := unix.Open(fmt.Sprintf("/proc/self/fd/%d", l.fifoFd), unix.O_WRONLY|unix.O_CLOEXEC, 0)
if err != nil { if err != nil {
return newSystemErrorWithCause(err, "openat exec fifo") return newSystemErrorWithCause(err, "open exec fifo")
} }
if _, err := unix.Write(fd, []byte("0")); err != nil { if _, err := unix.Write(fd, []byte("0")); err != nil {
return newSystemErrorWithCause(err, "write 0 exec fifo") return newSystemErrorWithCause(err, "write 0 exec fifo")
} }
// Close the O_PATH fifofd fd before exec because the kernel resets
// dumpable in the wrong order. This has been fixed in newer kernels, but
// we keep this to ensure CVE-2016-9962 doesn't re-emerge on older kernels.
// N.B. the core issue itself (passing dirfds to the host filesystem) has
// since been resolved.
// https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
unix.Close(l.fifoFd)
// Set seccomp as close to execve as possible, so as few syscalls take
// place afterward (reducing the amount of syscalls that users need to
// enable in their seccomp profiles).
if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges {
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
return newSystemErrorWithCause(err, "init seccomp") 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
unix.Close(l.fifoFd)
if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil { if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil {
return newSystemErrorWithCause(err, "exec user process") return newSystemErrorWithCause(err, "exec user process")
} }