]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
blockdev-util: fix access to possibly invalidated dirent struct
authorLennart Poettering <lennart@poettering.net>
Fri, 19 Mar 2021 10:14:52 +0000 (11:14 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 19 Mar 2021 17:13:17 +0000 (18:13 +0100)
Let's copy out the string we need from the dirent, there's no reason to
believe the dirent struct might live for longer than one loop iteration.

src/basic/blockdev-util.c

index 0f1e30ccd971ce6a2880858cf79a5ce2874df334..2f3f1aecc8a99c277422940abebabc47d46db13f 100644 (file)
@@ -94,7 +94,8 @@ int block_get_originating(dev_t dt, dev_t *ret) {
         _cleanup_closedir_ DIR *d = NULL;
         _cleanup_free_ char *t = NULL;
         char p[SYS_BLOCK_PATH_MAX("/slaves")];
-        struct dirent *de, *found = NULL;
+        _cleanup_free_ char *first_found = NULL;
+        struct dirent *de;
         const char *q;
         dev_t devt;
         int r;
@@ -115,20 +116,22 @@ int block_get_originating(dev_t dt, dev_t *ret) {
                 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
                         continue;
 
-                if (found) {
+                if (first_found) {
                         _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
 
-                        /* We found a device backed by multiple other devices. We don't really support automatic
-                         * discovery on such setups, with the exception of dm-verity partitions. In this case there are
-                         * two backing devices: the data partition and the hash partition. We are fine with such
-                         * setups, however, only if both partitions are on the same physical device. Hence, let's
-                         * verify this. */
+                        /* We found a device backed by multiple other devices. We don't really support
+                         * automatic discovery on such setups, with the exception of dm-verity partitions. In
+                         * this case there are two backing devices: the data partition and the hash
+                         * partition. We are fine with such setups, however, only if both partitions are on
+                         * the same physical device.  Hence, let's verify this by iterating over every node
+                         * in the 'slaves/' directory and comparing them with the first that gets returned by
+                         * readdir(), to ensure they all point to the same device. */
 
                         u = path_join(p, de->d_name, "../dev");
                         if (!u)
                                 return -ENOMEM;
 
-                        v = path_join(p, found->d_name, "../dev");
+                        v = path_join(p, first_found, "../dev");
                         if (!v)
                                 return -ENOMEM;
 
@@ -144,15 +147,17 @@ int block_get_originating(dev_t dt, dev_t *ret) {
                          * different physical devices, and we don't support that. */
                         if (!streq(a, b))
                                 return -ENOTUNIQ;
+                } else {
+                        first_found = strdup(de->d_name);
+                        if (!first_found)
+                                return -ENOMEM;
                 }
-
-                found = de;
         }
 
-        if (!found)
+        if (!first_found)
                 return -ENOENT;
 
-        q = strjoina(p, "/", found->d_name, "/dev");
+        q = strjoina(p, "/", first_found, "/dev");
 
         r = read_one_line_file(q, &t);
         if (r < 0)