Skip to content

Commit

Permalink
conf: check for {filecaps,setuid} on new{g,u}idmap
Browse files Browse the repository at this point in the history
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 <christian.brauner@ubuntu.com>
  • Loading branch information
Christian Brauner authored and stgraber committed Apr 17, 2017
1 parent abeded9 commit 25743d0
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 15 deletions.
85 changes: 72 additions & 13 deletions src/lxc/conf.c
Expand Up @@ -3223,30 +3223,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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/lxc/utils.c
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/lxc/utils.h
Expand Up @@ -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);
Expand Down

0 comments on commit 25743d0

Please sign in to comment.