On 20/10/2026 08:17, Collin Funk wrote:
This change will also allow for the use of the fchroot system call
added in Linux 7.3, once glibc has updated sys/syscall.h to define
SYS_fchroot.

-- 8< --

* src/chroot.c (is_root) [HAVE_STATX && STATX_INO && STATX_MNT_ID]: Use
the dev/ino and mount ID to determine if the new root is "/".
---
  src/chroot.c | 43 +++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 43 insertions(+)

diff --git a/src/chroot.c b/src/chroot.c
index cad94264e..d33461c7d 100644
--- a/src/chroot.c
+++ b/src/chroot.c
@@ -24,6 +24,7 @@
  #include <grp.h>
#include "system.h"
+#include "fcntl--.h"
  #include "ignore-value.h"
  #include "mgetgroups.h"
  #include "quote.h"
@@ -168,10 +169,52 @@ parse_additional_groups (char const *groups, GETGROUPS_T 
**pgids,
  static bool
  is_root (char const *dir)
  {
+#if HAVE_STATX && defined STATX_INO && defined STATX_MNT_ID
+  /* If the kernel supports it, get the unique mount ID, which
+     will not be reused while the system is running.  */
+# ifdef STATX_MNT_ID_UNIQUE
+#  define MNT_ID_MASK STATX_MNT_ID_UNIQUE
+# else
+#  define MNT_ID_MASK STATX_MNT_ID
+# endif
+
+  int const root_fd = open ("/", O_PATHSEARCH | O_DIRECTORY);
+  if (root_fd < 0)
+    error (EXIT_CANCELED, errno, _("failed to open %s"), quoteaf ("/"));
+
+  int const dir_fd = open (dir, O_PATHSEARCH | O_DIRECTORY);
+  if (dir_fd < 0)
+    error (EXIT_CANCELED, errno, _("failed to open NEWROOT %s"),
+           quoteaf (dir));
+
+  struct statx root_st;
+  if (statx (root_fd, "", AT_EMPTY_PATH,
+             STATX_INO | MNT_ID_MASK, &root_st) < 0)
+    error (EXIT_CANCELED, errno, _("failed to get attributes of %s"),
+           quoteaf ("/"));
+
+  struct statx dir_st;
+  if (statx (dir_fd, "", AT_EMPTY_PATH,
+             STATX_INO | MNT_ID_MASK, &dir_st) < 0)
+    error (EXIT_CANCELED, errno, _("failed to get attributes of NEWROOT %s"),
+           quoteaf (dir));

There should be a check here that MNT_ID_MASK (and STATX_INO) was returned.

+
+  close (root_fd);
+  close (dir_fd);
+
+  return (root_st.stx_dev_minor == dir_st.stx_dev_minor
+          && root_st.stx_dev_major == dir_st.stx_dev_major
+          && root_st.stx_ino == dir_st.stx_ino
+          && root_st.stx_mnt_id == dir_st.stx_mnt_id);
+
+#else

It would be good to fallback at runtime to the following
for older systems that don't support mount ids (or even statx).

+
    char *resolved = canonicalize_file_name (dir);
    bool is_res_root = resolved && streq ("/", resolved);
    free (resolved);
    return is_res_root;
+
+#endif
  }
void

thanks,
Padraig

Reply via email to