diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 0ce6491..e6863d6 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -7,6 +7,7 @@ pkginclude_HEADERS = \ lock.h \ lxc.h \ cgroup.h \ + capability.h \ conf.h \ list.h \ log.h \ @@ -31,6 +32,7 @@ liblxc_so_SOURCES = \ error.h error.c \ parse.c parse.h \ cgroup.c cgroup.h \ + capability.c capability.h \ lxc.h \ utils.c utils.h \ lock.c lock.h \ @@ -59,7 +61,7 @@ liblxc_so_LDFLAGS = \ -shared \ -Wl,-soname,liblxc.so.$(firstword $(subst ., ,$(VERSION))) -liblxc_so_LDADD = -lutil +liblxc_so_LDADD = -lutil -lcap bin_SCRIPTS = \ lxc-ps \ diff --git a/src/lxc/capability.c b/src/lxc/capability.c new file mode 100644 index 0000000..0d24ca8 --- /dev/null +++ b/src/lxc/capability.c @@ -0,0 +1,162 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * File by: + * Andrian Nord + * + * 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 + */ + +#undef _GNU_SOURCE +#include +#include +#include + +#include +#include + +#if !HAVE_DECL_PR_CAPBSET_DROP +#define PR_CAPBSET_DROP 24 +#endif + +lxc_log_define(lxc_capability, lxc); + +struct capability { + char *name; + lxc_cap_t code; + lxc_cap_state initial_state; +}; + +static struct capability capabilities[] = { + { "chown", CAP_CHOWN, LXC_CAP_ON }, + + { "dac_override", CAP_DAC_OVERRIDE, LXC_CAP_ON }, + { "dac_read_search", CAP_DAC_READ_SEARCH, LXC_CAP_ON }, + + { "fowner", CAP_FOWNER, LXC_CAP_ON }, + { "fsetid", CAP_FSETID, LXC_CAP_ON }, + + { "kill", CAP_KILL, LXC_CAP_ON }, + + { "setgid", CAP_SETGID, LXC_CAP_ON }, + { "setuid", CAP_SETUID, LXC_CAP_ON }, + + { "setpcap", CAP_SETPCAP, LXC_CAP_ON }, + { "linux_immutable", CAP_LINUX_IMMUTABLE, LXC_CAP_ON }, + + { "net_bind_service", CAP_NET_BIND_SERVICE, LXC_CAP_ON }, + { "net_broadcast", CAP_NET_BROADCAST, LXC_CAP_ON }, + { "net_admin", CAP_NET_ADMIN, LXC_CAP_OFF }, + { "net_raw", CAP_NET_RAW, LXC_CAP_ON }, + + { "ipc_lock", CAP_IPC_LOCK, LXC_CAP_ON }, + { "ipc_owner", CAP_IPC_OWNER, LXC_CAP_ON }, + + { "sys_module", CAP_SYS_MODULE, LXC_CAP_OFF }, + + { "sys_rawio", CAP_SYS_RAWIO, LXC_CAP_OFF }, + + { "sys_chroot", CAP_SYS_CHROOT, LXC_CAP_ON }, + + { "sys_ptrace", CAP_SYS_PTRACE, LXC_CAP_ON }, + { "sys_pacct", CAP_SYS_PACCT, LXC_CAP_OFF }, + + { "sys_admin", CAP_SYS_ADMIN, LXC_CAP_ON }, + { "sys_boot", CAP_SYS_BOOT, LXC_CAP_OFF }, + { "sys_nice", CAP_SYS_NICE, LXC_CAP_ON }, + { "sys_resource", CAP_SYS_RESOURCE, LXC_CAP_ON }, + { "sys_time", CAP_SYS_TIME, LXC_CAP_OFF }, + + { "sys_tty_config", CAP_SYS_TTY_CONFIG, LXC_CAP_ON }, + { "mknod", CAP_MKNOD, LXC_CAP_ON }, + { "lease", CAP_LEASE, LXC_CAP_ON }, + + { "audit_write", CAP_AUDIT_WRITE, LXC_CAP_OFF }, + { "audit_control", CAP_AUDIT_CONTROL, LXC_CAP_OFF }, + + { "setfcap", CAP_SETFCAP, LXC_CAP_OFF }, + { "mac_override", CAP_MAC_OVERRIDE, LXC_CAP_OFF }, + { "mac_admin", CAP_MAC_ADMIN, LXC_CAP_OFF } +}; + +static const size_t cap_count = sizeof(capabilities)/sizeof(struct capability); + +static struct capability *find_name( const char *cap_name ) { + int i; + + for ( i = 0; i < cap_count; i++ ) { + if ( !strncmp( capabilities[i].name, cap_name, + strlen(cap_name) ) ) + return &capabilities[i]; + } + + return NULL; +} + +lxc_cap_t lxc_init_cap( void ) { + int i; + lxc_cap_t initial_state = 0; + + for ( i = 0; i < cap_count; i++ ) { + if( capabilities[i].initial_state == LXC_CAP_ON ) + initial_state |= CAP_TO_MASK(capabilities[i].code); + } + + return initial_state; +} + +int lxc_mod_cap( lxc_cap_t *mask, const char *cap_name, lxc_cap_state state ) { + struct capability *cap_spec; + + cap_spec = find_name( cap_name ); + + if ( !cap_spec ) { + ERROR( "capability '%s' not found", cap_name ); + return -1; + } + + if ( state == LXC_CAP_OFF ) + *mask &= ~CAP_TO_MASK(cap_spec->code); + else if ( state == LXC_CAP_ON ) + *mask |= CAP_TO_MASK(cap_spec->code); + + return 0; +} + +int lxc_apply_cap( lxc_cap_t mask ) { + int i; + struct capability *cur_cap; + + for ( i = 0; i < cap_count; i++ ) { + cur_cap = &capabilities[i]; + + if ( lxc_cap_check( mask, cur_cap->code ) ) + continue; + + DEBUG( "Dropping capability '%s'", cur_cap->name ); + + if ( !prctl(PR_CAPBSET_DROP, cur_cap->code, 0, 0, 0) ) + continue; + + SYSERROR( "Failed to remove '%s' capability", cur_cap->name ); + return -1; + } + + return 0; +} diff --git a/src/lxc/capability.h b/src/lxc/capability.h new file mode 100644 index 0000000..99bde5a --- /dev/null +++ b/src/lxc/capability.h @@ -0,0 +1,45 @@ +/* + * lxc: linux Container library + * + * (C) Copyright IBM Corp. 2007, 2008 + * + * Authors: + * Daniel Lezcano + * File by: + * Andrian Nord + * + * 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 _capability_h +#define _capability_h + +#include + +#define lxc_cap_check( mask, code ) ( mask & CAP_TO_MASK(code) ) + +typedef __u32 lxc_cap_t; + +typedef enum { + LXC_CAP_OFF = 0, + LXC_CAP_ON = 1 +} lxc_cap_state; + +lxc_cap_t lxc_init_cap( void ); + +int lxc_mod_cap( lxc_cap_t *mask, const char *cap_name, lxc_cap_state state ); + +int lxc_apply_cap( lxc_cap_t mask ); + +#endif diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 69cf8e6..0046e75 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -893,6 +893,11 @@ static int setup_network(struct lxc_list *network) return 0; } +static int setup_capabilities( lxc_cap_t capabilities ) +{ + return lxc_apply_cap( capabilities ); +} + int conf_has(const char *name, const char *info) { int ret = 0; @@ -923,6 +928,7 @@ int lxc_conf_init(struct lxc_conf *conf) conf->utsname = NULL; conf->tty = 0; conf->pts = 0; + conf->capabilities = lxc_init_cap(); conf->console[0] = '\0'; lxc_list_init(&conf->cgroup); lxc_list_init(&conf->network); @@ -1225,6 +1231,11 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf) return -1; } + if (setup_capabilities(lxc_conf->capabilities)) { + ERROR("failed to set capabilities"); + return -1; + } + NOTICE("'%s' is setup.", name); return 0; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index c6e0496..4a4f057 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -133,6 +133,7 @@ struct lxc_conf { char *fstab; int tty; int pts; + lxc_cap_t capabilities; struct utsname *utsname; struct lxc_list cgroup; struct lxc_list network; diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 900ecc3..c217e19 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -42,6 +42,7 @@ lxc_log_define(lxc_confile, lxc); static int config_pts(const char *, char *, struct lxc_conf *); static int config_tty(const char *, char *, struct lxc_conf *); static int config_cgroup(const char *, char *, struct lxc_conf *); +static int config_capability(const char *, char *, struct lxc_conf *); static int config_mount(const char *, char *, struct lxc_conf *); static int config_rootfs(const char *, char *, struct lxc_conf *); static int config_utsname(const char *, char *, struct lxc_conf *); @@ -66,6 +67,7 @@ static struct config config[] = { { "lxc.pts", config_pts }, { "lxc.tty", config_tty }, { "lxc.cgroup", config_cgroup }, + { "lxc.capability", config_capability }, { "lxc.mount", config_mount }, { "lxc.rootfs", config_rootfs }, { "lxc.utsname", config_utsname }, @@ -441,6 +443,38 @@ static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf return 0; } +static int config_capability(const char *key, char *value, struct lxc_conf *lxc_conf) +{ + char *prekey = "lxc.capability."; + char *subkey; + + subkey = strstr(key, prekey); + + if (!subkey) + return -1; + + if (!strlen(subkey)) + return -1; + + if (strlen(subkey) == strlen(prekey)) + return -1; + + subkey += strlen(prekey); + + lxc_cap_state state; + + if ( strcmp(value, "on") == 0 ) + state = LXC_CAP_ON; + else if ( strcmp(value, "off") == 0 ) + state = LXC_CAP_OFF; + else { + ERROR("Bad value for '%s', should be 'on' or 'off'", key); + return -1; + } + + return lxc_mod_cap( &lxc_conf->capabilities, subkey, state ); +} + static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf) { if (strlen(value) >= MAXPATHLEN) { diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h index 327a90b..bf00839 100644 --- a/src/lxc/lxc.h +++ b/src/lxc/lxc.h @@ -36,6 +36,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/src/lxc/start.c b/src/lxc/start.c index 5759024..95e57fe 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -380,11 +379,6 @@ static int do_start(void *arg) goto out_warn_father; } - if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) { - SYSERROR("failed to remove CAP_SYS_BOOT capability"); - goto out_child; - } - if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { SYSERROR("failed to set pdeath signal"); goto out_child;