From: W.C.A. Wijngaards Date: Tue, 24 Mar 2026 07:45:52 +0000 (+0100) Subject: - Fix to check for invalid http content length and chunk size, X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=315077b9e655ac60b0aa9fbd3e7eec343e2c47da;p=thirdparty%2Funbound.git - Fix to check for invalid http content length and chunk size, and to check the RR rdata field lengths when decompressing and inserting RRs from an authority zone transfer. This stops large memory use and heap buffer-overflow read errors. Thanks to Haruto Kimura (Stella) for the report. --- diff --git a/doc/Changelog b/doc/Changelog index f92de7fd0..5981ac2fa 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,10 @@ +24 March 2026: Wouter + - Fix to check for invalid http content length and chunk size, + and to check the RR rdata field lengths when decompressing and + inserting RRs from an authority zone transfer. This stops + large memory use and heap buffer-overflow read errors. Thanks + to Haruto Kimura (Stella) for the report. + 20 March 2026: Wouter - Fix for testcode pktview to check buffer size and log errors. diff --git a/services/authzone.c b/services/authzone.c index 3965b5e17..9778cf1b7 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -1384,6 +1384,9 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt, len = 0; break; case LDNS_RDF_TYPE_STR: + /* Check rdlen for resilience, because it is + * checked above, that rdlen > 0 */ + if(rdlen < 1) return 0; /* malformed */ len = rd[0] + 1; break; default: @@ -1391,6 +1394,8 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt, break; } if(len) { + if(len > rdlen) + return 0; /* malformed */ if(!sldns_buffer_available(buf, len)) return 0; /* too long for buffer */ sldns_buffer_write(buf, rd, len); diff --git a/util/netevent.c b/util/netevent.c index 01ef54dfe..a86e22518 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -4870,8 +4870,17 @@ http_process_initial_header(struct comm_point* c) return 0; } } else if(strncasecmp(line, "Content-Length: ", 16) == 0) { - if(!c->http_is_chunked) - c->tcp_byte_count = (size_t)atoi(line+16); + if(!c->http_is_chunked) { + char* end = NULL; + long long cl; + errno = 0; + cl = strtoll(line+16, &end, 10); + if(end == line+16 || errno != 0 || cl < 0) { + verbose(VERB_ALGO, "http invalid Content-Length: " ARG_LL "d", cl); + return 0; /* reject */ + } + c->tcp_byte_count = (size_t)cl; + } } else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) { c->tcp_byte_count = 0; c->http_is_chunked = 1; @@ -4927,9 +4936,15 @@ http_process_chunk_header(struct comm_point* c) if(c->http_in_chunk_headers == 1) { /* read chunked start line */ char* end = NULL; - c->tcp_byte_count = (size_t)strtol(line, &end, 16); - if(end == line) + long chunk_sz; + errno = 0; + chunk_sz = strtol(line, &end, 16); + if(end == line || errno != 0 || chunk_sz < 0) { + verbose(VERB_ALGO, "http invalid chunk size: %ld", + chunk_sz); return 0; + } + c->tcp_byte_count = (size_t)chunk_sz; c->http_in_chunk_headers = 0; /* remove header text from front of buffer */ http_moveover_buffer(c->buffer);