]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fd-util: skip to check mount ID if kernel is too old and /proc is not mounted
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 17 Apr 2023 14:37:12 +0000 (23:37 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 18 Apr 2023 18:38:47 +0000 (03:38 +0900)
Now, dir_fd_is_root() is heavily used in chaseat(), which is used at
various places. If the kernel is too old and /proc is not mounted, then
there is no way to get the mount ID of a directory. In that case, let's
silently skip the mount ID check.

Fixes https://github.com/systemd/systemd/pull/27299#issuecomment-1511403680.

src/basic/fd-util.c

index 7125e28e1b096f8ecbc414543604083cb28fa7ef..974a7aac655725d5ebfd95d0016570729a0178ea 100644 (file)
@@ -911,10 +911,23 @@ int dir_fd_is_root(int dir_fd) {
         if (!statx_inode_same(&st.sx, &pst.sx))
                 return false;
 
+        /* Even if the parent directory has the same inode, the fd may not point to the root directory "/",
+         * and we also need to check that the mount ids are the same. Otherwise, a construct like the
+         * following could be used to trick us:
+         *
+         * $ mkdir /tmp/x /tmp/x/y
+         * $ mount --bind /tmp/x /tmp/x/y
+         *
+         * Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old
+         * kernel is used without /proc mounted. In that case, let's assume that we do not have such spurious
+         * mount points in an early boot stage, and silently skip the following check. */
+
         if (!FLAGS_SET(st.nsx.stx_mask, STATX_MNT_ID)) {
                 int mntid;
 
                 r = path_get_mnt_id_at(dir_fd, "", &mntid);
+                if (r == -ENOSYS)
+                        return true; /* skip the mount ID check */
                 if (r < 0)
                         return r;
                 assert(mntid >= 0);
@@ -927,6 +940,8 @@ int dir_fd_is_root(int dir_fd) {
                 int mntid;
 
                 r = path_get_mnt_id_at(dir_fd, "..", &mntid);
+                if (r == -ENOSYS)
+                        return true; /* skip the mount ID check */
                 if (r < 0)
                         return r;
                 assert(mntid >= 0);
@@ -935,13 +950,6 @@ int dir_fd_is_root(int dir_fd) {
                 pst.nsx.stx_mask |= STATX_MNT_ID;
         }
 
-        /* Even if the parent directory has the same inode, the fd may not point to the root directory "/",
-         * and we also need to check that the mount ids are the same. Otherwise, a construct like the
-         * following could be used to trick us:
-         *
-         * $ mkdir /tmp/x /tmp/x/y
-         * $ mount --bind /tmp/x /tmp/x/y
-         */
         return statx_mount_same(&st.nsx, &pst.nsx);
 }