]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
drop capabilities
authorDaniel Lezcano <dlezcano@fr.ibm.com>
Thu, 21 Jan 2010 13:48:42 +0000 (14:48 +0100)
committerDaniel Lezcano <dlezcano@fr.ibm.com>
Thu, 21 Jan 2010 14:06:42 +0000 (15:06 +0100)
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

or specify in a single line:

lxc.cap.drop = sys_chroot mknod sys_module

Reworked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Michael Holzt <lxc@my.fqdn.org>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
doc/lxc.conf.sgml.in
src/lxc/conf.c
src/lxc/conf.h
src/lxc/confile.c

index 4258885f44170a8d2a5f5e004e239f45fcab6b1e..c0c8bb1b4b510fc29fada02bcaacbdba4ea8b038 100644 (file)
@@ -421,6 +421,36 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
       </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 without the "CAP_" prefix,
+             eg. CAP_SYS_MODULE should be specified as
+             sys_module. See
+             <citerefentry>
+               <refentrytitle><command>capabilities</command></refentrytitle>
+               <manvolnum>7</manvolnum>. A single line defining
+               several capabilities with a space separation is
+               allowed.
+             </citerefentry>,
+           </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </refsect2>
+
   </refsect1>
 
   <refsect1>
@@ -639,6 +669,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
          <term>lxc.rootfs = /mnt/rootfs.complex</term>
          <listitem><para></para></listitem>
        </varlistentry>
+       <varlistentry>
+         <term>lxc.cap.drop = sys_module mknod setuid net_raw</term>
+         <listitem><para></para></listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>lxc.cap.drop = mac_override</term>
+         <listitem><para></para></listitem>
+       </varlistentry>
       </variablelist>
     </refsect2>
 
index 7fc8c1e34497faf88e6c18301c1ed2b68692f60c..c660488987ddb75c914ee02eb59766a04d6f5f76 100644 (file)
@@ -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 {
@@ -790,6 +836,46 @@ static int setup_mount_entries(struct lxc_list *mount)
        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;
@@ -981,6 +1067,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;
 }
@@ -1284,6 +1371,11 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
                return -1;
        }
 
+       if (setup_caps(&lxc_conf->caps)) {
+               ERROR("failed to drop capabilities");
+               return -1;
+       }
+
        NOTICE("'%s' is setup.", name);
 
        return 0;
index ec0badbfb462af0975ff76757b658fd5fb504486..f152defbe16597a39b48385dd650e537366c0670 100644 (file)
@@ -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 0e3ce54ea2a964331a95d89816d88dc18eb4e76a..6a22cc38c3bf658c4bcdfbb6a95c763a8d486f4d 100644 (file)
@@ -58,6 +58,7 @@ static int config_network_vlan_id(const char *, char *, struct lxc_conf *);
 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);
@@ -566,6 +568,53 @@ static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf)
        return 0;
 }
 
+static int config_cap_drop(const char *key, char *value,
+                          struct lxc_conf *lxc_conf)
+{
+       char *dropcaps, *caps, *sptr, *token;
+       struct lxc_list *droplist;
+       int ret = -1;
+
+       if (!strlen(value))
+               return -1;
+
+       dropcaps = strdup(value);
+       if (!dropcaps) {
+               SYSERROR("failed to dup '%s'", value);
+               return -1;
+       }
+
+       /* in case several capability drop is specified in a single line
+        * split these caps in a single element for the list */
+       for (;;) {
+                token = strtok_r(dropcaps, " \t", &sptr);
+                if (!token) {
+                       ret = 0;
+                        break;
+               }
+               dropcaps = NULL;
+
+               droplist = malloc(sizeof(*droplist));
+               if (!droplist) {
+                       SYSERROR("failed to allocate drop list");
+                       break;
+               }
+
+               droplist->elem = strdup(token);
+               if (!droplist->elem) {
+                       SYSERROR("failed to dup '%s'", token);
+                       free(droplist);
+                       break;
+               }
+
+               lxc_list_add_tail(&lxc_conf->caps, droplist);
+        }
+
+       free(dropcaps);
+
+       return ret;
+}
+
 static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf)
 {
        if (strlen(value) >= MAXPATHLEN) {