From: Christian Brauner Date: Sat, 15 Apr 2017 11:50:27 +0000 (+0200) Subject: conf: check for {filecaps,setuid} on new{g,u}idmap X-Git-Tag: lxc-2.1.0~159^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=df6a2945484ed626168c43f95059923c2d4c88ab;p=thirdparty%2Flxc.git conf: check for {filecaps,setuid} on new{g,u}idmap The new{g,u}idmap binaries where a source of trouble for users when they lacked sufficient privileges. This commit adds code to check for sufficient privilege. It checks whether new{g,u}idmap is root owned and has the setuid bit set and if it doesn't it checks whether new{g,u}idmap is root owned and has CAP_SETUID in its CAP_PERMITTED and CAP_EFFECTIVE set. Closes #296. Signed-off-by: Christian Brauner --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index afae3ca5d..2bc209802 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3319,30 +3319,89 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, return ret < 0 ? ret : closeret; } +/* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both. */ +static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap) +{ + char *path; + int ret; + struct stat st; + int fret = 0; + + path = on_path(binary, NULL); + if (!path) + return -ENOENT; + + ret = stat(path, &st); + if (ret < 0) { + fret = -errno; + goto cleanup; + } + + /* Check if the binary is setuid. */ + if (st.st_mode & S_ISUID) { + DEBUG("The binary \"%s\" does have the setuid bit set.", path); + fret = 1; + goto cleanup; + } + + #if HAVE_LIBCAP + /* Check if it has the CAP_SETUID capability. */ + if ((cap & CAP_SETUID) && + lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) && + lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) { + DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE " + "and CAP_PERMITTED sets.", path); + fret = 1; + goto cleanup; + } + + /* Check if it has the CAP_SETGID capability. */ + if ((cap & CAP_SETGID) && + lxc_file_cap_is_set(path, CAP_SETGID, CAP_EFFECTIVE) && + lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) { + DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE " + "and CAP_PERMITTED sets.", path); + fret = 1; + goto cleanup; + } + #endif + +cleanup: + free(path); + return fret; +} + int lxc_map_ids(struct lxc_list *idmap, pid_t pid) { struct id_map *map; struct lxc_list *iterator; enum idtype type; char *pos; - char *buf = NULL, *cmdpath = NULL; - bool use_shadow = false; - int ret = 0; + int euid; + int ret = 0, use_shadow = 0; + int uidmap = 0, gidmap = 0; + char *buf = NULL; - /* - * If newuidmap exists, that is, if shadow is handing out subuid - * ranges, then insist that root also reserve ranges in subuid. This + euid = geteuid(); + + /* 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 * will protected it by preventing another user from being handed the * range by shadow. */ - cmdpath = on_path("newuidmap", NULL); - if (cmdpath) { + uidmap = idmaptool_on_path_and_privileged("newuidmap", CAP_SETUID); + gidmap = idmaptool_on_path_and_privileged("newgidmap", CAP_SETGID); + if (uidmap > 0 && gidmap > 0) { + DEBUG("Functional newuidmap and newgidmap binary found."); use_shadow = true; - free(cmdpath); - } - - if (!use_shadow && geteuid()) { - ERROR("Missing newuidmap/newgidmap"); + } else if (uidmap == -ENOENT && gidmap == -ENOENT && !euid) { + DEBUG("No newuidmap and newgidmap binary found. Trying to " + "write directly with euid 0."); + use_shadow = false; + } else { + DEBUG("Either one or both of the newuidmap and newgidmap " + "binaries do not exist or are missing necessary " + "privilege."); return -1; } diff --git a/src/lxc/utils.c b/src/lxc/utils.c index fbdc13b97..1154d415a 100644 --- a/src/lxc/utils.c +++ b/src/lxc/utils.c @@ -1199,7 +1199,7 @@ bool detect_ramfs_rootfs(void) return false; } -char *on_path(char *cmd, const char *rootfs) { +char *on_path(const char *cmd, const char *rootfs) { char *path = NULL; char *entry = NULL; char *saveptr = NULL; diff --git a/src/lxc/utils.h b/src/lxc/utils.h index d1966ff75..19caa6dad 100644 --- a/src/lxc/utils.h +++ b/src/lxc/utils.h @@ -302,7 +302,7 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); int detect_shared_rootfs(void); bool detect_ramfs_rootfs(void); -char *on_path(char *cmd, const char *rootfs); +char *on_path(const char *cmd, const char *rootfs); bool file_exists(const char *f); bool cgns_supported(void); char *choose_init(const char *rootfs);