]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
start: rework namespace preservation and path creation for hooks
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 14 Feb 2021 13:03:07 +0000 (14:03 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 14 Feb 2021 14:42:10 +0000 (15:42 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/macro.h
src/lxc/namespace.h
src/lxc/start.c
src/lxc/start.h

index fac4983ee095b9f2ad8f7b9f48eb7a1b5d7d9eef..9e74078f4ef7033a6ee2a465cb3fc963b363e4a9 100644 (file)
  */
 #define LXC_LSMATTRLEN (6 + INTTYPE_TO_STRLEN(pid_t) + 6 + 8 + 1)
 
+/* MAX_NS_PROC_NAME = MAX_NS_PROC_NAME
+ *                  +
+ * :                = 1
+ *                  +
+ * /proc/           = 6
+ *                  +
+ * <pid-as_str>     = INTTYPE_TO_STRLEN(pid_t)
+ *                  +
+ * /fd/             = 4
+ *                  +
+ * <int-as-str>     = INTTYPE_TO_STRLEN(int)
+ *                  +
+ * \0               = 1
+ */
+#define LXC_EXPOSE_NAMESPACE_LEN                                   \
+       (MAX_NS_PROC_NAME + 1 + 6 + INTTYPE_TO_STRLEN(pid_t) + 4 + \
+        INTTYPE_TO_STRLEN(int) + 1)
+
 #define LXC_CMD_DATA_MAX (PATH_MAX * 2)
 
 /* loop devices */
index 6dd83be14f25937da522fd90e6bf1133f256f39f..adb8619a3bf791ee7edea64816e18f33bd198bb6 100644 (file)
@@ -9,20 +9,21 @@
 
 #include "compiler.h"
 
-enum {
-       LXC_NS_USER,
-       LXC_NS_MNT,
-       LXC_NS_PID,
-       LXC_NS_UTS,
-       LXC_NS_IPC,
-       LXC_NS_NET,
-       LXC_NS_CGROUP,
-       LXC_NS_TIME,
-       LXC_NS_MAX
-};
+typedef enum lxc_namespace_t {
+       LXC_NS_USER     = 0,
+       LXC_NS_MNT      = 1,
+       LXC_NS_PID      = 2,
+       LXC_NS_UTS      = 3,
+       LXC_NS_IPC      = 4,
+       LXC_NS_NET      = 5,
+       LXC_NS_CGROUP   = 6,
+       LXC_NS_TIME     = 7,
+       LXC_NS_MAX      = 8
+} lxc_namespace_t;
 
 __hidden extern const struct ns_info {
-       const char *proc_name;
+#define MAX_NS_PROC_NAME 6
+       const char proc_name[MAX_NS_PROC_NAME];
        const char *proc_path;
        int clone_flag;
        const char *flag_name;
index f883787673ad7aa9b893879da4cbd3f51e549c71..6e0765e760909bfc6a3bacfcbf3743424770b6ab 100644 (file)
@@ -112,23 +112,37 @@ static void lxc_put_nsfds(struct lxc_handler *handler)
        }
 }
 
-static int lxc_try_preserve_ns(const int pid, const char *ns)
+static int lxc_try_preserve_namespace(struct lxc_handler *handler,
+                                     lxc_namespace_t idx, const char *ns)
 {
-       int fd;
+       __do_close int fd = -EBADF;
+       int ret;
 
-       fd = lxc_preserve_ns(pid, ns);
+       fd = lxc_preserve_ns(handler->pid, ns);
        if (fd < 0) {
                if (errno != ENOENT)
-                       return log_error_errno(-EINVAL,
-                                              errno, "Failed to preserve %s namespace",
-                                              ns);
+                       return log_error_errno(-EINVAL, errno,
+                                              "Failed to preserve %s namespace", ns);
 
-               return log_warn_errno(-EOPNOTSUPP,
-                                     errno, "Kernel does not support preserving %s namespaces",
-                                     ns);
+               return log_warn_errno(-EOPNOTSUPP, errno,
+                                     "Kernel does not support preserving %s namespaces", ns);
        }
 
-       return fd;
+       ret = strnprintf(handler->nsfd_paths[idx],
+                        sizeof(handler->nsfd_paths[idx]), "%s:/proc/%d/fd/%d",
+                        ns_info[idx].proc_name, handler->monitor_pid, fd);
+
+       /* Legacy style argument passing as arguments to hooks. */
+       handler->hook_argv[handler->hook_argc] = handler->nsfd_paths[idx];
+       handler->hook_argc++;
+       if (ret < 0)
+               return ret_errno(EIO);
+
+       DEBUG("Preserved %s namespace via fd %d and stashed path as %s",
+             ns_info[idx].proc_name, fd, handler->nsfd_paths[idx]);
+
+       handler->nsfd[idx] = move_fd(fd);
+       return 0;
 }
 
 /* lxc_try_preserve_namespaces: open /proc/@pid/ns/@ns for each namespace
@@ -136,35 +150,30 @@ static int lxc_try_preserve_ns(const int pid, const char *ns)
  * Return true on success, false on failure.
  */
 static bool lxc_try_preserve_namespaces(struct lxc_handler *handler,
-                                       int ns_clone_flags, pid_t pid)
+                                       int ns_clone_flags)
 {
-       int i;
+       for (lxc_namespace_t ns_idx = 0; ns_idx < LXC_NS_MAX; ns_idx++)
+               handler->nsfd[ns_idx] = -EBADF;
 
-       for (i = 0; i < LXC_NS_MAX; i++)
-               handler->nsfd[i] = -EBADF;
-
-       for (i = 0; i < LXC_NS_MAX; i++) {
-               int fd;
+       for (lxc_namespace_t ns_idx = 0; ns_idx < LXC_NS_MAX; ns_idx++) {
+               int ret;
 
-               if ((ns_clone_flags & ns_info[i].clone_flag) == 0)
+               if ((ns_clone_flags & ns_info[ns_idx].clone_flag) == 0)
                        continue;
 
-               fd = lxc_try_preserve_ns(pid, ns_info[i].proc_name);
-               if (fd < 0) {
+               ret = lxc_try_preserve_namespace(handler, ns_idx,
+                                                ns_info[ns_idx].proc_name);
+               if (ret < 0) {
                        /* Do not fail to start container on kernels that do
                         * not support interacting with namespaces through
                         * /proc.
                         */
-                       if (fd == -EOPNOTSUPP)
+                       if (ret == -EOPNOTSUPP)
                                continue;
 
                        lxc_put_nsfds(handler);
                        return false;
                }
-
-               handler->nsfd[i] = fd;
-               DEBUG("Preserved %s namespace via fd %d", ns_info[i].proc_name,
-                     handler->nsfd[i]);
        }
 
        return true;
@@ -666,8 +675,18 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old,
        if (handler->conf->reboot == REBOOT_NONE)
                lxc_list_init(&handler->conf->state_clients);
 
-       for (int i = 0; i < LXC_NS_MAX; i++)
-               handler->nsfd[i] = -EBADF;
+       for (lxc_namespace_t idx = 0; idx < LXC_NS_MAX; idx++) {
+               handler->nsfd[idx] = -EBADF;
+
+               if (handler->conf->reboot == REBOOT_NONE)
+                       continue;
+
+               handler->nsfd_paths[idx][0] = '\0';
+               handler->hook_argv[idx] = NULL;
+
+               if (handler->hook_argc != 0)
+                       handler->hook_argc = 0;
+       }
 
        handler->name = name;
        if (daemonize)
@@ -845,13 +864,30 @@ out_restore_sigmask:
        return -1;
 }
 
+void lxc_expose_namespace_environment(const struct lxc_handler *handler)
+{
+       for (lxc_namespace_t i = 0; i < LXC_NS_MAX; i++) {
+               int ret;
+               const char *fd_path;
+
+               if (handler->nsfd[i] < 0)
+                       continue;
+
+               fd_path = handler->nsfd_paths[i] + strcspn(handler->nsfd_paths[i], "/");
+               ret = setenv(ns_info[i].env_name, fd_path, 1);
+               if (ret < 0)
+                       SYSERROR("Failed to set environment variable %s=%s",
+                                ns_info[i].env_name, fd_path);
+               else
+                       TRACE("Set environment variable %s=%s",
+                             ns_info[i].env_name, fd_path);
+       }
+}
+
 void lxc_end(struct lxc_handler *handler)
 {
        int ret;
-       pid_t self;
        struct lxc_list *cur, *next;
-       char *namespaces[LXC_NS_MAX + 1];
-       size_t namespace_count = 0;
        const char *name = handler->name;
        struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
 
@@ -860,39 +896,9 @@ void lxc_end(struct lxc_handler *handler)
         */
        lxc_set_state(name, handler, STOPPING);
 
-       self = lxc_raw_getpid();
-       for (int i = 0; i < LXC_NS_MAX; i++) {
-               if (handler->nsfd[i] < 0)
-                       continue;
-
-               if (handler->conf->hooks_version == 0)
-                       ret = asprintf(&namespaces[namespace_count],
-                                     "%s:/proc/%d/fd/%d", ns_info[i].proc_name,
-                                     self, handler->nsfd[i]);
-               else
-                       ret = asprintf(&namespaces[namespace_count],
-                                     "/proc/%d/fd/%d", self, handler->nsfd[i]);
-               if (ret < 0) {
-                       SYSERROR("Failed to allocate memory");
-                       break;
-               }
-
-               if (handler->conf->hooks_version == 0) {
-                       namespace_count++;
-                       continue;
-               }
-
-               ret = setenv(ns_info[i].env_name, namespaces[namespace_count], 1);
-               if (ret < 0)
-                       SYSERROR("Failed to set environment variable %s=%s",
-                                ns_info[i].env_name, namespaces[namespace_count]);
-               else
-                       TRACE("Set environment variable %s=%s",
-                             ns_info[i].env_name, namespaces[namespace_count]);
-
-               namespace_count++;
-       }
-       namespaces[namespace_count] = NULL;
+       /* Passing information to hooks via environment variables. */
+       if (handler->conf->hooks_version > 0)
+               lxc_expose_namespace_environment(handler);
 
        if (handler->conf->reboot > REBOOT_NONE) {
                ret = setenv("LXC_TARGET", "reboot", 1);
@@ -907,15 +913,12 @@ void lxc_end(struct lxc_handler *handler)
        }
 
        if (handler->conf->hooks_version == 0)
-               ret = run_lxc_hooks(name, "stop", handler->conf, namespaces);
+               ret = run_lxc_hooks(name, "stop", handler->conf, handler->hook_argv);
        else
                ret = run_lxc_hooks(name, "stop", handler->conf, NULL);
        if (ret < 0)
                ERROR("Failed to run \"lxc.hook.stop\" hook");
 
-       while (namespace_count--)
-               free(namespaces[namespace_count]);
-
        handler->lsm_ops->cleanup(handler->lsm_ops, handler->conf, handler->lxcpath);
 
        if (cgroup_ops) {
@@ -1761,7 +1764,7 @@ static int lxc_spawn(struct lxc_handler *handler)
                if (handler->ns_on_clone_flags & ns_info[i].clone_flag)
                        INFO("Cloned %s", ns_info[i].flag_name);
 
-       if (!lxc_try_preserve_namespaces(handler, handler->ns_on_clone_flags, handler->pid)) {
+       if (!lxc_try_preserve_namespaces(handler, handler->ns_on_clone_flags)) {
                ERROR("Failed to preserve cloned namespaces for lxc.hook.stop");
                goto out_delete_net;
        }
@@ -1822,15 +1825,12 @@ static int lxc_spawn(struct lxc_handler *handler)
 
        /* If not done yet, we're now ready to preserve the network namespace */
        if (handler->nsfd[LXC_NS_NET] < 0) {
-               ret = lxc_try_preserve_ns(handler->pid, "net");
+               ret = lxc_try_preserve_namespace(handler, LXC_NS_NET, "net");
                if (ret < 0) {
                        if (ret != -EOPNOTSUPP) {
                                SYSERROR("Failed to preserve net namespace");
                                goto out_delete_net;
                        }
-               } else {
-                       handler->nsfd[LXC_NS_NET] = ret;
-                       DEBUG("Preserved net namespace via fd %d", ret);
                }
        }
        ret = lxc_netns_set_nsid(handler->nsfd[LXC_NS_NET]);
@@ -1896,15 +1896,12 @@ static int lxc_spawn(struct lxc_handler *handler)
 
        if (handler->ns_unshare_flags & CLONE_NEWCGROUP) {
                /* Now we're ready to preserve the cgroup namespace */
-               ret = lxc_try_preserve_ns(handler->pid, "cgroup");
+               ret = lxc_try_preserve_namespace(handler, LXC_NS_CGROUP, "cgroup");
                if (ret < 0) {
                        if (ret != -EOPNOTSUPP) {
                                SYSERROR("Failed to preserve cgroup namespace");
                                goto out_delete_net;
                        }
-               } else {
-                       handler->nsfd[LXC_NS_CGROUP] = ret;
-                       DEBUG("Preserved cgroup namespace via fd %d", ret);
                }
        }
 
@@ -1913,15 +1910,12 @@ static int lxc_spawn(struct lxc_handler *handler)
 
        if (handler->ns_unshare_flags & CLONE_NEWTIME) {
                /* Now we're ready to preserve the cgroup namespace */
-               ret = lxc_try_preserve_ns(handler->pid, "time");
+               ret = lxc_try_preserve_namespace(handler, LXC_NS_TIME, "time");
                if (ret < 0) {
                        if (ret != -EOPNOTSUPP) {
                                SYSERROR("Failed to preserve time namespace");
                                goto out_delete_net;
                        }
-               } else {
-                       handler->nsfd[LXC_NS_TIME] = ret;
-                       DEBUG("Preserved time namespace via fd %d", ret);
                }
        }
 
index 45c48a650281b6bef683cb05bf95e2e4a0be91ce..b06b0dd0436673a1e3c8ecec5b794ff2c541eb09 100644 (file)
@@ -127,6 +127,12 @@ struct lxc_handler {
 
        /* Static memory, don't free. */
        struct lsm_ops *lsm_ops;
+
+       /* The namespace idx is guaranteed to match the stashed namespace path. */
+       char nsfd_paths[LXC_NS_MAX + 1][LXC_EXPOSE_NAMESPACE_LEN];
+       /* The namesace idx is _not_ guaranteed to match the stashed namespace path. */
+       lxc_namespace_t hook_argc;
+       char *hook_argv[LXC_NS_MAX + 1];
 };
 
 struct execute_args {
@@ -172,5 +178,6 @@ __hidden extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, v
                                bool, int *);
 
 __hidden extern int resolve_clone_flags(struct lxc_handler *handler);
+__hidden extern void lxc_expose_namespace_environment(const struct lxc_handler *handler);
 
 #endif