[linux-user-chroot/walters-seccomp-profile-v1] seccomp: Add version 1 that blocks `keyctl` due to CVE-2016-0728



commit 3981d30f44f550d6680fa9aef4c74fbb83c3770f
Author: Colin Walters <walters verbum org>
Date:   Wed Jan 20 12:27:10 2016 -0500

    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);


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