summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-03-19 11:14:52 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-03-23 01:35:34 +0100
commit928ab001fb77fea95ee833fe27e1913f043587ff (patch)
treea0401881c98455c54ba157a7c813523f71421364
parentb132bca9f6dc6ed4965c0ac48bac90e9fc443a9e (diff)
downloadsystemd-928ab001fb77fea95ee833fe27e1913f043587ff.tar.gz
blockdev-util: fix access to possibly invalidated dirent struct
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. (cherry picked from commit c68fc3514ddd53abd7ecfd22afb07aa0ad785c5c)
-rw-r--r--src/basic/blockdev-util.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/src/basic/blockdev-util.c b/src/basic/blockdev-util.c
index 0f1e30ccd9..2f3f1aecc8 100644
--- a/src/basic/blockdev-util.c
+++ b/src/basic/blockdev-util.c
@@ -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)