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) &&
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;
}
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)) {
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));