mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 14:13:58 +08:00
40f1468413
While all modern kernels (and I do mean _all_ of them -- this syscall
was added in 2.6.10 before git had begun development!) have support for
this syscall, LXC has a default seccomp profile that returns ENOSYS for
this syscall. For most syscalls this would be a deal-breaker, and our
use of session keyrings is security-based there are a few mitigating
factors that make this change not-completely-insane:
* We already have a flag that disables the use of session keyrings
(for older kernels that had system-wide keyring limits and so
on). So disabling it is not a new idea.
* While the primary justification of using session keys *is*
security-based, it's more of a security-by-obscurity protection.
The main defense keyrings have is VFS credentials -- which is
something that users already have better security tools for
(setuid(2) and user namespaces).
* Given the security justification you might argue that we
shouldn't silently ignore this. However, the only way for the
kernel to return -ENOSYS is either being ridiculously old (at
which point we wouldn't work anyway) or that there is a seccomp
profile in place blocking it.
Given that the seccomp profile (if malicious) could very easily
just return 0 or a silly return code (or something even more
clever with seccomp-bpf) and trick us without this patch, there
isn't much of a significant change in how much seccomp can trick
us with or without this patch.
Given all of that over-analysis, I'm pretty convinced there isn't a
security problem in this very specific case and it will help out the
ChromeOS folks by allowing Docker to run inside their LXC container
setup. I'd be happy to be proven wrong.
Ref: https://bugs.chromium.org/p/chromium/issues/detail?id=860565
Signed-off-by: Aleksa Sarai <asarai@suse.de>
84 lines
2.5 KiB
Go
84 lines
2.5 KiB
Go
// +build linux
|
|
|
|
package libcontainer
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/apparmor"
|
|
"github.com/opencontainers/runc/libcontainer/keys"
|
|
"github.com/opencontainers/runc/libcontainer/seccomp"
|
|
"github.com/opencontainers/runc/libcontainer/system"
|
|
"github.com/opencontainers/selinux/go-selinux/label"
|
|
"github.com/pkg/errors"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// linuxSetnsInit performs the container's initialization for running a new process
|
|
// inside an existing container.
|
|
type linuxSetnsInit struct {
|
|
pipe *os.File
|
|
consoleSocket *os.File
|
|
config *initConfig
|
|
}
|
|
|
|
func (l *linuxSetnsInit) getSessionRingName() string {
|
|
return fmt.Sprintf("_ses.%s", l.config.ContainerId)
|
|
}
|
|
|
|
func (l *linuxSetnsInit) Init() error {
|
|
if !l.config.Config.NoNewKeyring {
|
|
// Do not inherit the parent's session keyring.
|
|
if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil {
|
|
// Same justification as in standart_init_linux.go as to why we
|
|
// don't bail on ENOSYS.
|
|
//
|
|
// TODO(cyphar): And we should have logging here too.
|
|
if errors.Cause(err) != unix.ENOSYS {
|
|
return errors.Wrap(err, "join session keyring")
|
|
}
|
|
}
|
|
}
|
|
if l.config.CreateConsole {
|
|
if err := setupConsole(l.consoleSocket, l.config, false); err != nil {
|
|
return err
|
|
}
|
|
if err := system.Setctty(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if l.config.NoNewPrivileges {
|
|
if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
// Without NoNewPrivileges seccomp is a privileged operation, so we need to
|
|
// do this before dropping capabilities; otherwise do it as late as possible
|
|
// just before execve so as few syscalls take place after it as possible.
|
|
if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges {
|
|
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := finalizeNamespace(l.config); err != nil {
|
|
return err
|
|
}
|
|
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
|
|
return err
|
|
}
|
|
if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
|
|
return err
|
|
}
|
|
// 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 err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
|
|
return newSystemErrorWithCause(err, "init seccomp")
|
|
}
|
|
}
|
|
return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
|
|
}
|