Hello everyone!

I've written a patch which adds a new config keyword 
'lxc.cap.drop'. This keyword allows to specify capabilities which are
dropped before executing the container binary.

Example:

lxc.cap.drop = sys_chroot
lxc.cap.drop = mknod
lxc.cap.drop = sys_module

Reworked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
 doc/lxc.conf.sgml.in |   27 +++++++++++++++
 src/lxc/conf.c       |   91 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/conf.h       |    1 
 src/lxc/confile.c    |   22 ++++++++++++
 4 files changed, 141 insertions(+)

Index: lxc/src/lxc/conf.c
===================================================================
--- lxc.orig/src/lxc/conf.c
+++ lxc/src/lxc/conf.c
@@ -38,6 +38,8 @@
 #include <sys/socket.h>
 #include <sys/mount.h>
 #include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
 
 #include <arpa/inet.h>
 #include <fcntl.h>
@@ -75,6 +77,11 @@ struct mount_opt {
 	int flag;
 };
 
+struct caps_opt {
+	char *name;
+	int value;
+};
+
 static int instanciate_veth(struct lxc_netdev *);
 static int instanciate_macvlan(struct lxc_netdev *);
 static int instanciate_vlan(struct lxc_netdev *);
@@ -113,6 +120,45 @@ static struct mount_opt mount_opt[] = {
 	{ NULL,         0, 0              },
 };
 
+static struct caps_opt caps_opt[] = {
+ 	{ "chown",             CAP_CHOWN 	     },
+ 	{ "dac_override",      CAP_DAC_OVERRIDE      },
+ 	{ "dac_read_search",   CAP_DAC_READ_SEARCH   },
+ 	{ "fowner",            CAP_FOWNER            },
+ 	{ "fsetid",            CAP_FSETID            },
+	{ "kill",              CAP_KILL              },
+	{ "setgid",            CAP_SETGID            },
+	{ "setuid",            CAP_SETUID            },
+	{ "setpcap",           CAP_SETPCAP           },
+	{ "linux_immutable",   CAP_LINUX_IMMUTABLE   },
+	{ "net_bind_service",  CAP_NET_BIND_SERVICE  },
+	{ "net_broadcast",     CAP_NET_BROADCAST     },
+	{ "net_admin",         CAP_NET_ADMIN         },
+	{ "net_raw",           CAP_NET_RAW           },
+	{ "ipc_lock",          CAP_IPC_LOCK          },
+	{ "ipc_owner",         CAP_IPC_OWNER         },
+	{ "sys_module",        CAP_SYS_MODULE        },
+	{ "sys_rawio",         CAP_SYS_RAWIO         },
+	{ "sys_chroot",        CAP_SYS_CHROOT        },
+	{ "sys_ptrace",        CAP_SYS_PTRACE        },
+	{ "sys_pacct",         CAP_SYS_PACCT         },
+	{ "sys_admin",         CAP_SYS_ADMIN         },
+	{ "sys_boot",          CAP_SYS_BOOT          },
+	{ "sys_nice",          CAP_SYS_NICE          },
+	{ "sys_resource",      CAP_SYS_RESOURCE      },
+	{ "sys_time",          CAP_SYS_TIME          },
+	{ "sys_tty_config",    CAP_SYS_TTY_CONFIG    },
+	{ "mknod",             CAP_MKNOD             },
+	{ "lease",             CAP_LEASE             },
+	{ "audit_write",       CAP_AUDIT_WRITE       },
+	{ "audit_control",     CAP_AUDIT_CONTROL     },
+	{ "setfcap",           CAP_SETFCAP           },
+	{ "mac_override",      CAP_MAC_OVERRIDE      },
+	{ "mac_admin",         CAP_MAC_ADMIN         },
+	{ NULL,                0,		     },
+};
+
+
 static int configure_find_fstype_cb(char* buffer, void *data)
 {
 	struct cbarg {
@@ -793,6 +839,45 @@ static int setup_mount_entries(struct lx
 	return ret;
 }
 
+static int setup_caps(struct lxc_list *caps)
+{
+	struct lxc_list *iterator;
+	char *drop_entry;
+	int i, capid;
+
+	lxc_list_for_each(iterator, caps) {
+
+		drop_entry = iterator->elem;
+
+		capid = -1;
+
+		for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
+			if (strcmp(drop_entry, caps_opt[i].name))
+				continue;
+
+			capid = caps_opt[i].value;
+			break;
+		}
+
+	        if (capid < 0) {
+        		ERROR("unknown capability %s", drop_entry);
+        		return -1;
+		}
+
+		DEBUG("drop capability '%s' (%d)", drop_entry, capid);
+
+		if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) {
+                       SYSERROR("failed to remove %s capability", drop_entry);
+                       return -1;
+                }
+
+	}
+
+	DEBUG("capabilities has been setup");
+
+	return 0;
+}
+
 static int setup_hw_addr(char *hwaddr, const char *ifname)
 {
 	struct sockaddr sockaddr;
@@ -984,6 +1069,7 @@ struct lxc_conf *lxc_conf_init(void)
 	lxc_list_init(&new->cgroup);
 	lxc_list_init(&new->network);
 	lxc_list_init(&new->mount_list);
+	lxc_list_init(&new->caps);
 
 	return new;
 }
