]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
virt: revert to detect chroot by comparing with / rather than /proc/PID/root
authorMike Yuan <me@yhndnzj.com>
Thu, 18 Sep 2025 23:16:19 +0000 (01:16 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 10 Oct 2025 08:36:47 +0000 (10:36 +0200)
This partially reverts d6267b9b18a30c81dd3335230ef71af04e1ea330

So, arch-chroot currently uses a rather cursed setup:
it sets up a PID namespace, but mounts /proc/ from the outside
into the chroot tree, and then call chroot(2), essentially
making it somewhere between chroot(8) and a full-blown
container. Hence, the PID dirs in /proc/ reveal the outer world.
The offending commit switched chroot detection to compare
/proc/1/root and /proc/OUR_PID/root, exhibiting the faulty behavior
where the mentioned environment now gets deemed to be non-chroot.

Now, this is very much an issue in arch-chroot. However,
if /proc/ is to be properly associated with the pidns,
then we'd treat it as a container and no longer a chroot.
Also, the previous logic feels more readable and more
honestly reported errors in proc_mounted(). Hence I opted
for reverting the change here. Still note that the culprit
(once again :/) lies in the arch-chroot's pidns impl, not
systemd.

Fixes https://gitlab.archlinux.org/archlinux/packaging/packages/systemd/-/issues/54

(cherry picked from commit 01184496a2b518f33c56b5803549f27fa8f226fe)

src/basic/virt.c

index 1a0156159d0f643d5b07832a96d53f7a17ec1213..ad4b9aa3eafddc659412b91938fe55608f386817 100644 (file)
@@ -16,8 +16,8 @@
 #include "log.h"
 #include "namespace-util.h"
 #include "parse-util.h"
-#include "pidref.h"
 #include "process-util.h"
+#include "stat-util.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
@@ -816,16 +816,19 @@ int running_in_chroot(void) {
         if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0)
                 return 0;
 
-        r = pidref_from_same_root_fs(&PIDREF_MAKE_FROM_PID(1), NULL);
-        if (r == -ENOSYS) {
-                if (getpid_cached() == 1)
-                        return false; /* We will mount /proc, assuming we're not in a chroot. */
+        r = inode_same("/proc/1/root", "/", /* flags = */ 0);
+        if (r == -ENOENT) {
+                r = proc_mounted();
+                if (r == 0) {
+                        if (getpid_cached() == 1)
+                                return false; /* We will mount /proc, assuming we're not in a chroot. */
 
-                log_debug("/proc/ is not mounted, assuming we're in a chroot.");
-                return true;
+                        log_debug("/proc/ is not mounted, assuming we're in a chroot.");
+                        return true;
+                }
+                if (r > 0) /* If we have fake /proc/, we can't do the check properly. */
+                        return -ENOSYS;
         }
-        if (r == -ESRCH) /* We must have a fake /proc/, we can't do the check properly. */
-                return -ENOSYS;
         if (r < 0)
                 return r;