]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
namespace: store and use original MountEntry paths when prefixing 18620/head
authorLuca Boccassi <luca.boccassi@microsoft.com>
Thu, 28 Jan 2021 17:02:33 +0000 (17:02 +0000)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Tue, 16 Feb 2021 14:33:23 +0000 (14:33 +0000)
Some paths (eg: mount_tmpfs) simply assumed that prefixing always
happens and it always stores the original path in path_const, and
the prefixed path in path_malloc.
But if a MountEntry is set up in a helper function and thus uses
only _malloc struct members, this assumption doesn't hold and there's
a crash.

Refactor so that prefixing is done with a helper which stores the
original path in a separate struct member, and accessing it also
uses a helper which does the right thing.

src/core/namespace.c

index d98a53a39afe2a29326ca7c3578356fe7c1396fc..285a87dfcdd1feae224d4d65840cc68f0470c23f 100644 (file)
@@ -72,6 +72,8 @@ typedef struct MountEntry {
         bool exec:1;              /* Shall clear MS_NOEXEC on the mount itself */
         bool applied:1;           /* Already applied */
         char *path_malloc;        /* Use this instead of 'path_const' if we had to allocate memory */
+        const char *unprefixed_path_const; /* If the path was amended with a prefix, these will save the original */
+        char *unprefixed_path_malloc;
         const char *source_const; /* The source path, for bind mounts or images */
         char *source_malloc;
         const char *options_const;/* Mount options for tmpfs */
@@ -231,6 +233,29 @@ static const char *mount_entry_path(const MountEntry *p) {
         return p->path_malloc ?: p->path_const;
 }
 
+static const char *mount_entry_unprefixed_path(const MountEntry *p) {
+        assert(p);
+
+        /* Returns the unprefixed path (ie: before prefix_where_needed() ran), if any */
+
+        return p->unprefixed_path_malloc ?: p->unprefixed_path_const ?: mount_entry_path(p);
+}
+
+static void mount_entry_consume_prefix(MountEntry *p, char *new_path) {
+        assert(p);
+        assert(p->path_malloc || p->path_const);
+        assert(new_path);
+
+        /* Saves current path in unprefixed_ variable, and takes over new_path */
+
+        free_and_replace(p->unprefixed_path_malloc, p->path_malloc);
+        /* If we didn't have a path on the heap, then it's a static one */
+        if (!p->unprefixed_path_malloc)
+                p->unprefixed_path_const = p->path_const;
+        p->path_malloc = new_path;
+        p->has_prefix = true;
+}
+
 static bool mount_entry_read_only(const MountEntry *p) {
         assert(p);
 
@@ -265,6 +290,7 @@ static void mount_entry_done(MountEntry *p) {
         assert(p);
 
         p->path_malloc = mfree(p->path_malloc);
+        p->unprefixed_path_malloc = mfree(p->unprefixed_path_malloc);
         p->source_malloc = mfree(p->source_malloc);
         p->options_malloc = mfree(p->options_malloc);
         p->image_options = mount_options_free_all(p->image_options);
@@ -492,8 +518,7 @@ static int prefix_where_needed(MountEntry *m, size_t n, const char *root_directo
                 if (!s)
                         return -ENOMEM;
 
-                free_and_replace(m[i].path_malloc, s);
-                m[i].has_prefix = true;
+                mount_entry_consume_prefix(&m[i], s);
         }
 
         return 0;
@@ -946,7 +971,7 @@ static int mount_tmpfs(const MountEntry *m) {
         assert(m);
 
         entry_path = mount_entry_path(m);
-        inner_path = m->path_const;
+        inner_path = mount_entry_unprefixed_path(m);
 
         /* First, get rid of everything that is below if there is anything. Then, overmount with our new tmpfs */
 
@@ -1017,8 +1042,7 @@ static int follow_symlink(
 
         log_debug("Followed mount entry path symlink %s → %s.", mount_entry_path(m), target);
 
-        free_and_replace(m->path_malloc, target);
-        m->has_prefix = true;
+        mount_entry_consume_prefix(m, TAKE_PTR(target));
 
         m->n_followed ++;