From 3981d30f44f550d6680fa9aef4c74fbb83c3770f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 20 Jan 2016 12:27:10 -0500 Subject: [PATCH] seccomp: Add version 1 that blocks `keyctl` due to CVE-2016-0728 This entailed actually refactoring the code now so we can have versioned profiles. There's some code motion, but it's all relatively straightforward. --- src/linux-user-chroot.c | 4 +- src/setup-seccomp.c | 197 +++++++++++++++++++++++++++++------------------- src/setup-seccomp.h | 4 +- 3 files changed, 126 insertions(+), 79 deletions(-) diff --git a/src/linux-user-chroot.c b/src/linux-user-chroot.c index 4c9dbbb..29d9035 100644 --- a/src/linux-user-chroot.c +++ b/src/linux-user-chroot.c @@ -447,8 +447,8 @@ main (int argc, fatal_errno ("chdir"); /* Add the seccomp filters just before we exec */ - if (seccomp_profile_version == 0) - setup_seccomp_v0 (); + if (seccomp_profile_version >= 0 && seccomp_profile_version <= MAX_SECCOMP_PROFILE_VERSION) + setup_seccomp (seccomp_profile_version); else if (seccomp_profile_version == -1) ; else diff --git a/src/setup-seccomp.c b/src/setup-seccomp.c index fc00227..19d2396 100644 --- a/src/setup-seccomp.c +++ b/src/setup-seccomp.c @@ -85,48 +85,95 @@ die_oom (void) die ("Out of memory"); } -/* - * We're calling this filter "v0" - any future additions or changes - * should become new versions. This helps ensure backwards - * compatibility for build systems. +typedef struct { + int scall; + struct scmp_arg_cmp *arg; +} SyscallBlackListEntry; + + +/**** BEGIN NOTE ON CODE SHARING + * + * There are today a number of different Linux container + * implementations. That will likely continue for long into the + * future. But we can still try to share code, and it's important + * to do so because it affects what library and application writers + * can do, and we should support code portability between different + * container tools. + * + * This syscall blacklist is copied from xdg-app, which was in turn + * clearly influenced by the Sandstorm.io blacklist. + * + * If you make any changes here, I suggest sending the changes along + * to other sandbox maintainers. Using the libseccomp list is also + * an appropriate venue: + * https://groups.google.com/forum/#!topic/libseccomp + * + * A non-exhaustive list of links to container tooling that might + * want to share this blacklist: + * + * https://github.com/sandstorm-io/sandstorm + * in src/sandstorm/supervisor.c++ + * http://cgit.freedesktop.org/xdg-app/xdg-app/ + * in lib/xdg-app-helper.c + * https://git.gnome.org/browse/linux-user-chroot + * in src/setup-seccomp.c + * + **** END NOTE ON CODE SHARING */ -void -setup_seccomp_v0 (void) + +static scmp_filter_ctx +prepare_seccomp (void) { scmp_filter_ctx seccomp; - /**** BEGIN NOTE ON CODE SHARING - * - * There are today a number of different Linux container - * implementations. That will likely continue for long into the - * future. But we can still try to share code, and it's important - * to do so because it affects what library and application writers - * can do, and we should support code portability between different - * container tools. - * - * This syscall blacklist is copied from xdg-app, which was in turn - * clearly influenced by the Sandstorm.io blacklist. - * - * If you make any changes here, I suggest sending the changes along - * to other sandbox maintainers. Using the libseccomp list is also - * an appropriate venue: - * https://groups.google.com/forum/#!topic/libseccomp - * - * A non-exhaustive list of links to container tooling that might - * want to share this blacklist: - * - * https://github.com/sandstorm-io/sandstorm - * in src/sandstorm/supervisor.c++ - * http://cgit.freedesktop.org/xdg-app/xdg-app/ - * in lib/xdg-app-helper.c - * https://git.gnome.org/browse/linux-user-chroot - * in src/setup-seccomp.c - * - **** END NOTE ON CODE SHARING - */ - struct { - int scall; - struct scmp_arg_cmp *arg; - } syscall_blacklist[] = { + int r; + + seccomp = seccomp_init (SCMP_ACT_ALLOW); + if (!seccomp) + die_oom (); + + /* Add in all possible secondary archs we are aware of that + * this kernel might support. */ +#if defined(__i386__) || defined(__x86_64__) + r = seccomp_arch_add (seccomp, SCMP_ARCH_X86); + if (r < 0 && r != -EEXIST) + die_with_error ("Failed to add x86 architecture to seccomp filter"); + + r = seccomp_arch_add (seccomp, SCMP_ARCH_X86_64); + if (r < 0 && r != -EEXIST) + die_with_error ("Failed to add x86_64 architecture to seccomp filter"); + + r = seccomp_arch_add (seccomp, SCMP_ARCH_X32); + if (r < 0 && r != -EEXIST) + die_with_error ("Failed to add x32 architecture to seccomp filter"); +#endif + + return seccomp; +} + +static void +add_syscall_blacklist (scmp_filter_ctx seccomp, + const SyscallBlackListEntry *syscall_blacklist, + unsigned int n_entries) +{ + int i, r; + for (i = 0; i < n_entries; i++) + { + int scall = syscall_blacklist[i].scall; + if (syscall_blacklist[i].arg) + r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO(EPERM), scall, 1, *syscall_blacklist[i].arg); + else + r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO(EPERM), scall, 0); + if (r < 0 && r == -EFAULT /* unknown syscall */) + die_with_error ("Failed to block syscall %d", scall); + } +} + +static void +add_seccomp_v0 (scmp_filter_ctx seccomp) +{ + struct utsname uts; + + const SyscallBlackListEntry syscall_blacklist_v0[] = { /* Block dmesg */ {SCMP_SYS(syslog)}, /* Useless old syscall */ @@ -160,8 +207,9 @@ setup_seccomp_v0 (void) {SCMP_SYS(perf_event_open)}, {SCMP_SYS(ptrace)} }; + /* Blacklist all but unix, inet, inet6 and netlink */ - int socket_family_blacklist[] = { + static const int socket_family_blacklist_v0[] = { AF_AX25, AF_IPX, AF_APPLETALK, @@ -176,52 +224,21 @@ setup_seccomp_v0 (void) AF_KEY, AF_NETLINK + 1, /* Last gets CMP_GE, so order is important */ }; - int i, r; - struct utsname uts; - - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return die_oom (); - - /* Add in all possible secondary archs we are aware of that - * this kernel might support. */ -#if defined(__i386__) || defined(__x86_64__) - r = seccomp_arch_add (seccomp, SCMP_ARCH_X86); - if (r < 0 && r != -EEXIST) - die_with_error ("Failed to add x86 architecture to seccomp filter"); - - r = seccomp_arch_add (seccomp, SCMP_ARCH_X86_64); - if (r < 0 && r != -EEXIST) - die_with_error ("Failed to add x86_64 architecture to seccomp filter"); - - r = seccomp_arch_add (seccomp, SCMP_ARCH_X32); - if (r < 0 && r != -EEXIST) - die_with_error ("Failed to add x32 architecture to seccomp filter"); -#endif /* TODO: Should we filter the kernel keyring syscalls in some way? * We do want them to be used by desktop apps, but they could also perhaps * leak system stuff or secrets from other apps. */ - - for (i = 0; i < N_ELEMENTS (syscall_blacklist); i++) - { - int scall = syscall_blacklist[i].scall; - if (syscall_blacklist[i].arg) - r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO(EPERM), scall, 1, *syscall_blacklist[i].arg); - else - r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO(EPERM), scall, 0); - if (r < 0 && r == -EFAULT /* unknown syscall */) - die_with_error ("Failed to block syscall %d", scall); - } + add_syscall_blacklist (seccomp, syscall_blacklist_v0, N_ELEMENTS (syscall_blacklist_v0)); /* Socket filtering doesn't work on x86 */ if (uname (&uts) == 0 && strcmp (uts.machine, "i686") != 0) { - for (i = 0; i < N_ELEMENTS (socket_family_blacklist); i++) + int i, r; + for (i = 0; i < N_ELEMENTS (socket_family_blacklist_v0); i++) { - int family = socket_family_blacklist[i]; - if (i == N_ELEMENTS (socket_family_blacklist) - 1) + int family = socket_family_blacklist_v0[i]; + if (i == N_ELEMENTS (socket_family_blacklist_v0) - 1) r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1, SCMP_A0(SCMP_CMP_GE, family)); else r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO(EAFNOSUPPORT), SCMP_SYS(socket), 1, SCMP_A0(SCMP_CMP_EQ, family)); @@ -229,6 +246,34 @@ setup_seccomp_v0 (void) die_with_error ("Failed to block socket family %d", family); } } +} + +/* + * Any future additions or changes should become new versions. This + * helps ensure backwards compatibility for build systems. + */ +void +setup_seccomp (unsigned int profile_version) +{ + int r; + scmp_filter_ctx seccomp; + + assert (profile_version >= 0 && profile_version <= MAX_SECCOMP_PROFILE_VERSION); + + seccomp = prepare_seccomp (); + + add_seccomp_v0 (seccomp); + + if (profile_version > 0) + { + static const SyscallBlackListEntry v1_blacklist[] = { + + /* CVE-2016-0728 - https://lwn.net/Articles/672405/ */ + { SCMP_SYS(keyctl) } + + }; + add_syscall_blacklist (seccomp, v1_blacklist, N_ELEMENTS (v1_blacklist)); + } r = seccomp_load (seccomp); if (r < 0) diff --git a/src/setup-seccomp.h b/src/setup-seccomp.h index 1d96578..9be73c5 100644 --- a/src/setup-seccomp.h +++ b/src/setup-seccomp.h @@ -21,4 +21,6 @@ #pragma once -void setup_seccomp_v0 (void); +#define MAX_SECCOMP_PROFILE_VERSION 1 + +void setup_seccomp (unsigned int profile_version); -- 1.8.3.1