From: Luca Boccassi Date: Wed, 15 Jul 2026 11:06:02 +0000 (+0100) Subject: clonesetup: check target table size for overflow X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5c94b43641e57afbda4fd9e2a0b5fb2a366829e;p=thirdparty%2Fsystemd.git clonesetup: check target table size for overflow 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 --- diff --git a/src/clonesetup/clonesetup-ioctl.c b/src/clonesetup/clonesetup-ioctl.c index 5accb114e45..e8f76888804 100644 --- a/src/clonesetup/clonesetup-ioctl.c +++ b/src/clonesetup/clonesetup-ioctl.c @@ -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(¶ms_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));