summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/namespace-util.c10
-rw-r--r--src/basic/namespace-util.h2
-rw-r--r--src/core/execute.c4
-rw-r--r--src/core/namespace.c76
-rw-r--r--src/core/namespace.h4
-rw-r--r--src/core/socket.c4
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/shared/nsflags.c8
-rw-r--r--src/shared/nsflags.h1
-rw-r--r--src/test/test-namespace.c17
-rw-r--r--src/test/test-stat-util.c19
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();