attach: improve id switching

parent 8c238670
...@@ -726,6 +726,8 @@ static int attach_child_main(struct attach_clone_payload *payload) ...@@ -726,6 +726,8 @@ static int attach_child_main(struct attach_clone_payload *payload)
int fd, lsm_fd, ret; int fd, lsm_fd, ret;
uid_t new_uid; uid_t new_uid;
gid_t new_gid; gid_t new_gid;
uid_t ns_root_uid = 0;
gid_t ns_root_gid = 0;
lxc_attach_options_t* options = payload->options; lxc_attach_options_t* options = payload->options;
struct lxc_proc_context_info* init_ctx = payload->init_ctx; struct lxc_proc_context_info* init_ctx = payload->init_ctx;
bool needs_lsm = (options->namespaces & CLONE_NEWNS) && bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
...@@ -809,25 +811,40 @@ static int attach_child_main(struct attach_clone_payload *payload) ...@@ -809,25 +811,40 @@ static int attach_child_main(struct attach_clone_payload *payload)
/* Ignore errors, we will fall back to root in that case (/proc was not /* Ignore errors, we will fall back to root in that case (/proc was not
* mounted etc.). * mounted etc.).
*/ */
if (options->namespaces & CLONE_NEWUSER) if (options->namespaces & CLONE_NEWUSER) {
lxc_attach_get_init_uidgid(&new_uid, &new_gid); /* Check whether nsuid 0 has a mapping. */
ns_root_uid = get_ns_uid(0);
if (options->uid != (uid_t)-1) /* Check whether nsgid 0 has a mapping. */
new_uid = options->uid; ns_root_gid = get_ns_gid(0);
if (options->gid != (gid_t)-1)
new_gid = options->gid;
/* Try to set the {u,g}id combination. */ /* If there's no mapping for nsuid 0 try to retrieve the nsuid
if (new_uid != 0 || new_gid != 0 || options->namespaces & CLONE_NEWUSER) { * init was started with.
ret = lxc_switch_uid_gid(new_uid, new_gid); */
if (ret < 0) if (ns_root_uid == LXC_INVALID_UID)
lxc_attach_get_init_uidgid(&ns_root_uid, &ns_root_gid);
if (ns_root_uid == LXC_INVALID_UID)
goto on_error; goto on_error;
ret = lxc_setgroups(0, NULL); if (!lxc_switch_uid_gid(ns_root_uid, ns_root_gid))
if (ret < 0)
goto on_error; goto on_error;
} }
if (!lxc_setgroups(0, NULL) && errno != EPERM)
goto on_error;
/* Set {u,g}id. */
if (options->uid != LXC_INVALID_UID)
new_uid = options->uid;
else
new_uid = ns_root_uid;
if (options->gid != LXC_INVALID_GID)
new_gid = options->gid;
else
new_gid = ns_root_gid;
if (needs_lsm) { if (needs_lsm) {
bool on_exec; bool on_exec;
...@@ -909,6 +926,16 @@ static int attach_child_main(struct attach_clone_payload *payload) ...@@ -909,6 +926,16 @@ static int attach_child_main(struct attach_clone_payload *payload)
TRACE("Prepared pty file descriptor %d", payload->pty_fd); TRACE("Prepared pty file descriptor %d", payload->pty_fd);
} }
/* Avoid unnecessary syscalls. */
if (new_uid == ns_root_uid)
new_uid = LXC_INVALID_UID;
if (new_gid == ns_root_gid)
new_gid = LXC_INVALID_GID;
if (!lxc_switch_uid_gid(new_uid, new_gid))
goto on_error;
/* We're done, so we can now do whatever the user intended us to do. */ /* We're done, so we can now do whatever the user intended us to do. */
rexit(payload->exec_function(payload->exec_payload)); rexit(payload->exec_function(payload->exec_payload));
......
...@@ -1001,17 +1001,18 @@ void **lxc_append_null_to_array(void **array, size_t count) ...@@ -1001,17 +1001,18 @@ void **lxc_append_null_to_array(void **array, size_t count)
int randseed(bool srand_it) int randseed(bool srand_it)
{ {
FILE *f;
/* /*
srand pre-seed function based on /dev/urandom * srand pre-seed function based on /dev/urandom
*/ */
unsigned int seed = time(NULL) + getpid(); unsigned int seed = time(NULL) + getpid();
FILE *f;
f = fopen("/dev/urandom", "r"); f = fopen("/dev/urandom", "r");
if (f) { if (f) {
int ret = fread(&seed, sizeof(seed), 1, f); int ret = fread(&seed, sizeof(seed), 1, f);
if (ret != 1) if (ret != 1)
DEBUG("unable to fread /dev/urandom, %s, fallback to time+pid rand seed", strerror(errno)); SYSDEBUG("Unable to fread /dev/urandom, fallback to time+pid rand seed");
fclose(f); fclose(f);
} }
...@@ -1026,26 +1027,62 @@ uid_t get_ns_uid(uid_t orig) ...@@ -1026,26 +1027,62 @@ uid_t get_ns_uid(uid_t orig)
char *line = NULL; char *line = NULL;
size_t sz = 0; size_t sz = 0;
uid_t nsid, hostid, range; uid_t nsid, hostid, range;
FILE *f = fopen("/proc/self/uid_map", "r"); FILE *f;
if (!f)
f = fopen("/proc/self/uid_map", "r");
if (!f) {
SYSERROR("Failed to open uid_map");
return 0; return 0;
}
while (getline(&line, &sz, f) != -1) { while (getline(&line, &sz, f) != -1) {
if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3) if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
continue; continue;
if (hostid <= orig && hostid + range > orig) { if (hostid <= orig && hostid + range > orig) {
nsid += orig - hostid; nsid += orig - hostid;
goto found; goto found;
} }
} }
nsid = 0; nsid = LXC_INVALID_UID;
found: found:
fclose(f); fclose(f);
free(line); free(line);
return nsid; return nsid;
} }
gid_t get_ns_gid(gid_t orig)
{
char *line = NULL;
size_t sz = 0;
gid_t nsid, hostid, range;
FILE *f;
f = fopen("/proc/self/gid_map", "r");
if (!f) {
SYSERROR("Failed to open gid_map");
return 0;
}
while (getline(&line, &sz, f) != -1) {
if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
continue;
if (hostid <= orig && hostid + range > orig) {
nsid += orig - hostid;
goto found;
}
}
nsid = LXC_INVALID_GID;
found:
fclose(f);
free(line);
return nsid;
}
bool dir_exists(const char *path) bool dir_exists(const char *path)
{ {
struct stat sb; struct stat sb;
......
...@@ -415,6 +415,7 @@ inline static bool am_host_unpriv(void) ...@@ -415,6 +415,7 @@ inline static bool am_host_unpriv(void)
* parse /proc/self/uid_map to find what @orig maps to * parse /proc/self/uid_map to find what @orig maps to
*/ */
extern uid_t get_ns_uid(uid_t orig); extern uid_t get_ns_uid(uid_t orig);
extern gid_t get_ns_gid(gid_t orig);
extern bool dir_exists(const char *path); extern bool dir_exists(const char *path);
......
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