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