summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2015-08-28 08:47:33 -0400
committerColin Walters <walters@verbum.org>2015-08-28 09:15:11 -0400
commit8cee4ab7345f126d1dec55b7ca1f28e8090a58d3 (patch)
treeb2c60c914d3202f6ccf2bc6b8553af15cba25ed8
parent99a02e4114b06edf6c03fcc01e09c137f1fc67dd (diff)
downloadlinux-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.am8
-rw-r--r--TODO1
-rw-r--r--configure.ac4
-rw-r--r--doc/linux-user-chroot.812
-rw-r--r--src/linux-user-chroot.c20
-rw-r--r--src/setup-seccomp.c235
-rw-r--r--src/setup-seccomp.h24
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
diff --git a/TODO b/TODO
index 3f32083..e69de29 100644
--- a/TODO
+++ b/TODO
@@ -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);