From: Christian Brauner Date: Sun, 14 Feb 2021 13:03:07 +0000 (+0100) Subject: start: rework namespace preservation and path creation for hooks X-Git-Tag: lxc-5.0.0~289^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8db6be1ba59c30f81c472ec47ccca30c0e3baa92;p=thirdparty%2Flxc.git start: rework namespace preservation and path creation for hooks Signed-off-by: Christian Brauner --- diff --git a/src/lxc/macro.h b/src/lxc/macro.h index fac4983ee..9e74078f4 100644 --- a/src/lxc/macro.h +++ b/src/lxc/macro.h @@ -339,6 +339,24 @@ */ #define LXC_LSMATTRLEN (6 + INTTYPE_TO_STRLEN(pid_t) + 6 + 8 + 1) +/* MAX_NS_PROC_NAME = MAX_NS_PROC_NAME + * + + * : = 1 + * + + * /proc/ = 6 + * + + * = INTTYPE_TO_STRLEN(pid_t) + * + + * /fd/ = 4 + * + + * = 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 */ diff --git a/src/lxc/namespace.h b/src/lxc/namespace.h index 6dd83be14..adb8619a3 100644 --- a/src/lxc/namespace.h +++ b/src/lxc/namespace.h @@ -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; diff --git a/src/lxc/start.c b/src/lxc/start.c index f88378767..6e0765e76 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -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); } } diff --git a/src/lxc/start.h b/src/lxc/start.h index 45c48a650..b06b0dd04 100644 --- a/src/lxc/start.h +++ b/src/lxc/start.h @@ -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