From: Daniel Lezcano Date: Thu, 21 Jan 2010 13:48:42 +0000 (+0100) Subject: drop capabilities X-Git-Tag: lxc-0.6.5~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81810dd120291b78daf7c6833e6fcbca0289aad5;p=thirdparty%2Flxc.git drop capabilities 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 Signed-off-by: Daniel Lezcano Signed-off-by: Michael Holzt Signed-off-by: Daniel Lezcano --- diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in index 4258885f4..c0c8bb1b4 100644 --- a/doc/lxc.conf.sgml.in +++ b/doc/lxc.conf.sgml.in @@ -421,6 +421,36 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Capabilities + + The capabilities can be dropped in the container if this one + is run as root. + + + + + + + + + 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 + + capabilities + 7. A single line defining + several capabilities with a space separation is + allowed. + , + + + + + + @@ -639,6 +669,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA lxc.rootfs = /mnt/rootfs.complex + + lxc.cap.drop = sys_module mknod setuid net_raw + + + + lxc.cap.drop = mac_override + + diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 7fc8c1e34..c66048898 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -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; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index ec0badbfb..f152defbe 100644 --- a/src/lxc/conf.h +++ b/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]; }; diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 0e3ce54ea..6a22cc38c 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -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) {