diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 87f14398f5..8387bbfe17 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -749,6 +749,8 @@ static int attach_child_main(struct attach_clone_payload *payload) int fd, lsm_fd, ret; uid_t new_uid; gid_t new_gid; + uid_t ns_root_uid = 0; + gid_t ns_root_gid = 0; lxc_attach_options_t* options = payload->options; struct lxc_proc_context_info* init_ctx = payload->init_ctx; bool needs_lsm = (options->namespaces & CLONE_NEWNS) && @@ -836,25 +838,23 @@ static int attach_child_main(struct attach_clone_payload *payload) goto on_error; } - /* Set {u,g}id. */ - new_uid = 0; - new_gid = 0; + if (options->namespaces & CLONE_NEWUSER) { + /* Check whether nsuid 0 has a mapping. */ + ns_root_uid = get_ns_uid(0); - /* Ignore errors, we will fall back to root in that case (/proc was not - * mounted etc.). - */ - if (options->namespaces & CLONE_NEWUSER) - lxc_attach_get_init_uidgid(&new_uid, &new_gid); + /* Check whether nsgid 0 has a mapping. */ + ns_root_gid = get_ns_gid(0); - if (options->uid != (uid_t)-1) - new_uid = options->uid; + /* If there's no mapping for nsuid 0 try to retrieve the nsuid + * init was started with. + */ + if (ns_root_uid == LXC_INVALID_UID) + lxc_attach_get_init_uidgid(&ns_root_uid, &ns_root_gid); - if (options->gid != (gid_t)-1) - new_gid = options->gid; + if (ns_root_uid == LXC_INVALID_UID) + goto on_error; - /* Try to set the {u,g}id combination. */ - if (new_uid != 0 || new_gid != 0 || options->namespaces & CLONE_NEWUSER) { - ret = lxc_switch_uid_gid(new_uid, new_gid); + ret = lxc_switch_uid_gid(ns_root_uid, ns_root_gid); if (ret < 0) goto on_error; } @@ -863,6 +863,17 @@ static int attach_child_main(struct attach_clone_payload *payload) if (ret < 0 && 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 ((init_ctx->container && init_ctx->container->lxc_conf && init_ctx->container->lxc_conf->no_new_privs) || (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) { @@ -952,6 +963,17 @@ static int attach_child_main(struct attach_clone_payload *payload) TRACE("Prepared terminal file descriptor %d", payload->terminal_slave_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; + + ret = lxc_switch_uid_gid(new_uid, new_gid); + if (ret < 0) + goto on_error; + /* We're done, so we can now do whatever the user intended us to do. */ _exit(payload->exec_function(payload->exec_payload));