]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mount-util: port over bind_remount_recursive_with_mountinfo() to mount_setattr()
authorLennart Poettering <lennart@poettering.net>
Wed, 20 Oct 2021 21:12:53 +0000 (23:12 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 25 Oct 2021 08:41:26 +0000 (10:41 +0200)
src/shared/mount-util.c
src/test/test-mount-util.c

index 25dde7b0e286471ad9ba2545d1f8ca89f72af034..2dad667126fcf139aa410b5fd3afe52cc1cb101f 100644 (file)
@@ -175,6 +175,30 @@ int bind_remount_recursive_with_mountinfo(
         assert(prefix);
         assert(proc_self_mountinfo);
 
+        if ((flags_mask & ~MS_CONVERTIBLE_FLAGS) == 0 && strv_isempty(deny_list) && !skip_mount_set_attr) {
+                /* Let's take a shortcut for all the flags we know how to convert into mount_setattr() flags */
+
+                if (mount_setattr(AT_FDCWD, prefix, AT_SYMLINK_NOFOLLOW|AT_RECURSIVE,
+                                  &(struct mount_attr) {
+                                          .attr_set = ms_flags_to_mount_attr(new_flags & flags_mask),
+                                          .attr_clr = ms_flags_to_mount_attr(~new_flags & flags_mask),
+                                  }, MOUNT_ATTR_SIZE_VER0) < 0) {
+
+                        log_debug_errno(errno, "mount_setattr() failed, falling back to classic remounting: %m");
+
+                        /* We fall through to classic behaviour if not supported (i.e. kernel < 5.12). We
+                         * also do this for all other kinds of errors since they are so many different, and
+                         * mount_setattr() has no graceful mode where it continues despite seeing errors one
+                         * some mounts, but we want that. Moreover mount_setattr() only works on the mount
+                         * point inode itself, not a non-mount point inode, and we want to support arbitrary
+                         * prefixes here. */
+
+                        if (ERRNO_IS_NOT_SUPPORTED(errno)) /* if not supported, then don't bother at all anymore */
+                                skip_mount_set_attr = true;
+                } else
+                        return 0; /* Nice, this worked! */
+        }
+
         /* Recursively remount a directory (and all its submounts) with desired flags (MS_READONLY,
          * MS_NOSUID, MS_NOEXEC). If the directory is already mounted, we reuse the mount and simply mark it
          * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write operation), ditto for other flags. If it
index 978fd45005dd55417ab21adeb1293d93644f3acb..fdf2a249ed26bce39eff5fe9aff69c3767a76703 100644 (file)
@@ -169,7 +169,7 @@ static void test_bind_remount_recursive(void) {
                         assert_se(!FLAGS_SET(svfs.f_flag, ST_RDONLY));
 
                         /* Now mark the path we currently run for read-only */
-                        assert_se(bind_remount_recursive(p, MS_RDONLY, MS_RDONLY, STRV_MAKE("/sys/kernel")) >= 0);
+                        assert_se(bind_remount_recursive(p, MS_RDONLY, MS_RDONLY, path_equal(p, "/sys") ? STRV_MAKE("/sys/kernel") : NULL) >= 0);
 
                         /* Ensure that this worked on the top-level */
                         assert_se(statvfs(p, &svfs) >= 0);