The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/2041
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === In particular, * make the default seccomp config optional * add a knob to block x32 syscalls on amd64 (enabled by default) * add a way for users to inject their own seccomp stuff Signed-off-by: Tycho Andersen <tycho.ander...@canonical.com>
From 5b04f732976ff84ea54ee828274ef88aad066796 Mon Sep 17 00:00:00 2001 From: Tycho Andersen <tycho.ander...@canonical.com> Date: Mon, 23 May 2016 09:40:06 -0600 Subject: [PATCH] add some seccomp knobs In particular, * make the default seccomp config optional * add a knob to block x32 syscalls on amd64 (enabled by default) * add a way for users to inject their own seccomp stuff Signed-off-by: Tycho Andersen <tycho.ander...@canonical.com> --- doc/configuration.md | 3 ++ lxd/container.go | 6 ++++ lxd/container_lxc.go | 10 +++--- lxd/seccomp.go | 92 +++++++++++++++++++++++++++++++++++++++++++++++++--- test/suites/basic.sh | 11 +++++++ 5 files changed, 114 insertions(+), 8 deletions(-) diff --git a/doc/configuration.md b/doc/configuration.md index 9c94db7..d4a1afb 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -83,9 +83,12 @@ limits.processes | integer | - (max) | yes | Maximu linux.kernel\_modules | string | - | yes | Comma separated list of kernel modules to load before starting the container raw.apparmor | blob | - | yes | Apparmor profile entries to be appended to the generated profile raw.lxc | blob | - | no | Raw LXC configuration to be appended to the generated one +raw.seccomp | blob | - | no | Raw LXC seccomp profile string to append to the generated one security.nesting | boolean | false | yes | Support running lxd (nested) inside the container security.privileged | boolean | false | no | Runs the container in privileged mode user.\* | string | - | n/a | Free form user key/value storage (can be used in search) +security.syscalls.default | boolean | true | no | Enables the default syscall blacklist +security.syscalls.compat | boolean | true | no | On x86\_64 this enables blocking of compat\_\* syscalls, it is a no-op on other arches The following volatile keys are currently internally used by LXD: diff --git a/lxd/container.go b/lxd/container.go index 9c196ca..7da08ec 100644 --- a/lxd/container.go +++ b/lxd/container.go @@ -109,10 +109,16 @@ func containerValidConfigKey(key string, value string) error { return isBool(key, value) case "security.nesting": return isBool(key, value) + case "security.syscalls.default": + return isBool(key, value) + case "security.syscalls.compat": + return isBool(key, value) case "raw.apparmor": return nil case "raw.lxc": return lxcValidConfig(value) + case "raw.seccomp": + return nil case "volatile.apply_template": return nil case "volatile.base_image": diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index 6aa3510..0cccd49 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -466,10 +466,12 @@ func (c *containerLXC) initLXC() error { } } - // Setup Seccomp - err = lxcSetConfigItem(cc, "lxc.seccomp", SeccompProfilePath(c)) - if err != nil { - return err + // Setup Seccomp if necessary + if ContainerNeedsSeccomp(c) { + err = lxcSetConfigItem(cc, "lxc.seccomp", SeccompProfilePath(c)) + if err != nil { + return err + } } // Setup idmap diff --git a/lxd/seccomp.go b/lxd/seccomp.go index 11817a9..9e4a18d 100644 --- a/lxd/seccomp.go +++ b/lxd/seccomp.go @@ -8,9 +8,12 @@ import ( "github.com/lxc/lxd/shared" ) -const DEFAULT_SECCOMP_POLICY = ` +const SECCOMP_HEADER = ` 2 blacklist +` + +const DEFAULT_SECCOMP_POLICY = ` reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 1 @@ -19,16 +22,93 @@ init_module errno 1 finit_module errno 1 delete_module errno 1 ` - +const COMPAT_BLOCKING_POLICY = ` +[x86_64] +compat_sys_rt_sigaction +stub_x32_rt_sigreturn +compat_sys_ioctl +compat_sys_readv +compat_sys_writev +compat_sys_recvfrom +compat_sys_sendmsg +compat_sys_recvmsg +stub_x32_execve +compat_sys_ptrace +compat_sys_rt_sigpending +compat_sys_rt_sigtimedwait +compat_sys_rt_sigqueueinfo +compat_sys_sigaltstack +compat_sys_timer_create +compat_sys_mq_notify +compat_sys_kexec_load +compat_sys_waitid +compat_sys_set_robust_list +compat_sys_get_robust_list +compat_sys_vmsplice +compat_sys_move_pages +compat_sys_preadv64 +compat_sys_pwritev64 +compat_sys_rt_tgsigqueueinfo +compat_sys_recvmmsg +compat_sys_sendmmsg +compat_sys_process_vm_readv +compat_sys_process_vm_writev +compat_sys_setsockopt +compat_sys_getsockopt +compat_sys_io_setup +compat_sys_io_submit +stub_x32_execveat +` var seccompPath = shared.VarPath("security", "seccomp") func SeccompProfilePath(c container) string { return path.Join(seccompPath, c.Name()) } +func ContainerNeedsSeccomp(c container) bool { + config := c.ExpandedConfig() + + /* these are enabled by default, so if the keys aren't present, that + * means "true" + */ + default_, ok := config["security.syscalls.default"] + if !ok || shared.IsTrue(default_) { + return true + } + + compat, ok := config["security.syscalls.compat"] + if !ok || shared.IsTrue(compat) { + return true + } + + raw := config["raw.seccomp"] + if raw != "" { + return true + } + + return false +} + func getSeccompProfileContent(c container) string { - /* for now there are no seccomp knobs. */ - return DEFAULT_SECCOMP_POLICY + config := c.ExpandedConfig() + policy := SECCOMP_HEADER + + default_, ok := config["security.syscalls.default"] + if !ok || shared.IsTrue(default_) { + policy += DEFAULT_SECCOMP_POLICY + } + + compat, ok := config["security.syscalls.compat"] + if !ok || shared.IsTrue(compat) { + policy += COMPAT_BLOCKING_POLICY + } + + raw := config["raw.seccomp"] + if raw != "" { + policy += raw + } + + return policy } func SeccompCreateProfile(c container) error { @@ -38,6 +118,10 @@ func SeccompCreateProfile(c container) error { * the mtime on the file for any compiler purpose, so let's just write * out the profile. */ + if !ContainerNeedsSeccomp(c) { + return nil + } + profile := getSeccompProfileContent(c) if err := os.MkdirAll(seccompPath, 0700); err != nil { return err diff --git a/test/suites/basic.sh b/test/suites/basic.sh index b2f3eef..df52e82 100644 --- a/test/suites/basic.sh +++ b/test/suites/basic.sh @@ -250,6 +250,17 @@ test_basic_usage() { lxc delete lxd-apparmor-test [ ! -f "${LXD_DIR}/security/apparmor/profiles/lxd-lxd-apparmor-test" ] + lxc launch testimage lxd-seccomp-test + init=$(lxc info lxd-seccomp-test | grep Pid | cut -f2 -d" ") + [ "$(grep Seccomp /proc/${init}/status | cut -f2)" -eq "2" ] + lxc stop --force lxd-seccomp-test + lxc config set testimage security.syscalls.default false + lxc config set testimage security.syscalls.compat false + lxc start lxd-seccomp-test + init=$(lxc info lxd-seccomp-test | grep Pid | cut -f2 -d" ") + [ "$(grep Seccomp /proc/${init}/status | cut -f2)" -eq "0" ] + lxc stop --force lxd-seccomp-test + # make sure that privileged containers are not world-readable lxc profile create unconfined lxc profile set unconfined security.privileged true
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel