]> git.proxmox.com Git - mirror_lxc.git/commitdiff
Introduce support for seccomp.
authorSerge Hallyn <serge.hallyn@canonical.com>
Sat, 28 Jul 2012 02:13:53 +0000 (21:13 -0500)
committerStéphane Graber <stgraber@ubuntu.com>
Mon, 12 Nov 2012 17:04:30 +0000 (12:04 -0500)
Hi,

This patch is so far just a proof of concept.  The libseccomp api will be
changing soon so it probably wouldn't be worth pulling this until it is
updated for the new API.

This patch introduces support for seccomp to lxc.  Seccomp lets a program
restrict its own (and its children's) future access to system calls.  It
uses a simple whitelist system call policy file.  It would probably be
better to switch to something more symbolic (i.e specifying 'open' rather
than the syscall #, especially given container arch flexibility).

I just wanted to get this out there as a first step.  You can also get
source for an ubuntu package based on this patch at
https://code.launchpad.net/~serge-hallyn/ubuntu/quantal/lxc/lxc-seccomp

Signed-off-by: Serge Hallyn <serge.hallyn@canonical.com>
README
configure.ac
src/lxc/Makefile.am
src/lxc/conf.h
src/lxc/confile.c
src/lxc/lxc-clone.in
src/lxc/lxcseccomp.h [new file with mode: 0644]
src/lxc/seccomp.c [new file with mode: 0644]
src/lxc/start.c

diff --git a/README b/README
index 74fa6ff4471078108e81410a46f696ccd1ff8fde..0cf024629a7346187f8d050fdd669bd2f9a4f96a 100644 (file)
--- a/README
+++ b/README
@@ -52,3 +52,27 @@ Portability:
 
 AUTHOR
        Daniel Lezcano <daniel.lezcano@free.fr>
+
+Seccomp with LXC
+----------------
+
+To restrict a container with seccomp, you must specify a profile which is
+basically a whitelist of system calls it may execute.  In the container
+config file, add a line like
+
+lxc.seccomp = /var/lib/lxc/q1/seccomp.full
+
+I created a usable (but basically worthless) seccomp.full file using
+
+cat > seccomp.full << EOF
+1
+whitelist
+EOF
+for i in `seq 0 300`; do
+       echo $i >> secomp.full
+done
+for i in `seq 1024 1079`; do
+       echo $i >> seccomp.full
+done
+
+ -- Serge Hallyn <serge.hallyn@ubuntu.com>  Fri, 27 Jul 2012 15:47:02 +0600
index 900e1e79961a51675cacdf6cad5d86fef03560fa..a3b961663d0de01ff329a58ad0f9d89d860bb47c 100644 (file)
@@ -23,6 +23,11 @@ AC_ARG_ENABLE([apparmor],
        [], [enable_apparmor=yes])
 AM_CONDITIONAL([ENABLE_APPARMOR], [test "x$enable_apparmor" = "xyes"])
 
+AC_ARG_ENABLE([seccomp],
+       [AC_HELP_STRING([--enable-seccomp], [enable seccomp])],
+       [], [enable_seccomp=yes])
+AM_CONDITIONAL([ENABLE_SECCOMP], [test "x$enable_seccomp" = "xyes"])
+
 AC_ARG_ENABLE([doc],
        [AC_HELP_STRING([--enable-doc], [make mans (require docbook2man installed) [default=auto]])],
        [], [enable_doc=auto])
@@ -39,6 +44,11 @@ AM_COND_IF([ENABLE_APPARMOR],
      AC_CHECK_LIB([apparmor], [aa_change_profile],[],[AC_MSG_ERROR([You must install the AppArmor development package in order to compile lxc])])
      AC_SUBST([APPARMOR_LIBS], [-lapparmor])])
 
+AM_COND_IF([ENABLE_SECCOMP],
+    [AC_CHECK_HEADER([seccomp.h],[],[AC_MSG_ERROR([You must install the seccomp development package in order to compile lxc])])
+     AC_CHECK_LIB([seccomp], [seccomp_init],[],[AC_MSG_ERROR([You must install the seccomp development package in order to compile lxc])])
+     AC_SUBST([SECCOMP_LIBS], [-lseccomp])])
+
 AM_CONDITIONAL([ENABLE_DOCBOOK], [test "x$have_docbook" = "xyes"])
 
 AC_ARG_ENABLE([examples],
index 50e67bbf2984654424d5dcaa44e96ec9890ca859..29dfa00d3d49cfce4894824dee7198e11f51575a 100644 (file)
@@ -50,6 +50,7 @@ liblxc_so_SOURCES = \
         genl.c genl.h \
        \
        caps.c caps.h \
+       seccomp.c seccomp.h \
        mainloop.c mainloop.h \
        af_unix.c af_unix.h \
        \
@@ -65,13 +66,17 @@ if ENABLE_APPARMOR
 AM_CFLAGS += -DHAVE_APPARMOR
 endif
 
+if ENABLE_SECCOMP
+AM_CFLAGS += -DHAVE_SECCOMP
+endif
+
 liblxc_so_CFLAGS = -fPIC -DPIC $(AM_CFLAGS)
 
 liblxc_so_LDFLAGS = \
        -shared \
        -Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION)))
 
-liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS)
+liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS)
 
 bin_SCRIPTS = \
        lxc-ps \
@@ -110,7 +115,7 @@ AM_LDFLAGS = -Wl,-E
 if ENABLE_RPATH
 AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
 endif
-LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@
+LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SECCOMP_LIBS@
 
 lxc_attach_SOURCES = lxc_attach.c
 lxc_cgroup_SOURCES = lxc_cgroup.c
index eee12b7b5c7da4de42ef3cabea4717ec61093ed2..ad48042af67ef6cb184d5e03e4dd37234adfd4f6 100644 (file)
@@ -229,6 +229,7 @@ struct lxc_conf {
 #if HAVE_APPARMOR /* || HAVE_SELINUX || HAVE_SMACK */
        int lsm_umount_proc;
 #endif
+       char *seccomp;  // filename with the seccomp rules
 };
 
 int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf);
index 4f816f55b5b55d51340f28f0821b0c1d7caa97a6..367a92cd07963898d907e635531599d63d4af056 100644 (file)
@@ -75,6 +75,7 @@ static int config_network_ipv6(const char *, char *, struct lxc_conf *);
 static int config_network_ipv6_gateway(const char *, char *, struct lxc_conf *);
 static int config_cap_drop(const char *, char *, struct lxc_conf *);
 static int config_console(const char *, char *, struct lxc_conf *);
+static int config_seccomp(const char *, char *, struct lxc_conf *);
 
 typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
 
@@ -118,6 +119,7 @@ static struct config config[] = {
        { "lxc.network.ipv6",         config_network_ipv6         },
        { "lxc.cap.drop",             config_cap_drop             },
        { "lxc.console",              config_console              },
+       { "lxc.seccomp",              config_seccomp              },
 };
 
 static const size_t config_size = sizeof(config)/sizeof(struct config);
@@ -610,6 +612,26 @@ static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
        return 0;
 }
 
