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));
+
+ 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
+
char *resolved = canonicalize_file_name (dir);
bool is_res_root = resolved && streq ("/", resolved);
free (resolved);
return is_res_root;
+
+#endif
}
void
--
2.56.0