]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
start: enable pre-setns() kernels 2357/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 28 May 2018 11:12:23 +0000 (13:12 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 28 May 2018 11:20:16 +0000 (13:20 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/start.c
src/lxc/utils.c
src/lxc/utils.h

index 9d148dae3e0e597ac3a2144e575f2e3cf6b3be77..c8523310f655877163c5a066c1d1ef3c00f4cb62 100644 (file)
@@ -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;
 
        for (i = 0; i < LXC_NS_MAX; i++) {
-               if (ns_fd[i] > -1) {
-                       close(ns_fd[i]);
-                       ns_fd[i] = -1;
+               if (nsfd[i] < 0)
+                       continue;
+
+               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;
 }
 
-/*
- * preserve_ns: open /proc/@pid/ns/@ns for each namespace specified
- * in clone_flags.
- * Return true on success, false on failure.  On failure, leave an error
- * message in *errmsg, which caller must free.
+/* lxc_try_preserve_namespaces: open /proc/@pid/ns/@ns for each namespace
+ * specified in ns_clone_flags.
+ * Return true on success, false on failure.
  */
-static
-bool preserve_ns(int ns_fd[LXC_NS_MAX], int clone_flags, pid_t pid, char **errmsg) {
-       int i, ret;
-       char path[MAXPATHLEN];
+static bool lxc_try_preserve_namespaces(int nsfd[LXC_NS_MAX],
+                                       int ns_clone_flags, pid_t pid)
+{
+       int i;
 
        for (i = 0; i < LXC_NS_MAX; i++)
-               ns_fd[i] = -1;
-
-       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;
-       }
+               nsfd[i] = -EBADF;
 
        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;
-               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:
-       if (errno == ENOENT) {
-               ret = asprintf(errmsg, "Kernel does not support setns for %s",
-                       ns_info[i].proc_name);
-       } else {
-               ret = asprintf(errmsg, "Failed to open %s: %s",
-                       path, strerror(errno));
+                       /* Do not fail to start container on kernels that do
+                        * not support interacting with namespaces through
+                        * /proc.
+                        */
+                       if (fd == -EOPNOTSUPP)
+                               continue;
+
+                       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;
-       close_ns(ns_fd);
-       return false;
+
+       return true;
 }
 
 static int attach_ns(const int ns_fd[LXC_NS_MAX]) {
@@ -931,9 +946,8 @@ static int lxc_spawn(struct lxc_handler *handler)
                        INFO("failed to pin the container's rootfs");
        }
 
-       if (!preserve_ns(saved_ns_fd, preserve_mask, getpid(), &errmsg)) {
-               SYSERROR("Failed to preserve requested namespaces: %s",
-                       errmsg ? errmsg : "(Out of memory)");
+       if (!lxc_try_preserve_namespaces(saved_ns_fd, preserve_mask, getpid())) {
+               SYSERROR("Failed to preserve requested namespaces");
                free(errmsg);
                goto out_delete_net;
        }
@@ -959,9 +973,8 @@ static int lxc_spawn(struct lxc_handler *handler)
                goto out_delete_net;
        }
 
-       if (!preserve_ns(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid, &errmsg)) {
-               INFO("Failed to store namespace references for stop hook: %s",
-                       errmsg ? errmsg : "(Out of memory)");
+       if (!lxc_try_preserve_namespaces(handler->nsfd, handler->clone_flags | preserve_mask, handler->pid)) {
+               INFO("Failed to store namespace references for stop hook");
                free(errmsg);
        }
 
index 97892ad1e9bd77a5aaf18808ac68942efb7fbb9f..6777118184f0c2495d2a7ee07af5ba4b68fd61ac 100644 (file)
@@ -1392,3 +1392,24 @@ int set_stdfds(int fd)
 
        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);
+}
index 8859eeb74597872cb6369f86ce52248952fc5f93..1c53d1c9960079c587a230564d780224c3e4371e 100644 (file)
@@ -319,4 +319,6 @@ int null_stdfds(void);
 int safe_mount(const char *src, const char *dest, const char *fstype,
                unsigned long flags, const void *data, const char *rootfs);
 int set_stdfds(int fd);
+int lxc_preserve_ns(const int pid, const char *ns);
+
 #endif /* __LXC_UTILS_H */