+static int config_seccomp(const char *key, char *value,
+                                struct lxc_conf *lxc_conf)
+{
+       char *path;
+
+       if (lxc_conf->seccomp) {
+               ERROR("seccomp already defined");
+               return -1;
+       }
+       path = strdup(value);
+       if (!path) {
+               SYSERROR("failed to strdup '%s': %m", value);
+               return -1;
+       }
+
+       lxc_conf->seccomp = path;
+
+       return 0;
+}
+
 static int config_hook(const char *key, char *value,
                                 struct lxc_conf *lxc_conf)
 {
index 04ef20bb2465055e50892d26a7afe5e3a449acc5..05d993df280a7489acb770b36f4a9277497e69ee 100644 (file)
@@ -175,7 +175,7 @@ cp $lxc_path/$lxc_orig/config $lxc_path/$lxc_new/config
 sed -i '/lxc.utsname/d' $lxc_path/$lxc_new/config
 echo "lxc.utsname = $hostname" >> $lxc_path/$lxc_new/config
 
-grep "lxc.mount[ \t]" $lxc_path/$lxc_new/config >/dev/null 2>&1 && { sed -i '/lxc.mount[ \t]/d' $lxc_path/$lxc_new/config; echo "lxc.mount = $lxc_path/$lxc_new/fstab" >> $lxc_path/$lxc_new/config; }
+grep "lxc.mount =" $lxc_path/$lxc_new/config >/dev/null 2>&1 && { sed -i '/lxc.mount =/d' $lxc_path/$lxc_new/config; echo "lxc.mount = $lxc_path/$lxc_new/fstab" >> $lxc_path/$lxc_new/config; }
 
 if [ -e  $lxc_path/$lxc_orig/fstab ];then
     cp $lxc_path/$lxc_orig/fstab $lxc_path/$lxc_new/fstab
diff --git a/src/lxc/lxcseccomp.h b/src/lxc/lxcseccomp.h
new file mode 100644 (file)
index 0000000..00262a5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright Canonical, Inc. 2012
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@canonical.com>
+ *
+ * This library 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.1 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _lxc_seccomp_h
+
+#include "conf.h"
+
+#ifdef HAVE_SECCOMP
+int lxc_seccomp_load(struct lxc_conf *conf);
+int lxc_read_seccomp_config(struct lxc_conf *conf);
+#else
+static inline int lxc_seccomp_load(struct lxc_conf *conf) {
+       return 0;
+}
+
+static inline int lxc_read_seccomp_config(struct lxc_conf *conf) {
+       return 0;
+}
+#endif
+
+#endif
diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c
new file mode 100644 (file)
index 0000000..f2c5d00
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright Canonical, Inc. 2012
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn@canonical.com>
+ *
+ * This library 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.1 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <seccomp.h>
+#include <errno.h>
+#include <seccomp.h>
+#include "lxcseccomp.h"
+
+#include "log.h"
+
+lxc_log_define(lxc_seccomp, lxc);
+
+/*
+ * The first line of the config file has a policy language version
+ * the second line has some directives
+ * then comes policy subject to the directives
+ * right now version must be '1'
+ * the directives must include 'whitelist' (only type of policy currently
+ * supported) and can include 'debug' (though debug is not yet supported).
+ */
+static int parse_config(FILE *f, struct lxc_conf *conf)
+{
+       char line[1024];
+       int ret, version;
+
+       ret = fscanf(f, "%d\n", &version);
+       if (ret != 1 || version != 1) {
+               ERROR("invalid version");
+               return -1;
+       }
+       if (!fgets(line, 1024, f)) {
+               ERROR("invalid config file");
+               return -1;
+       }
+       if (!strstr(line, "whitelist")) {
+               ERROR("only whitelist policy is supported");
+               return -1;
+       }
+       if (strstr(line, "debug")) {
+               ERROR("debug not yet implemented");
+               return -1;
+       }
+       /* now read in the whitelist entries one per line */
+       while (fgets(line, 1024, f)) {
+               int nr;
+               ret = sscanf(line, "%d", &nr);
+               if (ret != 1)
+                       return -1;
+               ret = seccomp_rule_add(SCMP_ACT_ALLOW, nr, 0);
+               if (ret < 0) {
+                       ERROR("failed loading allow rule for %d\n", nr);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+int lxc_read_seccomp_config(struct lxc_conf *conf)
+{
+       FILE *f;
+       int ret;
+
+       if (seccomp_init(SCMP_ACT_ERRNO(31)) < 0)  { /* for debug, pass in SCMP_ACT_TRAP */
+               ERROR("failed initializing seccomp");
+               return -1;
+       }
+       if (!conf->seccomp)
+               return 0;
+
+       /* turn of no-new-privs.  We don't want it in lxc, and it breaks
+        * with apparmor */
+       if (seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0)) {
+               ERROR("failed to turn off n-new-privs\n");
+               return -1;
+       }
+
+       f = fopen(conf->seccomp, "r");
+       if (!f) {
+               SYSERROR("failed to open seccomp policy file %s\n", conf->seccomp);
+               return -1;
+       }
+       ret = parse_config(f, conf);
+       fclose(f);
+       return ret;
+}
+
+int lxc_seccomp_load(struct lxc_conf *conf)
+{
+       int ret;
+       if (!conf->seccomp)
+               return 0;
+       ret = seccomp_load();
+       if (ret < 0) {
+               ERROR("Error loading the seccomp policy");
+               return -1;
+       }
+       return 0;
+}
index 19815fcab5b83c70de14ec1eb40c3f14151d850c..23ce1d94e495ed09239c931242e413aee8aecc58 100644 (file)
@@ -353,6 +353,11 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
                goto out_free;
        }
 
+       if (lxc_read_seccomp_config(conf) != 0) {
+               ERROR("failed loading seccomp policy");
+               goto out_free_name;
+       }
+
        /* Begin the set the state to STARTING*/
        if (lxc_set_state(name, handler, STARTING)) {
                ERROR("failed to set state '%s'", lxc_state2str(STARTING));
@@ -530,6 +535,9 @@ static int do_start(void *data)
        if (apparmor_load(handler) < 0)
                goto out_warn_father;
 
+       if (lxc_seccomp_load(handler->conf) != 0)
+               goto out_warn_father;
+
        if (run_lxc_hooks(handler->name, "start", handler->conf)) {
                ERROR("failed to run start hooks for container '%s'.", handler->name);
                goto out_warn_father;