]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
namespace-util: Do is_our_namespace() checks first in namespace_enter()
authorDaan De Meyer <daan@amutable.com>
Tue, 17 Feb 2026 14:36:00 +0000 (15:36 +0100)
committerDaan De Meyer <daan@amutable.com>
Tue, 17 Feb 2026 16:52:17 +0000 (17:52 +0100)
These checks may rely on /proc on older kernels which we could lose access
to by joining namespaces so let's do all the checks first and then join
namespaces.

src/basic/namespace-util.c

index 4ba84a27eab4597d4d0f192f8d9b1ef8cecff0e1..93b9ed1f3888681d0a359041d1b1c0153e18936a 100644 (file)
@@ -228,32 +228,38 @@ int namespace_open(
         return pidref_namespace_open(&pidref, ret_pidns_fd, ret_mntns_fd, ret_netns_fd, ret_userns_fd, ret_root_fd);
 }
 
-static int namespace_enter_one_idempotent(int nsfd, NamespaceType type) {
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
         int r;
 
-        /* Join a namespace, but only if we're not part of it already. This is important if we don't necessarily
-         * own the namespace in question, as kernel would unconditionally return EPERM otherwise. */
-
-        assert(nsfd >= 0);
-        assert(type >= 0 && type < _NAMESPACE_TYPE_MAX);
-
-        r = is_our_namespace(nsfd, type);
-        if (r < 0)
-                return r;
-        if (r > 0)
-                return 0;
+        /* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */
+        block_dlopen();
 
-        if (setns(nsfd, namespace_info[type].clone_flag) < 0)
-                return -errno;
+         /* Join namespaces, but only if we're not part of them already. This is important if we don't
+          * necessarily own the namespace in question, as kernel would unconditionally return EPERM otherwise. */
 
-        return 1;
-}
+        if (pidns_fd >= 0) {
+                r = is_our_namespace(pidns_fd, NAMESPACE_PID);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        pidns_fd = -EBADF;
+        }
 
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
-        int r;
+        if (mntns_fd >= 0) {
+                r = is_our_namespace(mntns_fd, NAMESPACE_MOUNT);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        mntns_fd = -EBADF;
+        }
 
-        /* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */
-        block_dlopen();
+        if (netns_fd >= 0) {
+                r = is_our_namespace(netns_fd, NAMESPACE_NET);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        netns_fd = -EBADF;
+        }
 
         if (userns_fd >= 0) {
                 /* Can't setns to your own userns, since then you could escalate from non-root to root in
@@ -287,23 +293,17 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
                         return -errno;
         }
 
-        if (pidns_fd >= 0) {
-                r = namespace_enter_one_idempotent(pidns_fd, NAMESPACE_PID);
-                if (r < 0)
-                        return r;
-        }
+        if (pidns_fd >= 0)
+                if (setns(pidns_fd, CLONE_NEWPID) < 0)
+                        return -errno;
 
-        if (mntns_fd >= 0) {
-                r = namespace_enter_one_idempotent(mntns_fd, NAMESPACE_MOUNT);
-                if (r < 0)
-                        return r;
-        }
+        if (mntns_fd >= 0)
+                if (setns(mntns_fd, CLONE_NEWNS) < 0)
+                        return -errno;
 
-        if (netns_fd >= 0) {
-                r = namespace_enter_one_idempotent(netns_fd, NAMESPACE_NET);
-                if (r < 0)
-                        return r;
-        }
+        if (netns_fd >= 0)
+                if (setns(netns_fd, CLONE_NEWNET) < 0)
+                        return -errno;
 
         if (userns_fd >= 0 && have_cap_sys_admin)
                 if (setns(userns_fd, CLONE_NEWUSER) < 0)