start: rework namespace preservation and path creation for hooks

parent 3bcf3ba0
...@@ -339,6 +339,24 @@ ...@@ -339,6 +339,24 @@
*/ */
#define LXC_LSMATTRLEN (6 + INTTYPE_TO_STRLEN(pid_t) + 6 + 8 + 1) #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) #define LXC_CMD_DATA_MAX (PATH_MAX * 2)
/* loop devices */ /* loop devices */
......
...@@ -9,20 +9,21 @@ ...@@ -9,20 +9,21 @@
#include "compiler.h" #include "compiler.h"
enum { typedef enum lxc_namespace_t {
LXC_NS_USER, LXC_NS_USER = 0,
LXC_NS_MNT, LXC_NS_MNT = 1,
LXC_NS_PID, LXC_NS_PID = 2,
LXC_NS_UTS, LXC_NS_UTS = 3,
LXC_NS_IPC, LXC_NS_IPC = 4,
LXC_NS_NET, LXC_NS_NET = 5,
LXC_NS_CGROUP, LXC_NS_CGROUP = 6,
LXC_NS_TIME, LXC_NS_TIME = 7,
LXC_NS_MAX LXC_NS_MAX = 8
}; } lxc_namespace_t;
__hidden extern const struct ns_info { __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; const char *proc_path;
int clone_flag; int clone_flag;
const char *flag_name; const char *flag_name;
......
...@@ -112,23 +112,37 @@ static void lxc_put_nsfds(struct lxc_handler *handler) ...@@ -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 (fd < 0) {
if (errno != ENOENT) if (errno != ENOENT)
return log_error_errno(-EINVAL, return log_error_errno(-EINVAL, errno,
errno, "Failed to preserve %s namespace", "Failed to preserve %s namespace", ns);
ns);
return log_warn_errno(-EOPNOTSUPP, return log_warn_errno(-EOPNOTSUPP, errno,
errno, "Kernel does not support preserving %s namespaces", "Kernel does not support preserving %s namespaces", ns);
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 /* 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) ...@@ -136,35 +150,30 @@ static int lxc_try_preserve_ns(const int pid, const char *ns)
* Return true on success, false on failure. * Return true on success, false on failure.
*/ */
static bool lxc_try_preserve_namespaces(struct lxc_handler *handler, 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++) for (lxc_namespace_t ns_idx = 0; ns_idx < LXC_NS_MAX; ns_idx++) {
handler->nsfd[i] = -EBADF; int ret;
for (i = 0; i < LXC_NS_MAX; i++) {
int fd;
if ((ns_clone_flags & ns_info[i].clone_flag) == 0) if ((ns_clone_flags & ns_info[ns_idx].clone_flag) == 0)
continue; continue;
fd = lxc_try_preserve_ns(pid, ns_info[i].proc_name); ret = lxc_try_preserve_namespace(handler, ns_idx,
if (fd < 0) { ns_info[ns_idx].proc_name);
if (ret < 0) {
/* Do not fail to start container on kernels that do /* Do not fail to start container on kernels that do
* not support interacting with namespaces through * not support interacting with namespaces through
* /proc. * /proc.
*/ */
if (fd == -EOPNOTSUPP) if (ret == -EOPNOTSUPP)
continue; continue;
lxc_put_nsfds(handler); lxc_put_nsfds(handler);
return false; return false;
} }
handler->nsfd[i] = fd;
DEBUG("Preserved %s namespace via fd %d", ns_info[i].proc_name,
handler->nsfd[i]);
} }
return true; return true;
...@@ -666,8 +675,18 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, ...@@ -666,8 +675,18 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old,
if (handler->conf->reboot == REBOOT_NONE) if (handler->conf->reboot == REBOOT_NONE)
lxc_list_init(&handler->conf->state_clients); lxc_list_init(&handler->conf->state_clients);
for (int i = 0; i < LXC_NS_MAX; i++) for (lxc_namespace_t idx = 0; idx < LXC_NS_MAX; idx++) {
handler->nsfd[i] = -EBADF; 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; handler->name = name;
if (daemonize) if (daemonize)
...@@ -845,13 +864,30 @@ out_restore_sigmask: ...@@ -845,13 +864,30 @@ out_restore_sigmask:
return -1; 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) void lxc_end(struct lxc_handler *handler)
{ {
int ret; int ret;
pid_t self;
struct lxc_list *cur, *next; struct lxc_list *cur, *next;
char *namespaces[LXC_NS_MAX + 1];
size_t namespace_count = 0;
const char *name = handler->name; const char *name = handler->name;
struct cgroup_ops *cgroup_ops = handler->cgroup_ops; struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
...@@ -860,39 +896,9 @@ void lxc_end(struct lxc_handler *handler) ...@@ -860,39 +896,9 @@ void lxc_end(struct lxc_handler *handler)
*/ */
lxc_set_state(name, handler, STOPPING); lxc_set_state(name, handler, STOPPING);
self = lxc_raw_getpid(); /* Passing information to hooks via environment variables. */
for (int i = 0; i < LXC_NS_MAX; i++) { if (handler->conf->hooks_version > 0)
if (handler->nsfd[i] < 0) lxc_expose_namespace_environment(handler);
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;
if (handler->conf->reboot > REBOOT_NONE) { if (handler->conf->reboot > REBOOT_NONE) {
ret = setenv("LXC_TARGET", "reboot", 1); ret = setenv("LXC_TARGET", "reboot", 1);
...@@ -907,15 +913,12 @@ void lxc_end(struct lxc_handler *handler) ...@@ -907,15 +913,12 @@ void lxc_end(struct lxc_handler *handler)
} }
if (handler->conf->hooks_version == 0) 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 else
ret = run_lxc_hooks(name, "stop", handler->conf, NULL); ret = run_lxc_hooks(name, "stop", handler->conf, NULL);
if (ret < 0) if (ret < 0)
ERROR("Failed to run \"lxc.hook.stop\" hook"); 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); handler->lsm_ops->cleanup(handler->lsm_ops, handler->conf, handler->lxcpath);
if (cgroup_ops) { if (cgroup_ops) {
...@@ -1761,7 +1764,7 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1761,7 +1764,7 @@ static int lxc_spawn(struct lxc_handler *handler)
if (handler->ns_on_clone_flags & ns_info[i].clone_flag) if (handler->ns_on_clone_flags & ns_info[i].clone_flag)
INFO("Cloned %s", ns_info[i].flag_name); 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"); ERROR("Failed to preserve cloned namespaces for lxc.hook.stop");
goto out_delete_net; goto out_delete_net;
} }
...@@ -1822,15 +1825,12 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -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 not done yet, we're now ready to preserve the network namespace */
if (handler->nsfd[LXC_NS_NET] < 0) { 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 < 0) {
if (ret != -EOPNOTSUPP) { if (ret != -EOPNOTSUPP) {
SYSERROR("Failed to preserve net namespace"); SYSERROR("Failed to preserve net namespace");
goto out_delete_net; 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]); ret = lxc_netns_set_nsid(handler->nsfd[LXC_NS_NET]);
...@@ -1896,15 +1896,12 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1896,15 +1896,12 @@ static int lxc_spawn(struct lxc_handler *handler)
if (handler->ns_unshare_flags & CLONE_NEWCGROUP) { if (handler->ns_unshare_flags & CLONE_NEWCGROUP) {
/* Now we're ready to preserve the cgroup namespace */ /* 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 < 0) {
if (ret != -EOPNOTSUPP) { if (ret != -EOPNOTSUPP) {
SYSERROR("Failed to preserve cgroup namespace"); SYSERROR("Failed to preserve cgroup namespace");
goto out_delete_net; 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) ...@@ -1913,15 +1910,12 @@ static int lxc_spawn(struct lxc_handler *handler)
if (handler->ns_unshare_flags & CLONE_NEWTIME) { if (handler->ns_unshare_flags & CLONE_NEWTIME) {
/* Now we're ready to preserve the cgroup namespace */ /* 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 < 0) {
if (ret != -EOPNOTSUPP) { if (ret != -EOPNOTSUPP) {
SYSERROR("Failed to preserve time namespace"); SYSERROR("Failed to preserve time namespace");
goto out_delete_net; goto out_delete_net;
} }
} else {
handler->nsfd[LXC_NS_TIME] = ret;
DEBUG("Preserved time namespace via fd %d", ret);
} }
} }
......
...@@ -127,6 +127,12 @@ struct lxc_handler { ...@@ -127,6 +127,12 @@ struct lxc_handler {
/* Static memory, don't free. */ /* Static memory, don't free. */
struct lsm_ops *lsm_ops; 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 { struct execute_args {
...@@ -172,5 +178,6 @@ __hidden extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, v ...@@ -172,5 +178,6 @@ __hidden extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, v
bool, int *); bool, int *);
__hidden extern int resolve_clone_flags(struct lxc_handler *handler); __hidden extern int resolve_clone_flags(struct lxc_handler *handler);
__hidden extern void lxc_expose_namespace_environment(const struct lxc_handler *handler);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment