diff --git a/src/clonesetup/clonesetup-ioctl.c b/src/clonesetup/clonesetup-ioctl.c index 73c52e6e99..e8f7688880 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; @@ -98,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(); @@ -122,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)); @@ -219,9 +232,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(); 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) {