From: Christian Brauner Date: Fri, 27 Mar 2020 19:11:41 +0000 (+0100) Subject: conf: introduce and use userns_exec_minimal() X-Git-Tag: lxc-5.0.0~488^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F3332%2Fhead;p=thirdparty%2Flxc.git conf: introduce and use userns_exec_minimal() Signed-off-by: Christian Brauner --- diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 42cef8831..8563ed7d2 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -2169,8 +2169,7 @@ int cgroup_attach(const struct lxc_conf *conf, const char *name, .pid = pid, }; - ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args, - "cgroup_unified_attach_wrapper"); + ret = userns_exec_minimal(conf, cgroup_unified_attach_wrapper, &args); } else { ret = cgroup_attach_leaf(conf, unified_fd, pid); } @@ -2224,8 +2223,7 @@ static int __cg_unified_attach(const struct hierarchy *h, .pid = pid, }; - ret = userns_exec_1(conf, cgroup_unified_attach_wrapper, &args, - "cgroup_unified_attach_wrapper"); + ret = userns_exec_minimal(conf, cgroup_unified_attach_wrapper, &args); } else { ret = cgroup_attach_leaf(conf, unified_fd, pid); } diff --git a/src/lxc/conf.c b/src/lxc/conf.c index edcc8cbf0..9e106b100 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -4120,6 +4120,110 @@ on_error: return ret; } +int userns_exec_minimal(const struct lxc_conf *conf, int (*fn)(void *), void *data) +{ + call_cleaner(lxc_free_idmap) struct lxc_list *idmap = NULL; + int ret = -1, status = -1; + ssize_t rret; + char c = '1'; + pid_t pid; + int sock_fds[2]; + + if (!conf) + return -EINVAL; + + idmap = get_minimal_idmap(conf); + if (!idmap) + return ret_errno(ENOENT); + + ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sock_fds); + if (ret < 0) + return -errno; + + pid = fork(); + if (pid < 0) { + ERROR("Failed to clone process in new user namespace"); + goto on_error; + } + + if (pid == 0) { + close_prot_errno_disarm(sock_fds[1]); + + ret = unshare(CLONE_NEWUSER); + if (ret < 0) + _exit(EXIT_FAILURE); + + rret = lxc_write_nointr(sock_fds[0], &c, 1); + if (rret != 1) + _exit(EXIT_FAILURE); + + ret = lxc_read_nointr(sock_fds[0], &c, 1); + if (ret != 1) + _exit(EXIT_FAILURE); + + close_prot_errno_disarm(sock_fds[0]); + + if (!lxc_setgroups(0, NULL) && errno != EPERM) + _exit(EXIT_FAILURE); + + if (!lxc_switch_uid_gid(0, 0)) + _exit(EXIT_FAILURE); + + ret = fn(data); + if (ret) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + close_prot_errno_disarm(sock_fds[0]); + + if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE || + conf->loglevel == LXC_LOG_LEVEL_TRACE) { + struct id_map *map; + struct lxc_list *it; + + lxc_list_for_each(it, idmap) { + map = it->elem; + TRACE("Establishing %cid mapping for \"%d\" in new user namespace: nsuid %lu - hostid %lu - range %lu", + (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid, map->nsid, map->hostid, map->range); + } + } + + ret = lxc_read_nointr(sock_fds[1], &c, 1); + if (ret != 1) { + SYSERROR("Failed waiting for child process %d\" to tell us to proceed", pid); + goto on_error; + } + + /* Set up {g,u}id mapping for user namespace of child process. */ + ret = lxc_map_ids(idmap, pid); + if (ret < 0) { + ERROR("Error setting up {g,u}id mappings for child process \"%d\"", pid); + goto on_error; + } + + /* Tell child to proceed. */ + ret = lxc_write_nointr(sock_fds[1], &c, 1); + if (ret != 1) { + SYSERROR("Failed telling child process \"%d\" to proceed", pid); + goto on_error; + } + +on_error: + close_prot_errno_disarm(sock_fds[0]); + close_prot_errno_disarm(sock_fds[1]); + + /* Wait for child to finish. */ + if (pid > 0) + status = wait_for_pid(pid); + + if (status < 0) + ret = -1; + + return ret; +} + int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, const char *fn_name) { diff --git a/src/lxc/conf.h b/src/lxc/conf.h index f37e09e4a..2bd2a203a 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -467,5 +467,6 @@ extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid); extern int lxc_clear_procs(struct lxc_conf *c, const char *key); extern int lxc_clear_apparmor_raw(struct lxc_conf *c); extern int lxc_clear_namespace(struct lxc_conf *c); +extern int userns_exec_minimal(const struct lxc_conf *conf, int (*fn)(void *), void *data); #endif /* __LXC_CONF_H */