]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: introduce and use userns_exec_minimal() 3332/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 27 Mar 2020 19:11:41 +0000 (20:11 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Fri, 27 Mar 2020 19:11:41 +0000 (20:11 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/conf.c
src/lxc/conf.h

index 42cef8831a1561ce026c0d582bbc96b646e61b53..8563ed7d27091f86323768f6b036f35558b90580 100644 (file)
@@ -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);
        }
index edcc8cbf037e8a51aa7814b2adbee40fb1097631..9e106b100657dbd2aa3bdf2d64c1c3ab94126556 100644 (file)
@@ -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)
 {
index f37e09e4afe33f620babb6770abb4a202b657b0d..2bd2a203a6e13ebbac9f44ea1623ecdde29dba35 100644 (file)
@@ -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 */