diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/namespace-util.c | 10 | ||||
-rw-r--r-- | src/basic/namespace-util.h | 2 | ||||
-rw-r--r-- | src/core/execute.c | 4 | ||||
-rw-r--r-- | src/core/namespace.c | 76 | ||||
-rw-r--r-- | src/core/namespace.h | 4 | ||||
-rw-r--r-- | src/core/socket.c | 4 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 2 | ||||
-rw-r--r-- | src/shared/nsflags.c | 8 | ||||
-rw-r--r-- | src/shared/nsflags.h | 1 | ||||
-rw-r--r-- | src/test/test-namespace.c | 17 | ||||
-rw-r--r-- | src/test/test-stat-util.c | 19 |
11 files changed, 88 insertions, 59 deletions
diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 833a18a204..74c3ca0421 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -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) { diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index 7f7d066873..daa9accda3 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -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); diff --git a/src/core/execute.c b/src/core/execute.c index 0d3fc1c0fc..0a2d2e1158 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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"); diff --git a/src/core/namespace.c b/src/core/namespace.c index 04b631d90c..d484ce7d67 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -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; } diff --git a/src/core/namespace.h b/src/core/namespace.h index cb9d5a5d38..81bce82555 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -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_; diff --git a/src/core/socket.c b/src/core/socket.c index e9cacfdf3a..4bc77f3018 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 44f457a5b5..1d9f1ddc55 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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) diff --git a/src/shared/nsflags.c b/src/shared/nsflags.c index d1c2168dea..b5bba80915 100644 --- a/src/shared/nsflags.c +++ b/src/shared/nsflags.c @@ -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; +} diff --git a/src/shared/nsflags.h b/src/shared/nsflags.h index 3d774c755c..7c4c271d7d 100644 --- a/src/shared/nsflags.h +++ b/src/shared/nsflags.h @@ -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; diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index b162928482..bf4b87e8a6 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -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; diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 9aca09c4de..7f03db5fa7 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -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(); |