summaryrefslogtreecommitdiff
path: root/src/basic/mount-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-09-25 10:40:51 +0200
committerSven Eden <yamakuzure@gmx.net>2017-07-05 08:50:54 +0200
commit666d14067ba8abed303f65fa8a86bd2e7ff7b3b1 (patch)
tree6571138d1661c89a07bf3004e9f0c8192911520c /src/basic/mount-util.c
parent7dd230537883c50e572752574e08c94aef5efa7f (diff)
namespace: rework how ReadWritePaths= is applied
Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
Diffstat (limited to 'src/basic/mount-util.c')
-rw-r--r--src/basic/mount-util.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index c85c47301..046885b23 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -288,10 +288,12 @@ int umount_recursive(const char *prefix, int flags) {
continue;
if (umount2(p, flags) < 0) {
- r = -errno;
+ r = log_debug_errno(errno, "Failed to umount %s: %m", p);
continue;
}
+ log_debug("Successfully unmounted %s", p);
+
again = true;
n++;
@@ -312,24 +314,21 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
return 0;
}
-int bind_remount_recursive(const char *prefix, bool ro) {
+int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
_cleanup_set_free_free_ Set *done = NULL;
_cleanup_free_ char *cleaned = NULL;
int r;
- /* Recursively remount a directory (and all its submounts)
- * read-only or read-write. 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). If it isn't we first make it one. Afterwards we
- * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all
- * submounts we can access, too. When mounts are stacked on
- * the same mount point we only care for each individual
- * "top-level" mount on each point, as we cannot
- * influence/access the underlying mounts anyway. We do not
- * have any effect on future submounts that might get
- * propagated, they migt be writable. This includes future
- * submounts that have been triggered via autofs. */
+ /* Recursively remount a directory (and all its submounts) read-only or read-write. 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). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
+ * all submounts we can access, too. When mounts are stacked on the same mount point we only care for each
+ * individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We
+ * do not have any effect on future submounts that might get propagated, they migt be writable. This includes
+ * future submounts that have been triggered via autofs.
+ *
+ * If the "blacklist" parameter is specified it may contain a list of subtrees to exclude from the
+ * remount operation. Note that we'll ignore the blacklist for the top-level path. */
cleaned = strdup(prefix);
if (!cleaned)
@@ -386,6 +385,33 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (r < 0)
return r;
+ if (!path_startswith(p, cleaned))
+ continue;
+
+ /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount we shall
+ * operate on. */
+ if (!path_equal(cleaned, p)) {
+ bool blacklisted = false;
+ char **i;
+
+ STRV_FOREACH(i, blacklist) {
+
+ if (path_equal(*i, cleaned))
+ continue;
+
+ if (!path_startswith(*i, cleaned))
+ continue;
+
+ if (path_startswith(p, *i)) {
+ blacklisted = true;
+ log_debug("Not remounting %s, because blacklisted by %s, called for %s", p, *i, cleaned);
+ break;
+ }
+ }
+ if (blacklisted)
+ continue;
+ }
+
/* Let's ignore autofs mounts. If they aren't
* triggered yet, we want to avoid triggering
* them, as we don't make any guarantees for
@@ -397,12 +423,9 @@ int bind_remount_recursive(const char *prefix, bool ro) {
continue;
}
- if (path_startswith(p, cleaned) &&
- !set_contains(done, p)) {
-
+ if (!set_contains(done, p)) {
r = set_consume(todo, p);
p = NULL;
-
if (r == -EEXIST)
continue;
if (r < 0)
@@ -419,8 +442,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (!set_contains(done, cleaned) &&
!set_contains(todo, cleaned)) {
- /* The prefix directory itself is not yet a
- * mount, make it one. */
+ /* The prefix directory itself is not yet a mount, make it one. */
if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
return -errno;
@@ -431,6 +453,8 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
return -errno;
+ log_debug("Made top-level directory %s a mount point.", prefix);
+
x = strdup(cleaned);
if (!x)
return -ENOMEM;
@@ -448,8 +472,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (r < 0)
return r;
- /* Deal with mount points that are obstructed by a
- * later mount */
+ /* Deal with mount points that are obstructed by a later mount */
r = path_is_mount_point(x, 0);
if (r == -ENOENT || r == 0)
continue;
@@ -464,6 +487,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
return -errno;
+ log_debug("Remounted %s read-only.", x);
}
}
}