698723
From 996f88461c45e8620c5a8a0c958dc133bd02c50e Mon Sep 17 00:00:00 2001
698723
From: Jakob Unterwurzacher <jakobunt@gmail.com>
698723
Date: Mon, 30 Nov 2020 10:27:48 +0100
698723
Subject: [PATCH] mount-util: bind_remount: avoid calling statvfs
698723
698723
The commit
698723
"util: Do not clear parent mount flags when setting up namespaces"
698723
introduced a statvfs call read the flags of the original mount
698723
and have them applied to the bind mount.
698723
698723
This has two problems:
698723
698723
(1) The mount flags returned by statvfs(2) do not match the flags
698723
accepted by mount(2). For example, the value 4096 means ST_RELATIME
698723
when returned by statvfs(2), but means MS_BIND when passed to mount(2).
698723
698723
(2) A call to statvfs blocks indefinitely when ran against a disconnected
698723
network drive ( https://github.com/systemd/systemd/issues/12667 ).
698723
698723
We already use libmount to parse `/proc/self/mountinfo` but did not use the
698723
mount flag information from there. This patch changes that to use the mount
698723
flags parsed by libmount instead of calling statvfs. Only if getting the
698723
flags through libmount fails we call statvfs.
698723
698723
Fixes https://github.com/systemd/systemd/issues/12667
698723
698723
(cherry picked from commit d34a40082db3ffca8de66bfa4df50951101bdae5)
698723
698723
Resolves: #1885143
698723
---
698723
 src/basic/mount-util.c | 31 +++++++++++++++++++++++++++----
698723
 1 file changed, 27 insertions(+), 4 deletions(-)
698723
698723
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
698723
index bac1a25cc8..2cf98eaa84 100644
698723
--- a/src/basic/mount-util.c
698723
+++ b/src/basic/mount-util.c
698723
@@ -364,11 +364,34 @@ int umount_recursive(const char *prefix, int flags) {
698723
         return r ? r : n;
698723
 }
698723
 
698723
-static int get_mount_flags(const char *path, unsigned long *flags) {
698723
-        struct statvfs buf;
698723
+/* Get the mount flags for the mountpoint at "path" from "table" */
698723
+static int get_mount_flags(const char *path, unsigned long *flags, struct libmnt_table *table) {
698723
+        struct statvfs buf = {};
698723
+        struct libmnt_fs *fs = NULL;
698723
+        const char *opts = NULL;
698723
+        int r = 0;
698723
+
698723
+        fs = mnt_table_find_target(table, path, MNT_ITER_FORWARD);
698723
+        if (fs == NULL) {
698723
+                log_warning("Could not find '%s' in mount table", path);
698723
+                goto fallback;
698723
+        }
698723
+
698723
+        opts = mnt_fs_get_vfs_options(fs);
698723
+        r = mnt_optstr_get_flags(opts, flags, mnt_get_builtin_optmap(MNT_LINUX_MAP));
698723
+        if (r != 0) {
698723
+                log_warning_errno(r, "Could not get flags for '%s': %m", path);
698723
+                goto fallback;
698723
+        }
698723
 
698723
+        /* relatime is default and trying to set it in an unprivileged container causes EPERM */
698723
+        *flags &= ~MS_RELATIME;
698723
+        return 0;
698723
+
698723
+fallback:
698723
         if (statvfs(path, &buf) < 0)
698723
                 return -errno;
698723
+
698723
         *flags = buf.f_flag;
698723
         return 0;
698723
 }
698723
@@ -501,7 +524,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
698723
                                 return -errno;
698723
 
698723
                         orig_flags = 0;
698723
-                        (void) get_mount_flags(cleaned, &orig_flags);
698723
+                        (void) get_mount_flags(cleaned, &orig_flags, table);
698723
                         orig_flags &= ~MS_RDONLY;
698723
 
698723
                         if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
698723
@@ -535,7 +558,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
698723
 
698723
                         /* Try to reuse the original flag set */
698723
                         orig_flags = 0;
698723
-                        (void) get_mount_flags(x, &orig_flags);
698723
+                        (void) get_mount_flags(x, &orig_flags, table);
698723
                         orig_flags &= ~MS_RDONLY;
698723
 
698723
                         if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)