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