Unverified Commit 86a31701 by Stéphane Graber Committed by GitHub

Merge pull request #2357 from brauner/2018-05-28/enable_pre_setns_kernels-II

start: enable pre-setns() kernels
parents 595d12b7 986d6340
...@@ -106,62 +106,77 @@ static void print_top_failing_dir(const char *path) ...@@ -106,62 +106,77 @@ static void print_top_failing_dir(const char *path)
} }
} }
static void close_ns(int ns_fd[LXC_NS_MAX]) { static void lxc_put_nsfds(int nsfd[LXC_NS_MAX])
{
int i; int i;
for (i = 0; i < LXC_NS_MAX; i++) { for (i = 0; i < LXC_NS_MAX; i++) {
if (ns_fd[i] > -1) { if (nsfd[i] < 0)
close(ns_fd[i]); continue;
ns_fd[i] = -1;
close(nsfd[i]);
nsfd[i] = -EBADF;
}
}
static int lxc_try_preserve_ns(const int pid, const char *ns)
{
int fd;
fd = lxc_preserve_ns(pid, ns);
if (fd < 0) {
if (errno != ENOENT) {
SYSERROR("Failed to preserve %s namespace", ns);
return -EINVAL;
} }
WARN("%s - Kernel does not support preserving %s namespaces",
strerror(errno), ns);
return -EOPNOTSUPP;
} }
return fd;
} }
/* /* lxc_try_preserve_namespaces: open /proc/@pid/ns/@ns for each namespace
* preserve_ns: open /proc/@pid/ns/@ns for each namespace specified * specified in ns_clone_flags.
* in clone_flags. * Return true on success, false on failure.
* Return true on success, false on failure. On failure, leave an error
* message in *errmsg, which caller must free.
*/ */
static static bool lxc_try_preserve_namespaces(int nsfd[LXC_NS_MAX],
bool preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid, char **errmsg) { int ns_clone_flags, pid_t pid)
int i, ret; {
char path[MAXPATHLEN]; int i;
for (i = 0; i < LXC_NS_MAX; i++) for (i = 0; i < LXC_NS_MAX; i++)
ns_fd[i] = -1; nsfd[i] = -EBADF;
snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
if (access(path, X_OK)) {
if (asprintf(errmsg, "Kernel does not support setns.") == -1)
*errmsg = NULL;
return false;
}
for (i = 0; i < LXC_NS_MAX; i++) { for (i = 0; i < LXC_NS_MAX; i++) {
if ((clone_flags & ns_info[i].clone_flag) == 0) int fd;
if ((ns_clone_flags & ns_info[i].clone_flag) == 0)
continue; continue;
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid,
ns_info[i].proc_name);
ns_fd[i] = open(path, O_RDONLY | O_CLOEXEC);
if (ns_fd[i] < 0)
goto error;
}
return true; fd = lxc_try_preserve_ns(pid, ns_info[i].proc_name);
if (fd < 0) {
nsfd[i] = -EBADF;
error: /* Do not fail to start container on kernels that do
if (errno == ENOENT) { * not support interacting with namespaces through
ret = asprintf(errmsg, "Kernel does not support setns for %s", * /proc.
ns_info[i].proc_name); */
} else { if (fd == -EOPNOTSUPP)
ret = asprintf(errmsg, "Failed to open %s: %s", continue;
path, strerror(errno));
lxc_put_nsfds(nsfd);
return false;
}
nsfd[i] = fd;
DEBUG("Preserved %s namespace via fd %d", ns_info[i].proc_name,
nsfd[i]);
} }
if (ret == -1)
*errmsg = NULL; return true;
close_ns(ns_fd);
return false;
} }
static int attach_ns(const int ns_fd[LXC_NS_MAX]) { static int attach_ns(const int ns_fd[LXC_NS_MAX]) {
...@@ -931,9 +946,8 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -931,9 +946,8 @@ static int lxc_spawn(struct lxc_handler *handler)
INFO("failed to pin the container's rootfs"); INFO("failed to pin the container's rootfs");
} }
if (!preserve_ns(saved_ns_fd, preserve_mask, getpid(), &errmsg)) { if (!lxc_try_preserve_namespaces(saved_ns_fd, preserve_mask, getpid())) {
SYSERROR("Failed to preserve requested namespaces: %s", SYSERROR("Failed to preserve requested namespaces");
errmsg ? errmsg : "(Out of memory)");
free(errmsg); free(errmsg);
goto out_delete_net; goto out_delete_net;
} }
...@@ -959,9 +973,8 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -959,9 +973,8 @@ static int lxc_spawn(struct lxc_handler *handler)
goto out_delete_net; goto out_delete_net;
} }
if (!preserve_ns(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid, &errmsg)) { if (!lxc_try_preserve_namespaces(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid)) {
INFO("Failed to store namespace references for stop hook: %s", INFO("Failed to store namespace references for stop hook");
errmsg ? errmsg : "(Out of memory)");
free(errmsg); free(errmsg);
} }
......
...@@ -1392,3 +1392,24 @@ int set_stdfds(int fd) ...@@ -1392,3 +1392,24 @@ int set_stdfds(int fd)
return 0; return 0;
} }
int lxc_preserve_ns(const int pid, const char *ns)
{
int ret;
/* 5 /proc + 21 /int_as_str + 3 /ns + 20 /NS_NAME + 1 \0 */
#define __NS_PATH_LEN 50
char path[__NS_PATH_LEN];
/* This way we can use this function to also check whether namespaces
* are supported by the kernel by passing in the NULL or the empty
* string.
*/
ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid,
!ns || strcmp(ns, "") == 0 ? "" : "/",
!ns || strcmp(ns, "") == 0 ? "" : ns);
errno = EFBIG;
if (ret < 0 || (size_t)ret >= __NS_PATH_LEN)
return -EFBIG;
return open(path, O_RDONLY | O_CLOEXEC);
}
...@@ -319,4 +319,6 @@ int null_stdfds(void); ...@@ -319,4 +319,6 @@ int null_stdfds(void);
int safe_mount(const char *src, const char *dest, const char *fstype, int safe_mount(const char *src, const char *dest, const char *fstype,
unsigned long flags, const void *data, const char *rootfs); unsigned long flags, const void *data, const char *rootfs);
int set_stdfds(int fd); int set_stdfds(int fd);
int lxc_preserve_ns(const int pid, const char *ns);
#endif /* __LXC_UTILS_H */ #endif /* __LXC_UTILS_H */
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