From 92feb880e00577c69b566c54db15dd68360bdca4 Mon Sep 17 00:00:00 2001 From: Koda Reef Date: Sun, 22 Mar 2026 23:57:21 +0000 Subject: [PATCH] Add integer overflow checks to 6 allocation size calculations 1. common/tree.c: Change new_len from signed int to unsigned int and add UINT_MAX/2 check before doubling. Signed int overflow in the doubling loop is undefined behavior that could cause infinite loop. 2. common/parse.c: Check universe_max > INT_MAX/2 before doubling the option space array. 3. omapip/alloc.c: Check count * sizeof(omapi_addr_t) + sizeof(list) does not overflow size_t before allocation. 4. omapip/array.c: Check (max + delta) * sizeof(char *) does not overflow size_t before array growth allocation. 5. common/options.c:3664: Check length * 4 + 3 does not overflow unsigned int in FQDN option buffer allocation. 6. common/options.c:2738: Check num_opts * 2 does not overflow int in server ORO buffer allocation. --- common/options.c | 10 +++++++++- common/parse.c | 2 ++ common/tree.c | 11 +++++++---- omapip/alloc.c | 2 ++ omapip/array.c | 3 +++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/common/options.c b/common/options.c index 25450e1df..f55daac5e 100644 --- a/common/options.c +++ b/common/options.c @@ -2735,6 +2735,9 @@ build_server_oro(struct data_string *server_oro, * Allocate space. */ memset(server_oro, 0, sizeof(*server_oro)); + if (num_opts > INT_MAX / 2) { + log_fatal("server ORO option count overflow"); + } if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) { log_fatal("no memory to build server ORO"); } @@ -3661,7 +3664,12 @@ fqdn6_universe_decode(struct option_state *options, * first to calculate the precise size or reallocate to a smaller * buffer later, either of which is a bigger performance hit than * just doing a generous allocation. */ - unsigned bp_size = 3 + (length * 4); + unsigned bp_size; + if (length > (UINT_MAX - 3) / 4) { + log_error("dhcp6.fqdn option length overflow."); + return 0; + } + bp_size = 3 + (length * 4); if (!buffer_allocate(&bp, bp_size, MDL)) { log_error("No memory for dhcp6.fqdn option buffer."); diff --git a/common/parse.c b/common/parse.c index b123a6c7e..924415442 100644 --- a/common/parse.c +++ b/common/parse.c @@ -1481,6 +1481,8 @@ void parse_option_space_decl (cfile) } nu -> index = universe_count++; if (nu -> index >= universe_max) { + if (universe_max > INT_MAX / 2) + log_fatal ("Option space array too large."); ua = dmalloc (universe_max * 2 * sizeof *ua, MDL); if (!ua) log_fatal ("No memory to expand option space array."); diff --git a/common/tree.c b/common/tree.c index 681733542..6657f6088 100644 --- a/common/tree.c +++ b/common/tree.c @@ -58,7 +58,7 @@ data_string_sprintfa(struct data_string *ds, const char *fmt, ...) { int cur_strlen; int max; int vsnprintf_ret; - int new_len; + unsigned int new_len; struct buffer *tmp_buffer; /* @@ -97,10 +97,13 @@ data_string_sprintfa(struct data_string *ds, const char *fmt, ...) { /* * Figure out a size big enough. */ - new_len = ds->len * 2; - while (new_len <= cur_strlen + vsnprintf_ret) { + new_len = ds->len; + do { + if (new_len > UINT_MAX / 2) { + return 0; + } new_len *= 2; - } + } while (new_len <= (unsigned int)(cur_strlen + vsnprintf_ret)); /* * Create a new buffer and fill it. diff --git a/omapip/alloc.c b/omapip/alloc.c index d13d3d7eb..0f458a6cb 100644 --- a/omapip/alloc.c +++ b/omapip/alloc.c @@ -1106,6 +1106,8 @@ isc_result_t omapi_addr_list_new (omapi_addr_list_t **d, unsigned count, { omapi_addr_list_t *new; + if (count > (SIZE_MAX - sizeof (omapi_addr_list_t)) / sizeof (omapi_addr_t)) + return ISC_R_NOMEMORY; new = dmalloc ((count * sizeof (omapi_addr_t)) + sizeof (omapi_addr_list_t), file, line); if (!new) diff --git a/omapip/array.c b/omapip/array.c index 600d78350..593b8f5df 100644 --- a/omapip/array.c +++ b/omapip/array.c @@ -102,6 +102,9 @@ isc_result_t omapi_array_set (omapi_array_t *array, void *ptr, int index, space in the array, make more space in the array. */ if (array -> max <= index) { delta = index - array -> max + 10; + if ((unsigned)delta > SIZE_MAX / sizeof (char *) || + (unsigned)(array -> max + delta) > SIZE_MAX / sizeof (char *)) + return ISC_R_NOMEMORY; newbuf = dmalloc ((array -> max + delta) * sizeof (char *), file, line); if (!newbuf)