]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: make sure we use the correct mount flag when re-mounting bind mounts 14532/head
authorLennart Poettering <lennart@poettering.net>
Thu, 9 Jan 2020 14:06:06 +0000 (15:06 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 Jan 2020 14:18:08 +0000 (15:18 +0100)
When in a userns environment we cannot take away per-mount point flags
set on a mount point that was passed to us. Hence we need to be careful
to always check the actual mount flags in place and manipulate only
those flags of them that we actually want to change and not reset more
as side-effect.

We mostly got this right already in
bind_remount_recursive_with_mountinfo(), but didn't in the simpler
bind_remount_one_with_mountinfo(). Catch up.

(The old code assumed that the MountEntry.flags field contained the
right flag settings, but it actually doesn't for new mounts we just
established as for those mount() establishes the initial flags for us,
and we have to read them back to figure out which ones the kernel
picked.)

Fixes: #13622
src/core/namespace.c
src/shared/mount-util.c
src/shared/mount-util.h

index fee4c98096460a1631502199b9d28208386ab5db..d4702cdd9639f44405a7f4731ff199217b08127c 100644 (file)
@@ -1063,14 +1063,6 @@ static int apply_mount(
         return 0;
 }
 
-/* Change per-mount flags on an existing mount */
-static int bind_remount_one(const char *path, unsigned long orig_flags, unsigned long new_flags, unsigned long flags_mask) {
-        if (mount(NULL, path, NULL, (orig_flags & ~flags_mask) | MS_REMOUNT | MS_BIND | new_flags, NULL) < 0)
-                return -errno;
-
-        return 0;
-}
-
 static int make_read_only(const MountEntry *m, char **blacklist, FILE *proc_self_mountinfo) {
         unsigned long new_flags = 0, flags_mask = 0;
         bool submounts = false;
@@ -1102,7 +1094,7 @@ static int make_read_only(const MountEntry *m, char **blacklist, FILE *proc_self
         if (submounts)
                 r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, blacklist, proc_self_mountinfo);
         else
-                r = bind_remount_one(mount_entry_path(m), m->flags, new_flags, flags_mask);
+                r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo);
 
         /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked
          * read-only already stays this way. This improves compatibility with container managers, where we
index c74f391b06e2498ea29df60ef743308cffccd54d..32c5332822f01832a90ce07710a43432aaf81a1a 100644 (file)
@@ -326,6 +326,38 @@ int bind_remount_recursive(
         return bind_remount_recursive_with_mountinfo(prefix, new_flags, flags_mask, blacklist, proc_self_mountinfo);
 }
 
+int bind_remount_one_with_mountinfo(
+                const char *path,
+                unsigned long new_flags,
+                unsigned long flags_mask,
+                FILE *proc_self_mountinfo) {
+
+        _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
+        unsigned long orig_flags = 0;
+        int r;
+
+        assert(path);
+        assert(proc_self_mountinfo);
+
+        rewind(proc_self_mountinfo);
+
+        table = mnt_new_table();
+        if (!table)
+                return -ENOMEM;
+
+        r = mnt_table_parse_stream(table, proc_self_mountinfo, "/proc/self/mountinfo");
+        if (r < 0)
+                return r;
+
+        /* Try to reuse the original flag set */
+        (void) get_mount_flags(table, path, &orig_flags);
+
+        if (mount(NULL, path, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
+                return -errno;
+
+        return 0;
+}
+
 int mount_move_root(const char *path) {
         assert(path);
 
index 9a8d073631d237ec676fee9984a268bcd26eb813..06fddacf16d03b60350abcc1cfefa1aa3528d658 100644 (file)
@@ -10,6 +10,7 @@ int repeat_unmount(const char *path, int flags);
 int umount_recursive(const char *target, int flags);
 int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist);
 int bind_remount_recursive_with_mountinfo(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist, FILE *proc_self_mountinfo);
+int bind_remount_one_with_mountinfo(const char *path, unsigned long new_flags, unsigned long flags_mask, FILE *proc_self_mountinfo);
 
 int mount_move_root(const char *path);