conf: handle kernels with CAP_SETFCAP

LXC is being very clever and sometimes maps the caller's uid into the child userns. This means that the caller can technically write fscaps that are valid in the ancestor userns (which can be a security issue in some scenarios) so newer kernels require CAP_SETFCAP to do this. Until newuidmap/newgidmap are updated to account for this simply write the mapping directly in this case. Cc: stable-4.0 Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 37485abd
...@@ -2978,6 +2978,9 @@ static int lxc_map_ids_exec_wrapper(void *args) ...@@ -2978,6 +2978,9 @@ static int lxc_map_ids_exec_wrapper(void *args)
return -1; return -1;
} }
static struct id_map *find_mapped_hostid_entry(const struct lxc_list *idmap,
unsigned id, enum idtype idtype);
int lxc_map_ids(struct lxc_list *idmap, pid_t pid) int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
{ {
int fill, left; int fill, left;
...@@ -2991,12 +2994,22 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -2991,12 +2994,22 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
char mapbuf[STRLITERALLEN("new@idmap") + STRLITERALLEN(" ") + char mapbuf[STRLITERALLEN("new@idmap") + STRLITERALLEN(" ") +
INTTYPE_TO_STRLEN(pid_t) + STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(pid_t) + STRLITERALLEN(" ") +
LXC_IDMAPLEN] = {0}; LXC_IDMAPLEN] = {0};
bool had_entry = false, use_shadow = false; bool had_entry = false, maps_host_root = false, use_shadow = false;
int hostuid, hostgid; int hostuid, hostgid;
hostuid = geteuid(); hostuid = geteuid();
hostgid = getegid(); hostgid = getegid();
/*
* Check whether caller wants to map host root.
* Due to a security fix newer kernels require CAP_SETFCAP when mapping
* host root into the child userns as you would be able to write fscaps
* that would be valid in the ancestor userns. Mapping host root should
* rarely be the case but LXC is being clever in a bunch of cases.
*/
if (find_mapped_hostid_entry(idmap, 0, ID_TYPE_UID))
maps_host_root = true;
/* If new{g,u}idmap exists, that is, if shadow is handing out subuid /* If new{g,u}idmap exists, that is, if shadow is handing out subuid
* ranges, then insist that root also reserve ranges in subuid. This * ranges, then insist that root also reserve ranges in subuid. This
* will protected it by preventing another user from being handed the * will protected it by preventing another user from being handed the
...@@ -3014,7 +3027,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -3014,7 +3027,9 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
else if (!gidmap) else if (!gidmap)
WARN("newgidmap is lacking necessary privileges"); WARN("newgidmap is lacking necessary privileges");
if (uidmap > 0 && gidmap > 0) { if (maps_host_root) {
INFO("Caller maps host root. Writing mapping directly");
} else if (uidmap > 0 && gidmap > 0) {
DEBUG("Functional newuidmap and newgidmap binary found"); DEBUG("Functional newuidmap and newgidmap binary found");
use_shadow = true; use_shadow = true;
} else { } else {
...@@ -4229,14 +4244,14 @@ static struct id_map *mapped_nsid_add(const struct lxc_conf *conf, unsigned id, ...@@ -4229,14 +4244,14 @@ static struct id_map *mapped_nsid_add(const struct lxc_conf *conf, unsigned id,
return retmap; return retmap;
} }
static struct id_map *find_mapped_hostid_entry(const struct lxc_conf *conf, static struct id_map *find_mapped_hostid_entry(const struct lxc_list *idmap,
unsigned id, enum idtype idtype) unsigned id, enum idtype idtype)
{ {
struct id_map *map; struct id_map *map;
struct lxc_list *it; struct lxc_list *it;
struct id_map *retmap = NULL; struct id_map *retmap = NULL;
lxc_list_for_each (it, &conf->id_map) { lxc_list_for_each (it, idmap) {
map = it->elem; map = it->elem;
if (map->idtype != idtype) if (map->idtype != idtype)
continue; continue;
...@@ -4265,7 +4280,7 @@ static struct id_map *mapped_hostid_add(const struct lxc_conf *conf, uid_t id, ...@@ -4265,7 +4280,7 @@ static struct id_map *mapped_hostid_add(const struct lxc_conf *conf, uid_t id,
return NULL; return NULL;
/* Reuse existing mapping. */ /* Reuse existing mapping. */
tmp = find_mapped_hostid_entry(conf, id, type); tmp = find_mapped_hostid_entry(&conf->id_map, id, type);
if (tmp) { if (tmp) {
memcpy(entry, tmp, sizeof(*entry)); memcpy(entry, tmp, sizeof(*entry));
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment