]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
clonesetup: check target table size for overflow 43035/head
authorLuca Boccassi <luca.boccassi@gmail.com>
Wed, 15 Jul 2026 11:06:02 +0000 (12:06 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 15 Jul 2026 16:51:48 +0000 (17:51 +0100)
The target parameter length is added to two headers and aligned before
allocation. Check each operation and reject payloads that cannot be
represented by the device-mapper ioctl header.

CID#1663846

Follow-up for 104970a8bd7a3b53067f6e50283183406a579f0b

src/clonesetup/clonesetup-ioctl.c

index 5accb114e45703b31e818dbb19488617e3825173..e8f76888804241705f04dd2f0885de13e07a8ea8 100644 (file)
@@ -101,16 +101,26 @@ static int dm_clone_create(const char *name) {
 /* Second dm ioctl needed to create a device. */
 static int dm_clone_load_table(const char *name, uint64_t size_sectors, const char *target_params) {
         char *params_buf;
-        size_t params_len, dm_size;
+        size_t params_len, target_size, dm_size;
         _cleanup_free_ struct dm_ioctl *dm = NULL;
         struct dm_target_spec *tgt;
 
         assert(name);
         assert(target_params);
 
-        params_len = strlen(target_params) + 1;
+        params_len = strlen(target_params);
+        target_size = sizeof(struct dm_target_spec);
+        if (!ADD_SAFE(&params_len, params_len, 1) ||
+            !ADD_SAFE(&target_size, target_size, params_len))
+                return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "DM target parameters too long.");
+
         /* ensure that dm_size is always aligned, so it makes the buffer actually match what .next claims */
-        dm_size = ALIGN8(sizeof(struct dm_ioctl)) + ALIGN8(sizeof(struct dm_target_spec) + params_len);
+        target_size = ALIGN8(target_size);
+        dm_size = ALIGN8(sizeof(struct dm_ioctl));
+        if (target_size == SIZE_MAX ||
+            !ADD_SAFE(&dm_size, dm_size, target_size))
+                return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "DM target parameters too long.");
+
         dm = malloc0(dm_size);
         if (!dm)
                 return log_oom();
@@ -125,7 +135,7 @@ static int dm_clone_load_table(const char *name, uint64_t size_sectors, const ch
                 /* Per linux/dm-ioctl.h: next is the byte offset from this dm_target_spec to the next one,
                  * rounded up to 8-byte alignment. With target_count == 1 next == 0 works, but set it
                  * correctly to avoid silent breakage if a second target is ever added. */
-                .next = ALIGN8(sizeof(struct dm_target_spec) + params_len),
+                .next = target_size,
         };
         strncpy(tgt->target_type, "clone", sizeof(tgt->target_type));