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: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 207c4c71
...@@ -3319,30 +3319,89 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, ...@@ -3319,30 +3319,89 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
return ret < 0 ? ret : closeret; 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) int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
{ {
struct id_map *map; struct id_map *map;
struct lxc_list *iterator; struct lxc_list *iterator;
enum idtype type; enum idtype type;
char *pos; char *pos;
char *buf = NULL, *cmdpath = NULL; int euid;
bool use_shadow = false; int ret = 0, use_shadow = 0;
int ret = 0; int uidmap = 0, gidmap = 0;
char *buf = NULL;
/* euid = geteuid();
* If newuidmap exists, that is, if shadow is handing out subuid
* ranges, then insist that root also reserve ranges in subuid. This /* 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 * will protected it by preventing another user from being handed the
* range by shadow. * range by shadow.
*/ */
cmdpath = on_path("newuidmap", NULL); uidmap = idmaptool_on_path_and_privileged("newuidmap", CAP_SETUID);
if (cmdpath) { gidmap = idmaptool_on_path_and_privileged("newgidmap", CAP_SETGID);
if (uidmap > 0 && gidmap > 0) {
DEBUG("Functional newuidmap and newgidmap binary found.");
use_shadow = true; use_shadow = true;
free(cmdpath); } else if (uidmap == -ENOENT && gidmap == -ENOENT && !euid) {
} DEBUG("No newuidmap and newgidmap binary found. Trying to "
"write directly with euid 0.");
if (!use_shadow && geteuid()) { use_shadow = false;
ERROR("Missing newuidmap/newgidmap"); } else {
DEBUG("Either one or both of the newuidmap and newgidmap "
"binaries do not exist or are missing necessary "
"privilege.");
return -1; return -1;
} }
......
...@@ -1199,7 +1199,7 @@ bool detect_ramfs_rootfs(void) ...@@ -1199,7 +1199,7 @@ bool detect_ramfs_rootfs(void)
return false; return false;
} }
char *on_path(char *cmd, const char *rootfs) { char *on_path(const char *cmd, const char *rootfs) {
char *path = NULL; char *path = NULL;
char *entry = NULL; char *entry = NULL;
char *saveptr = NULL; char *saveptr = NULL;
......
...@@ -302,7 +302,7 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval); ...@@ -302,7 +302,7 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
int detect_shared_rootfs(void); int detect_shared_rootfs(void);
bool detect_ramfs_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 file_exists(const char *f);
bool cgns_supported(void); bool cgns_supported(void);
char *choose_init(const char *rootfs); char *choose_init(const char *rootfs);
......
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