]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Refactor network namespace specific functions in generic helpers
authorXℹ Ruoyao <xry111@mengyan1223.wang>
Tue, 16 Feb 2021 12:49:15 +0000 (20:49 +0800)
committerXℹ Ruoyao <xry111@mengyan1223.wang>
Wed, 3 Mar 2021 16:04:36 +0000 (00:04 +0800)
src/basic/namespace-util.c
src/basic/namespace-util.h
src/core/execute.c
src/core/namespace.c
src/core/namespace.h
src/core/socket.c
src/nspawn/nspawn.c
src/shared/nsflags.c
src/shared/nsflags.h
src/test/test-namespace.c
src/test/test-stat-util.c

index 833a18a20499d012a6c3f7c5b089bb86e6132925..74c3ca042185d888a0b6acbbd8e5778e4951e84d 100644 (file)
@@ -125,13 +125,13 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
         return reset_uid_gid();
 }
 
-int fd_is_network_ns(int fd) {
+int fd_is_ns(int fd, unsigned long nsflag) {
         struct statfs s;
         int r;
 
-        /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
-         * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
-         * this somewhat nicely.
+        /* Checks whether the specified file descriptor refers to a namespace created by specifying nsflag in clone().
+         * On old kernels there's no nice way to detect that, hence on those we'll return a recognizable error (EUCLEAN),
+         * so that callers can handle this somewhat nicely.
          *
          * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
          * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
@@ -168,7 +168,7 @@ int fd_is_network_ns(int fd) {
                 return -errno;
         }
 
-        return r == CLONE_NEWNET;
+        return (unsigned long) r == nsflag;
 }
 
 int detach_mount_namespace(void) {
index 7f7d06687307d6f747a31a21eb173ea25c03df3e..daa9accda378240ed6e66c419bc64916f7a1c3d3 100644 (file)
@@ -6,6 +6,6 @@
 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
 
-int fd_is_network_ns(int fd);
+int fd_is_ns(int fd, unsigned long nsflag);
 
 int detach_mount_namespace(void);
index 0d3fc1c0fc4a425bdb249b3ebc4b9a53d2809702..0a2d2e1158519d2054a8dec28d6b8b07eca0e093 100644 (file)
@@ -3918,7 +3918,7 @@ static int exec_child(
         }
 
         if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) {
-                r = open_netns_path(runtime->netns_storage_socket, context->network_namespace_path);
+                r = open_shareable_ns_path(runtime->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET);
                 if (r < 0) {
                         *exit_status = EXIT_NETWORK;
                         return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path);
@@ -4195,7 +4195,7 @@ static int exec_child(
         if ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) {
 
                 if (ns_type_supported(NAMESPACE_NET)) {
-                        r = setup_netns(runtime->netns_storage_socket);
+                        r = setup_shareable_ns(runtime->netns_storage_socket, CLONE_NEWNET);
                         if (r == -EPERM)
                                 log_unit_warning_errno(unit, r,
                                                        "PrivateNetwork=yes is configured, but network namespace setup failed, ignoring: %m");
index 04b631d90c9a956e8e9b92186fe6c8b0c50ec6d8..d484ce7d67fd55a5c41b02d58916dd9888b55290 100644 (file)
@@ -26,6 +26,7 @@
 #include "mountpoint-util.h"
 #include "namespace-util.h"
 #include "namespace.h"
+#include "nsflags.h"
 #include "nulstr-util.h"
 #include "os-util.h"
 #include "path-util.h"
@@ -2508,13 +2509,17 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
         return 0;
 }
 
-int setup_netns(const int netns_storage_socket[static 2]) {
-        _cleanup_close_ int netns = -1;
+int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag) {
+        _cleanup_close_ int ns = -1;
         int r, q;
+        const char *ns_name, *ns_path;
 
-        assert(netns_storage_socket);
-        assert(netns_storage_socket[0] >= 0);
-        assert(netns_storage_socket[1] >= 0);
+        assert(ns_storage_socket);
+        assert(ns_storage_socket[0] >= 0);
+        assert(ns_storage_socket[1] >= 0);
+
+        ns_name = namespace_single_flag_to_string(nsflag);
+        assert(ns_name);
 
         /* We use the passed socketpair as a storage buffer for our
          * namespace reference fd. Whatever process runs this first
@@ -2524,35 +2529,36 @@ int setup_netns(const int netns_storage_socket[static 2]) {
          *
          * It's a bit crazy, but hey, works great! */
 
-        if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
+        if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0)
                 return -errno;
 
-        netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
-        if (netns == -EAGAIN) {
+        ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
+        if (ns == -EAGAIN) {
                 /* Nothing stored yet, so let's create a new namespace. */
 
-                if (unshare(CLONE_NEWNET) < 0) {
+                if (unshare(nsflag) < 0) {
                         r = -errno;
                         goto fail;
                 }
 
                 (void) loopback_setup();
 
-                netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (netns < 0) {
+                ns_path = strjoina("/proc/self/ns/", ns_name);
+                ns = open(ns_path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (ns < 0) {
                         r = -errno;
                         goto fail;
                 }
 
                 r = 1;
 
-        } else if (netns < 0) {
-                r = netns;
+        } else if (ns < 0) {
+                r = ns;
                 goto fail;
 
         } else {
                 /* Yay, found something, so let's join the namespace */
-                if (setns(netns, CLONE_NEWNET) < 0) {
+                if (setns(ns, nsflag) < 0) {
                         r = -errno;
                         goto fail;
                 }
@@ -2560,45 +2566,45 @@ int setup_netns(const int netns_storage_socket[static 2]) {
                 r = 0;
         }
 
-        q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
+        q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT);
         if (q < 0) {
                 r = q;
                 goto fail;
         }
 
 fail:
-        (void) lockf(netns_storage_socket[0], F_ULOCK, 0);
+        (void) lockf(ns_storage_socket[0], F_ULOCK, 0);
         return r;
 }
 
-int open_netns_path(const int netns_storage_socket[static 2], const char *path) {
-        _cleanup_close_ int netns = -1;
+int open_shareable_ns_path(const int ns_storage_socket[static 2], const char *path, unsigned long nsflag) {
+        _cleanup_close_ int ns = -1;
         int q, r;
 
-        assert(netns_storage_socket);
-        assert(netns_storage_socket[0] >= 0);
-        assert(netns_storage_socket[1] >= 0);
+        assert(ns_storage_socket);
+        assert(ns_storage_socket[0] >= 0);
+        assert(ns_storage_socket[1] >= 0);
         assert(path);
 
-        /* If the storage socket doesn't contain a netns fd yet, open one via the file system and store it in
-         * it. This is supposed to be called ahead of time, i.e. before setup_netns() which will allocate a
-         * new anonymous netns if needed. */
+        /* If the storage socket doesn't contain a ns fd yet, open one via the file system and store it in
+         * it. This is supposed to be called ahead of time, i.e. before setup_shareable_ns() which will
+         * allocate a new anonymous ns if needed. */
 
-        if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
+        if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0)
                 return -errno;
 
-        netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
-        if (netns == -EAGAIN) {
+        ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
+        if (ns == -EAGAIN) {
                 /* Nothing stored yet. Open the file from the file system. */
 
-                netns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (netns < 0) {
+                ns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (ns < 0) {
                         r = -errno;
                         goto fail;
                 }
 
-                r = fd_is_network_ns(netns);
-                if (r == 0) { /* Not a netns? Refuse early. */
+                r = fd_is_ns(ns, nsflag);
+                if (r == 0) { /* Not a ns of our type? Refuse early. */
                         r = -EINVAL;
                         goto fail;
                 }
@@ -2607,20 +2613,20 @@ int open_netns_path(const int netns_storage_socket[static 2], const char *path)
 
                 r = 1;
 
-        } else if (netns < 0) {
-                r = netns;
+        } else if (ns < 0) {
+                r = ns;
                 goto fail;
         } else
                 r = 0; /* Already allocated */
 
-        q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
+        q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT);
         if (q < 0) {
                 r = q;
                 goto fail;
         }
 
 fail:
-        (void) lockf(netns_storage_socket[0], F_ULOCK, 0);
+        (void) lockf(ns_storage_socket[0], F_ULOCK, 0);
         return r;
 }
 
index cb9d5a5d388a193b66547128c71800dbdc24f723..81bce8255508a7d251d56dbb5565ec16866ee007 100644 (file)
@@ -160,8 +160,8 @@ int setup_tmp_dirs(
                 char **tmp_dir,
                 char **var_tmp_dir);
 
-int setup_netns(const int netns_storage_socket[static 2]);
-int open_netns_path(const int netns_storage_socket[static 2], const char *path);
+int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag);
+int open_shareable_ns_path(const int netns_storage_socket[static 2], const char *path, unsigned long nsflag);
 
 const char* protect_home_to_string(ProtectHome p) _const_;
 ProtectHome protect_home_from_string(const char *s) _pure_;
index e9cacfdf3a237a264587c0e0f4f3a64f403b0a03..4bc77f3018aa4f69cf505737b10fe317de317954 100644 (file)
@@ -1547,7 +1547,7 @@ static int socket_address_listen_in_cgroup(
         if (s->exec_context.network_namespace_path &&
             s->exec_runtime &&
             s->exec_runtime->netns_storage_socket[0] >= 0) {
-                r = open_netns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path);
+                r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET);
                 if (r < 0)
                         return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path);
         }
@@ -1568,7 +1568,7 @@ static int socket_address_listen_in_cgroup(
                     s->exec_runtime->netns_storage_socket[0] >= 0) {
 
                         if (ns_type_supported(NAMESPACE_NET)) {
-                                r = setup_netns(s->exec_runtime->netns_storage_socket);
+                                r = setup_shareable_ns(s->exec_runtime->netns_storage_socket, CLONE_NEWNET);
                                 if (r < 0) {
                                         log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m");
                                         _exit(EXIT_NETWORK);
index 44f457a5b549e93572d2aa6e9de1d4ceef85e223..1d9f1ddc5568a61281913716da01675629fc3bc6 100644 (file)
@@ -4563,7 +4563,7 @@ static int run_container(
                 if (child_netns_fd < 0)
                         return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path);
 
-                r = fd_is_network_ns(child_netns_fd);
+                r = fd_is_ns(child_netns_fd, CLONE_NEWNET);
                 if (r == -EUCLEAN)
                         log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path);
                 else if (r < 0)
index d1c2168dea2917491bc5a758756d9babcd87e4fc..b5bba809151b97acec061425697d120e0a4c8456 100644 (file)
@@ -69,3 +69,11 @@ int namespace_flags_to_string(unsigned long flags, char **ret) {
 
         return 0;
 }
+
+const char *namespace_single_flag_to_string(unsigned long flag) {
+        for (unsigned i = 0; namespace_flag_map[i].name; i++)
+                if (namespace_flag_map[i].flag == flag)
+                        return namespace_flag_map[i].name;
+
+        return NULL;
+}
index 3d774c755ca4bb08de058a9c4c95e98334824421..7c4c271d7d0b39a0e1ead63d45d73fff08c2ff67 100644 (file)
@@ -20,6 +20,7 @@
 
 int namespace_flags_from_string(const char *name, unsigned long *ret);
 int namespace_flags_to_string(unsigned long flags, char **ret);
+const char *namespace_single_flag_to_string(unsigned long flag);
 
 struct namespace_flag_map {
         unsigned long flag;
index b162928482cb7e17b553596b7e74740603f1e8f3..bf4b87e8a678d72d4d89826fa18b9155f28c8cf5 100644 (file)
@@ -63,7 +63,7 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
         }
 }
 
-static void test_netns(void) {
+static void test_shareable_ns(unsigned long nsflag) {
         _cleanup_close_pair_ int s[2] = { -1, -1 };
         pid_t pid1, pid2, pid3;
         int r, n = 0;
@@ -80,7 +80,7 @@ static void test_netns(void) {
         assert_se(pid1 >= 0);
 
         if (pid1 == 0) {
-                r = setup_netns(s);
+                r = setup_shareable_ns(s, nsflag);
                 assert_se(r >= 0);
                 _exit(r);
         }
@@ -89,7 +89,7 @@ static void test_netns(void) {
         assert_se(pid2 >= 0);
 
         if (pid2 == 0) {
-                r = setup_netns(s);
+                r = setup_shareable_ns(s, nsflag);
                 assert_se(r >= 0);
                 exit(r);
         }
@@ -98,7 +98,7 @@ static void test_netns(void) {
         assert_se(pid3 >= 0);
 
         if (pid3 == 0) {
-                r = setup_netns(s);
+                r = setup_shareable_ns(s, nsflag);
                 assert_se(r >= 0);
                 exit(r);
         }
@@ -121,6 +121,14 @@ static void test_netns(void) {
         assert_se(n == 1);
 }
 
+static void test_netns(void) {
+        test_shareable_ns(CLONE_NEWNET);
+}
+
+static void test_ipcns(void) {
+        test_shareable_ns(CLONE_NEWIPC);
+}
+
 static void test_protect_kernel_logs(void) {
         int r;
         pid_t pid;
@@ -224,6 +232,7 @@ int main(int argc, char *argv[]) {
         test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
 
         test_netns();
+        test_ipcns();
         test_protect_kernel_logs();
 
         return EXIT_SUCCESS;
index 9aca09c4defa359f59a1bd6567a4e0f6bd2768b9..7f03db5fa7a3ea96c7b66c2b8a43ea113d3c8f64 100644 (file)
@@ -3,6 +3,7 @@
 #include <fcntl.h>
 #include <linux/magic.h>
 #include <unistd.h>
+#include <sched.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
@@ -67,18 +68,22 @@ static void test_path_is_temporary_fs(void) {
         assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT);
 }
 
-static void test_fd_is_network_ns(void) {
+static void test_fd_is_ns(void) {
         _cleanup_close_ int fd = -1;
-        assert_se(fd_is_network_ns(STDIN_FILENO) == 0);
-        assert_se(fd_is_network_ns(STDERR_FILENO) == 0);
-        assert_se(fd_is_network_ns(STDOUT_FILENO) == 0);
+        assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0);
+        assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0);
+        assert_se(fd_is_ns(STDOUT_FILENO, CLONE_NEWNET) == 0);
 
         assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0);
-        assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN));
+        assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 0, -EUCLEAN));
+        fd = safe_close(fd);
+
+        assert_se((fd = open("/proc/self/ns/ipc", O_CLOEXEC|O_RDONLY)) >= 0);
+        assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWIPC), 1, -EUCLEAN));
         fd = safe_close(fd);
 
         assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0);
-        assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN));
+        assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN));
 }
 
 static void test_device_major_minor_valid(void) {
@@ -159,7 +164,7 @@ int main(int argc, char *argv[]) {
         test_is_symlink();
         test_path_is_fs_type();
         test_path_is_temporary_fs();
-        test_fd_is_network_ns();
+        test_fd_is_ns();
         test_device_major_minor_valid();
         test_device_path_make_canonical();