[linux-user-chroot] Add seccomp and rules imported from xdg-app/Sandstorm.io



commit 8cee4ab7345f126d1dec55b7ca1f28e8090a58d3
Author: Colin Walters <walters verbum org>
Date:   Fri Aug 28 08:47:33 2015 -0400

    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.

 Makefile-user-chroot.am |    8 +-
 TODO                    |    1 -
 configure.ac            |    4 +
 doc/linux-user-chroot.8 |   12 +++
 src/linux-user-chroot.c |   20 ++++
 src/setup-seccomp.c     |  235 +++++++++++++++++++++++++++++++++++++++++++++++
 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
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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]