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
[], [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])
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],
genl.c genl.h \
\
caps.c caps.h \
+ seccomp.c seccomp.h \
mainloop.c mainloop.h \
af_unix.c af_unix.h \
\
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 \
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
#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);
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 *);
{ "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);
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)
{
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
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));
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;