From df965878c72805da41be99b26e41235827f58cc0 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 15 Jul 2026 12:07:20 +0100 Subject: [PATCH 1/3] test: make NSS IPv4 tuple bounds explicit gaih_addrtuple.addr has room for an IPv6 address, while IPv4 uses only the first struct in_addr. Express the remaining range directly in terms of that type so static analysis can prove the access remains within the array. CID#1663899 Follow-up for 2d85bba6b9ddd20b74992c740fab7f82c9c03f01 --- src/test/test-nss-hosts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c index 61f9b153f8..761677430a 100644 --- a/src/test/test-nss-hosts.c +++ b/src/test/test-nss-hosts.c @@ -74,8 +74,8 @@ static void assert_myhostname_gaih_addrtuples(const struct gaih_addrtuple *tuple for (const struct gaih_addrtuple *it = tuples; it; it = it->next) if (it->family == AF_INET) assert_se(memeqzero( - (const uint8_t*) it->addr + FAMILY_ADDRESS_SIZE(AF_INET), - sizeof(it->addr) - FAMILY_ADDRESS_SIZE(AF_INET))); + (const uint8_t*) it->addr + sizeof(struct in_addr), + sizeof(it->addr) - sizeof(struct in_addr))); } static void print_struct_hostent(struct hostent *host, const char *canon) { From 280b88038827ee66219b2de4e9ed363481df6e03 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 15 Jul 2026 12:05:04 +0100 Subject: [PATCH 2/3] clonesetup: check target message size for overflow Build the variable-length ioctl size with checked additions. Reject an oversized message before allocating and copying it into the buffer. CID#1663845 Follow-up for 104970a8bd7a3b53067f6e50283183406a579f0b --- src/clonesetup/clonesetup-ioctl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/clonesetup/clonesetup-ioctl.c b/src/clonesetup/clonesetup-ioctl.c index 73c52e6e99..5accb114e4 100644 --- a/src/clonesetup/clonesetup-ioctl.c +++ b/src/clonesetup/clonesetup-ioctl.c @@ -55,6 +55,9 @@ static int dm_ioctl_run(const char *name, uint32_t cmd, struct dm_ioctl *data, s assert(data); assert(data_size >= sizeof(struct dm_ioctl)); + if (data_size > UINT32_MAX) + return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "DM ioctl data too large."); + dm->version[0] = DM_VERSION_MAJOR; dm->version[1] = DM_VERSION_MINOR; dm->version[2] = DM_VERSION_PATCHLEVEL; @@ -219,9 +222,14 @@ int dm_clone_send_message(const char *name, const char *message) { assert(name); assert(message); - msg_len = strlen(message) + 1; + msg_len = strlen(message); /* need to take into account both headers in size calculation */ - dm_size = ALIGN8(sizeof(struct dm_ioctl)) + sizeof(struct dm_target_msg) + msg_len; + dm_size = ALIGN8(sizeof(struct dm_ioctl)); + if (!ADD_SAFE(&msg_len, msg_len, 1) || + !ADD_SAFE(&dm_size, dm_size, sizeof(struct dm_target_msg)) || + !ADD_SAFE(&dm_size, dm_size, msg_len)) + return log_error_errno(SYNTHETIC_ERRNO(EOVERFLOW), "DM target message too long."); + dm = malloc0(dm_size); if (!dm) return log_oom(); From b5c94b43641e57afbda4fd9e2a0b5fb2a366829e Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 15 Jul 2026 12:06:02 +0100 Subject: [PATCH 3/3] 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 --- src/clonesetup/clonesetup-ioctl.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/clonesetup/clonesetup-ioctl.c b/src/clonesetup/clonesetup-ioctl.c index 5accb114e4..e8f7688880 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));