]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
namespace-util: introduce network_namespace_is_init()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 2 Jun 2026 02:32:26 +0000 (11:32 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 17 Jul 2026 20:29:59 +0000 (05:29 +0900)
src/basic/namespace-util.c
src/basic/namespace-util.h
src/test/test-namespace.c

index db95ab86275bc85350c05752eadc0c42d277241a..72e7005c946133b8e693fb8ac5817f8a8ed90ada 100644 (file)
@@ -3,6 +3,7 @@
 #include <fcntl.h>
 #include <linux/magic.h>
 #include <linux/nsfs.h>
+#include <linux/sockios.h>
 #include <sched.h>
 #include <sys/ioctl.h>
 #include <sys/mount.h>
@@ -410,12 +411,48 @@ int are_our_namespaces(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd,
         return true;
 }
 
+int network_namespace_is_init(int socket_fd) {
+        struct stat a, b;
+        int r;
+
+        /* This works only when privileged. */
+
+        r = RET_NERRNO(stat(pid_namespace_path(1, NAMESPACE_NET), &a));
+        if (r == -ENOENT) {
+                /* If the /proc/ns/<type> API is not around in /proc/ then ns is off in the kernel and we are in the init ns */
+                r = proc_mounted();
+                if (r < 0)
+                        return -ENOENT; /* If we can't determine if /proc/ is mounted propagate original error */
+
+                return r ? true : -ENOSYS;
+        }
+        if (r < 0)
+                return r;
+
+        if (socket_fd >= 0) {
+                _cleanup_close_ int netns = ioctl(socket_fd, SIOCGSKNS);
+                if (netns < 0)
+                        return -errno;
+
+                if (fstat(netns, &b) < 0)
+                        return -errno;
+        } else {
+                if (stat(pid_namespace_path(0, NAMESPACE_NET), &b) < 0)
+                        return -errno;
+        }
+
+        return stat_inode_same(&a, &b);
+}
+
 int namespace_is_init(NamespaceType type) {
         int r;
 
         assert(type >= 0);
         assert(type < _NAMESPACE_TYPE_MAX);
 
+        if (type == NAMESPACE_NET)
+                return network_namespace_is_init(/* socket_fd= */ -EBADF);
+
         if (namespace_info[type].root_inode == 0)
                 return -EBADR; /* Cannot answer this question */
 
index b82efc826b70f0cf1f3371234a2cf402810273e6..d0eff636a9d2b921da859e0f98cf449785b7be8a 100644 (file)
@@ -52,6 +52,7 @@ int fd_is_namespace(int fd, NamespaceType type);
 int is_our_namespace(int fd, NamespaceType type);
 int are_our_namespaces(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
 
+int network_namespace_is_init(int socket_fd);
 int namespace_is_init(NamespaceType type);
 
 int pidref_in_same_namespace(PidRef *pid1, PidRef *pid2, NamespaceType type);
index b9f4e35f2e1a209833a16ab7f95a1b3738001502..7b95a591355624fde165a7bb6d7a9a57fdd2565d 100644 (file)
@@ -253,6 +253,8 @@ TEST(namespace_is_init) {
                 r = namespace_is_init(t);
                 if (r == -EBADR)
                         log_info_errno(r, "In root namespace of type '%s': don't know", namespace_info[t].proc_name);
+                else if (t == NAMESPACE_NET && ERRNO_IS_NEG_PRIVILEGE(r))
+                        log_info_errno(r, "In root namespace of type '%s': no privilege: %m", namespace_info[t].proc_name);
                 else {
                         ASSERT_OK(r);
                         log_info("In root namespace of type '%s': %s", namespace_info[t].proc_name, yes_no(r));