diff options
author | Colin Walters <walters@verbum.org> | 2015-08-28 08:47:33 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2015-08-28 09:15:11 -0400 |
commit | 8cee4ab7345f126d1dec55b7ca1f28e8090a58d3 (patch) | |
tree | b2c60c914d3202f6ccf2bc6b8553af15cba25ed8 | |
parent | 99a02e4114b06edf6c03fcc01e09c137f1fc67dd (diff) | |
download | linux-user-chroot-8cee4ab7345f126d1dec55b7ca1f28e8090a58d3.tar.gz |
Add seccomp and rules imported from xdg-app/Sandstorm.io
seccomp is disabled by default for backwards compatibility.
This "v0" version is a basic blacklist that turns off some of the
known historical attack surface, initially imported from xdg-app.
I added a note about code sharing - we should share rules among
container implementations.
-rw-r--r-- | Makefile-user-chroot.am | 8 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | doc/linux-user-chroot.8 | 12 | ||||
-rw-r--r-- | src/linux-user-chroot.c | 20 | ||||
-rw-r--r-- | src/setup-seccomp.c | 235 | ||||
-rw-r--r-- | src/setup-seccomp.h | 24 |
7 files changed, 301 insertions, 3 deletions
diff --git a/Makefile-user-chroot.am b/Makefile-user-chroot.am index 32db975..66f8eb4 100644 --- a/Makefile-user-chroot.am +++ b/Makefile-user-chroot.am @@ -17,9 +17,13 @@ bin_PROGRAMS += linux-user-chroot -linux_user_chroot_SOURCES = src/linux-user-chroot.c +linux_user_chroot_SOURCES = \ + src/setup-seccomp.c \ + src/linux-user-chroot.c \ + $(NULL) -linux_user_chroot_CFLAGS = $(AM_CFLAGS) +linux_user_chroot_CFLAGS = $(AM_CFLAGS) $(LIBSECCOMP_CFLAGS) +linux_user_chroot_LDFLAGS = $(LIBSECCOMP_LIBS) if BUILD_NEWNET_HELPER bin_PROGRAMS += linux-user-chroot-newnet @@ -1 +0,0 @@ -* seccomp support diff --git a/configure.ac b/configure.ac index a634c5b..3d2ca86 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,10 @@ AC_SUBST(WARN_CFLAGS) LT_PREREQ([2.2.4]) LT_INIT([disable-static]) +PKG_CHECK_MODULES(LIBSECCOMP, [libseccomp]) +AC_SUBST(LIBSECCOMP_CFLAGS) +AC_SUBST(LIBSECCOMP_LIBS) + AC_ARG_ENABLE(documentation, AC_HELP_STRING([--enable-documentation], [build documentation]),, diff --git a/doc/linux-user-chroot.8 b/doc/linux-user-chroot.8 index f1cae55..20e61e5 100644 --- a/doc/linux-user-chroot.8 +++ b/doc/linux-user-chroot.8 @@ -22,6 +22,7 @@ linux\-user\-chroot \- safely allow normal users to chroot .RB [ --unshare-ipc ] .RB [ --unshare-pid ] .RB [ --unshare-net ] +.RB [ --seccomp-profile-version ] .RB [ --mount-proc " \fIDIR\fR] .RB [ --mount-readonly " \fIDIR\fR"] .RB [ --mount-bind " \fISOURCE DEST\fR"] @@ -87,6 +88,17 @@ Add a bind mount while the command is executing. After setting the new root directory for the command, change the current working directory to be .IR DIR . +.TP +.BI \-\-seccomp-profile-version " DIR" +Seccomp is a tool to restrict the system calls applications +can make. As linux-user-chroot is designed for build systems, +we do not need to expose the entire system to build processes; +things like profiling should not happen during builds. + +This argument is an integer, where -1 means "no seccomp", +and "0" enables the first profile version. This is an +opt-in system to any future versions. +.IR DIR . .SH "EXIT STATUS" The exit status is the exit status of the executed command, or 1 if diff --git a/src/linux-user-chroot.c b/src/linux-user-chroot.c index ccab6f4..e3f4d75 100644 --- a/src/linux-user-chroot.c +++ b/src/linux-user-chroot.c @@ -27,6 +27,7 @@ #include "config.h" +/* Core libc/linux-headers stuff */ #define _GNU_SOURCE #include <unistd.h> #include <stdio.h> @@ -44,6 +45,8 @@ #include <sys/wait.h> #include <sched.h> +#include "setup-seccomp.h" + #ifndef PR_SET_NO_NEW_PRIVS #define PR_SET_NO_NEW_PRIVS 38 #endif @@ -168,6 +171,7 @@ main (int argc, int unshare_ipc = 0; int unshare_net = 0; int unshare_pid = 0; + int seccomp_profile_version = -1; int clone_flags = 0; int child_status = 0; pid_t child; @@ -271,6 +275,14 @@ main (int argc, chdir_target = argv[after_mount_arg_index+1]; after_mount_arg_index += 2; } + else if (strcmp (arg, "--seccomp-profile-version") == 0) + { + if ((argc - after_mount_arg_index) < 2) + fatal ("--seccomp-profile-version takes one argument"); + + seccomp_profile_version = atoi(argv[after_mount_arg_index+1]); + after_mount_arg_index += 2; + } else break; } @@ -411,6 +423,14 @@ main (int argc, if (chdir (chdir_target) < 0) fatal_errno ("chdir"); + /* Add the seccomp filters just before we exec */ + if (seccomp_profile_version == 0) + setup_seccomp_v0 (); + else if (seccomp_profile_version == -1) + ; + else + fatal ("Unknown --seccomp-profile-version"); + if (execvp (program, program_argv) < 0) fatal_errno ("execv"); } diff --git a/src/setup-seccomp.c b/src/setup-seccomp.c new file mode 100644 index 0000000..31e75ff --- /dev/null +++ b/src/setup-seccomp.c @@ -0,0 +1,235 @@ +/* Seccomp rules, originally from xdg-app, which looks clearly influenced + * by sandstorm-io/sandstorm/src/standstorm/supervisor.c++ + * + * Copyright (C) 2014 Alexander Larsson + * Copyright (C) 2015 Colin Walters <walters@verbum.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "config.h" +/* Core libc/linux-headers stuff */ +#define _GNU_SOURCE +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <stdarg.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/prctl.h> +#include <sys/fsuid.h> +#include <sys/mount.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/utsname.h> +#include <sched.h> + +/* Seccomp */ +#include <seccomp.h> + +#define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) + +#include "setup-seccomp.h" + +static void +die_with_error (const char *format, ...) +{ + va_list args; + int errsv; + + errsv = errno; + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + fprintf (stderr, ": %s\n", strerror (errsv)); + + exit (1); +} + +static void +die (const char *format, ...) +{ + va_list args; + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + fprintf (stderr, "\n"); + + exit (1); +} + +static void +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. + */ +void +setup_seccomp_v0 (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[] = { + /* Block dmesg */ + {SCMP_SYS(syslog)}, + /* Useless old syscall */ + {SCMP_SYS(uselib)}, + /* Don't allow you to switch to bsd emulation or whatnot */ + {SCMP_SYS(personality)}, + /* Don't allow disabling accounting */ + {SCMP_SYS(acct)}, + /* 16-bit code is unnecessary in the sandbox, and modify_ldt is a + historic source of interesting information leaks. */ + {SCMP_SYS(modify_ldt)}, + /* Don't allow reading current quota use */ + {SCMP_SYS(quotactl)}, + + /* Scary VM/NUMA ops */ + {SCMP_SYS(move_pages)}, + {SCMP_SYS(mbind)}, + {SCMP_SYS(get_mempolicy)}, + {SCMP_SYS(set_mempolicy)}, + {SCMP_SYS(migrate_pages)}, + + /* Don't allow subnamespace setups: */ + {SCMP_SYS(unshare)}, + {SCMP_SYS(mount)}, + {SCMP_SYS(pivot_root)}, + {SCMP_SYS(clone), &SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)}, + + /* Utterly terrifying profiling operations */ + {SCMP_SYS(perf_event_open)} + }; + /* Blacklist all but unix, inet, inet6 and netlink */ + int socket_family_blacklist[] = { + AF_AX25, + AF_IPX, + AF_APPLETALK, + AF_NETROM, + AF_BRIDGE, + AF_ATMPVC, + AF_X25, + AF_ROSE, + AF_DECnet, + AF_NETBEUI, + AF_SECURITY, + 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); + } + + /* 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 family = socket_family_blacklist[i]; + if (i == N_ELEMENTS (socket_family_blacklist) - 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)); + if (r < 0) + die_with_error ("Failed to block socket family %d", family); + } + } + + r = seccomp_load (seccomp); + if (r < 0) + die_with_error ("Failed to install seccomp audit filter: "); + + seccomp_release (seccomp); +} diff --git a/src/setup-seccomp.h b/src/setup-seccomp.h new file mode 100644 index 0000000..1d96578 --- /dev/null +++ b/src/setup-seccomp.h @@ -0,0 +1,24 @@ +/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil -*- + * + * linux-user-chroot: A setuid program that allows non-root users to safely chroot(2) + * + * Copyright 2015 Colin Walters <walters@verbum.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma once + +void setup_seccomp_v0 (void); |