@@ -1287,6 +1373,11 @@ int lxc_setup(const char *name, struct l
 		return -1;
 	}
 
+	if (setup_caps(&lxc_conf->caps)) {
+		ERROR("failed to drop capabilities");
+		return -1;
+	}
+
 	NOTICE("'%s' is setup.", name);
 
 	return 0;
Index: lxc/src/lxc/conf.h
===================================================================
--- lxc.orig/src/lxc/conf.h
+++ lxc/src/lxc/conf.h
@@ -165,6 +165,7 @@ struct lxc_conf {
 	struct lxc_list cgroup;
 	struct lxc_list network;
 	struct lxc_list mount_list;
+	struct lxc_list caps;
 	struct lxc_tty_info tty_info;
 	char console[MAXPATHLEN];
 };
Index: lxc/src/lxc/confile.c
===================================================================
--- lxc.orig/src/lxc/confile.c
+++ lxc/src/lxc/confile.c
@@ -58,6 +58,7 @@ static int config_network_vlan_id(const
 static int config_network_mtu(const char *, char *, struct lxc_conf *);
 static int config_network_ipv4(const char *, char *, struct lxc_conf *);
 static int config_network_ipv6(const char *, char *, struct lxc_conf *);
+static int config_cap_drop(const char *, char *, struct lxc_conf *);
 
 typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
 
@@ -86,6 +87,7 @@ static struct config config[] = {
 	{ "lxc.network.vlan.id",      config_network_vlan_id      },
 	{ "lxc.network.ipv4",         config_network_ipv4         },
 	{ "lxc.network.ipv6",         config_network_ipv6         },
+	{ "lxc.cap.drop",             config_cap_drop             },
 };
 
 static const size_t config_size = sizeof(config)/sizeof(struct config);
@@ -565,6 +567,26 @@ static int config_mount(const char *key,
 
 	return 0;
 }
+
+static int config_cap_drop(const char *key, char *value, struct lxc_conf *lxc_conf)
+{
+	char *dropelem;
+	struct lxc_list *droplist;
+
+	if (!strlen(value))
+		return -1;
+
+	droplist = malloc(sizeof(*droplist));
+	if (!droplist)
+		return -1;
+
+	dropelem = strdup(value);
+	droplist->elem = dropelem;
+
+	lxc_list_add_tail(&lxc_conf->caps, droplist);
+
+	return 0;
+}
 
 static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf)
 {
Index: lxc/doc/lxc.conf.sgml.in
===================================================================
--- lxc.orig/doc/lxc.conf.sgml.in
+++ lxc/doc/lxc.conf.sgml.in
@@ -421,6 +421,33 @@ Foundation, Inc., 59 Temple Place, Suite
       </variablelist>
     </refsect2>
 
+    <refsect2>
+      <title>Capabilities</title>
+      <para>
+	The capabilities can be dropped in the container if this one
+	is run as root.
+      </para>
+      <variablelist>
+	<varlistentry>
+	  <term>
+	    <option>lxc.cap.drop</option>
+	  </term>
+	  <listitem>
+	    <para>
+	      Specify the capability to be dropped in the
+	      container. The format is the lower case of the
+	      capability definition with the "CAP_" prefix, eg. CAP_SYS_MODULE should be
+	      specified as sys_module. See
+	      <citerefentry>
+		<refentrytitle><command>capabilities</command></refentrytitle>
+		<manvolnum>7</manvolnum>
+	      </citerefentry>,
+	    </para>
+	  </listitem>
+	</varlistentry>
+      </variablelist>
+    </refsect2>
+
   </refsect1>
 
   <refsect1>



