]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix to check for invalid http content length and chunk size,
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 24 Mar 2026 07:45:52 +0000 (08:45 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 24 Mar 2026 07:45:52 +0000 (08:45 +0100)
  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.

doc/Changelog
services/authzone.c
util/netevent.c

index f92de7fd0ba239200cad81bb670a1e994039fb2c..5981ac2fa7fab690644f0bc0280ef074adf64d5a 100644 (file)
@@ -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.
 
index 3965b5e171801717ed967e3d893ee580422eb75c..9778cf1b79a23f130c62f79485714f5637419a54 100644 (file)
@@ -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);
index 01ef54dfe17639b230142ff206b9c10b6d870086..a86e22518fb81c59b4e9d5b119e3c58accc1f2f7 100644 (file)
@@ -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);