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 <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>
This commit is contained in:
Daniel Lezcano 2010-01-21 14:48:42 +01:00
parent 7674618ce4
commit 81810dd120
4 changed files with 180 additions and 0 deletions

View File

@ -421,6 +421,36 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
</variablelist> </variablelist>
</refsect2> </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>
<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> <term>lxc.rootfs = /mnt/rootfs.complex</term>
<listitem><para></para></listitem> <listitem><para></para></listitem>
</varlistentry> </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> </variablelist>
</refsect2> </refsect2>

View File

@ -38,6 +38,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/capability.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <fcntl.h> #include <fcntl.h>
@ -75,6 +77,11 @@ struct mount_opt {
int flag; int flag;
}; };
struct caps_opt {
char *name;
int value;
};
static int instanciate_veth(struct lxc_netdev *); static int instanciate_veth(struct lxc_netdev *);
static int instanciate_macvlan(struct lxc_netdev *); static int instanciate_macvlan(struct lxc_netdev *);
static int instanciate_vlan(struct lxc_netdev *); static int instanciate_vlan(struct lxc_netdev *);
@ -113,6 +120,45 @@ static struct mount_opt mount_opt[] = {
{ NULL, 0, 0 }, { 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) static int configure_find_fstype_cb(char* buffer, void *data)
{ {
struct cbarg { struct cbarg {
@ -790,6 +836,46 @@ static int setup_mount_entries(struct lxc_list *mount)
return ret; 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) static int setup_hw_addr(char *hwaddr, const char *ifname)
{ {
struct sockaddr sockaddr; struct sockaddr sockaddr;
@ -981,6 +1067,7 @@ struct lxc_conf *lxc_conf_init(void)
lxc_list_init(&new->cgroup); lxc_list_init(&new->cgroup);
lxc_list_init(&new->network); lxc_list_init(&new->network);
lxc_list_init(&new->mount_list); lxc_list_init(&new->mount_list);
lxc_list_init(&new->caps);
return new; return new;
} }
@ -1284,6 +1371,11 @@ int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
return -1; return -1;
} }
if (setup_caps(&lxc_conf->caps)) {
ERROR("failed to drop capabilities");
return -1;
}
NOTICE("'%s' is setup.", name); NOTICE("'%s' is setup.", name);
return 0; return 0;

View File

@ -165,6 +165,7 @@ struct lxc_conf {
struct lxc_list cgroup; struct lxc_list cgroup;
struct lxc_list network; struct lxc_list network;
struct lxc_list mount_list; struct lxc_list mount_list;
struct lxc_list caps;
struct lxc_tty_info tty_info; struct lxc_tty_info tty_info;
char console[MAXPATHLEN]; char console[MAXPATHLEN];
}; };

View 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_mtu(const char *, char *, struct lxc_conf *);
static int config_network_ipv4(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_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 *); 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.vlan.id", config_network_vlan_id },
{ "lxc.network.ipv4", config_network_ipv4 }, { "lxc.network.ipv4", config_network_ipv4 },
{ "lxc.network.ipv6", config_network_ipv6 }, { "lxc.network.ipv6", config_network_ipv6 },
{ "lxc.cap.drop", config_cap_drop },
}; };
static const size_t config_size = sizeof(config)/sizeof(struct config); 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; 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) static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf)
{ {
if (strlen(value) >= MAXPATHLEN) { if (strlen(value) >= MAXPATHLEN) {