From 2ec27994f42011e90ddc769470b254ee6a338d46 Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Mon, 13 Jul 2026 15:57:07 -0300 Subject: [PATCH] harden some len checks --- mongoose.c | 43 +++++++++++++++++++++++++++---------------- src/net_builtin.c | 34 ++++++++++++++++++++++------------ src/tls_builtin.c | 9 +++++---- 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/mongoose.c b/mongoose.c index c9ff611d..cd0db554 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8493,24 +8493,31 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len]; // min header length checked at payload calculation, options are optional if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; - while (p + 1 < end && p[0] != 255) { // Parse options, get #1; RFC-2132 9 - if (p[0] == 1 && p[1] == 4 && p + 6 < end) { // Mask, 3.3 + while (p < end && p[0] != 255) { // RFC-2132 9 + if (p[0] == 0) { p++; continue; } // Pad + if ((size_t) (end - p) < 2 || (size_t) (end - p) < 2U + p[1]) break; + if (p[0] == 1) { // Mask, 3.3 + if (p[1] != 4) break; memcpy(&mask, p + 2, sizeof(mask)); - } else if (p[0] == 3 && dhcp_opt_len_ok(p[1], p, end)) { // GW, 3.5 + } else if (p[0] == 3) { // GW, 3.5 + if (!dhcp_opt_len_ok(p[1], p, end)) break; memcpy(&gw, p + 2, sizeof(gw)); ip = pkt->dhcp->yiaddr; - } else if (ifp->enable_req_dns && p[0] == 6 && - dhcp_opt_len_ok(p[1], p, end)) { // DNS, 3.8 + } else if (ifp->enable_req_dns && p[0] == 6) { // DNS, 3.8 + if (!dhcp_opt_len_ok(p[1], p, end)) break; memcpy(&dns, p + 2, sizeof(dns)); - } else if (ifp->enable_req_sntp && p[0] == 42 && - dhcp_opt_len_ok(p[1], p, end)) { // SNTP, 8.3 + } else if (ifp->enable_req_sntp && p[0] == 42) { // SNTP, 8.3 + if (!dhcp_opt_len_ok(p[1], p, end)) break; memcpy(&sntp, p + 2, sizeof(sntp)); - } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease + } else if (p[0] == 51) { // Lease + if (p[1] != 4) break; memcpy(&lease, p + 2, sizeof(lease)); lease = mg_ntohl(lease); - } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type + } else if (p[0] == 53) { // Msg Type + if (p[1] != 1) break; msgtype = p[2]; - } else if (p[0] == 54 && p[1] == 4 && p + 6 < end) { // Server id 9.7 + } else if (p[0] == 54) { // Server id 9.7 + if (p[1] != 4) break; memcpy(&owner, p + 2, sizeof(sntp)); // This is the lease owner } p += p[1] + 2; @@ -8565,8 +8572,11 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { // min header length checked at payload calculation, options are optional res.yiaddr = ifp->ip; ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 - while (p + 1 < end && p[0] != 255) { // Parse options - if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type + while (p < end && p[0] != 255) { // Parse options + if (p[0] == 0) { p++; continue; } // Pad + if ((size_t) (end - p) < 2 || (size_t) (end - p) < 2U + p[1]) break; + if (p[0] == 53) { // Message type + if (p[1] != 1) break; op = p[2]; } p += p[1] + 2; @@ -17350,6 +17360,7 @@ static int mg_tls_client_recv_hello(struct mg_connection *c) { if (rio->len < 5 + 39 + 32 + 3 + 2) goto fail; msgsz = MG_LOAD_BE16(rio->buf + 3); + if (msgsz > rio->len - 5) goto fail; mg_sha256_update(&tls->sha256, rio->buf + 5, msgsz); ext_len = MG_LOAD_BE16(rio->buf + 5 + 39 + 32 + 3); @@ -18221,7 +18232,7 @@ static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end, // Long form length uint8_t len_bytes = len & 0x7F; MG_VERBOSE(("DER INT: long form, %d length bytes", len_bytes)); - if (end - *p < len_bytes) { + if (len_bytes == 0 || len_bytes > 4 || (size_t) (end - *p) < len_bytes) { MG_VERBOSE(("DER INT: not enough bytes for length")); return -1; } @@ -18234,7 +18245,7 @@ static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end, MG_VERBOSE(("DER INT: length=%u, remaining=%d", len, (int) (end - *p))); - if (end - *p < (long) len) { + if ((size_t) (end - *p) < len) { MG_VERBOSE(("DER INT: length exceeds remaining bytes")); return -1; } @@ -18335,7 +18346,7 @@ static int mg_rsa_parse_key(const uint8_t *der, size_t dersz, // Long form length uint8_t i, len_bytes = seq_len & 0x7F; MG_VERBOSE(("Long form length: %d bytes", len_bytes)); - if (end - p < len_bytes) { + if (len_bytes == 0 || len_bytes > 4 || (size_t) (end - p) < len_bytes) { MG_ERROR(("Not enough bytes for long form length")); return -1; } @@ -18349,7 +18360,7 @@ static int mg_rsa_parse_key(const uint8_t *der, size_t dersz, MG_VERBOSE( ("SEQUENCE length: %u, total DER size: %u", seq_len, (unsigned) dersz)); - if (end - p < (long) seq_len) { + if ((size_t) (end - p) < seq_len) { MG_ERROR(("SEQUENCE length exceeds buffer")); return -1; } diff --git a/src/net_builtin.c b/src/net_builtin.c index bca3fbd4..fb0769bd 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -666,24 +666,31 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len]; // min header length checked at payload calculation, options are optional if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return; - while (p + 1 < end && p[0] != 255) { // Parse options, get #1; RFC-2132 9 - if (p[0] == 1 && p[1] == 4 && p + 6 < end) { // Mask, 3.3 + while (p < end && p[0] != 255) { // RFC-2132 9 + if (p[0] == 0) { p++; continue; } // Pad + if ((size_t) (end - p) < 2 || (size_t) (end - p) < 2U + p[1]) break; + if (p[0] == 1) { // Mask, 3.3 + if (p[1] != 4) break; memcpy(&mask, p + 2, sizeof(mask)); - } else if (p[0] == 3 && dhcp_opt_len_ok(p[1], p, end)) { // GW, 3.5 + } else if (p[0] == 3) { // GW, 3.5 + if (!dhcp_opt_len_ok(p[1], p, end)) break; memcpy(&gw, p + 2, sizeof(gw)); ip = pkt->dhcp->yiaddr; - } else if (ifp->enable_req_dns && p[0] == 6 && - dhcp_opt_len_ok(p[1], p, end)) { // DNS, 3.8 + } else if (ifp->enable_req_dns && p[0] == 6) { // DNS, 3.8 + if (!dhcp_opt_len_ok(p[1], p, end)) break; memcpy(&dns, p + 2, sizeof(dns)); - } else if (ifp->enable_req_sntp && p[0] == 42 && - dhcp_opt_len_ok(p[1], p, end)) { // SNTP, 8.3 + } else if (ifp->enable_req_sntp && p[0] == 42) { // SNTP, 8.3 + if (!dhcp_opt_len_ok(p[1], p, end)) break; memcpy(&sntp, p + 2, sizeof(sntp)); - } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease + } else if (p[0] == 51) { // Lease + if (p[1] != 4) break; memcpy(&lease, p + 2, sizeof(lease)); lease = mg_ntohl(lease); - } else if (p[0] == 53 && p[1] == 1 && p + 6 < end) { // Msg Type + } else if (p[0] == 53) { // Msg Type + if (p[1] != 1) break; msgtype = p[2]; - } else if (p[0] == 54 && p[1] == 4 && p + 6 < end) { // Server id 9.7 + } else if (p[0] == 54) { // Server id 9.7 + if (p[1] != 4) break; memcpy(&owner, p + 2, sizeof(sntp)); // This is the lease owner } p += p[1] + 2; @@ -738,8 +745,11 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) { // min header length checked at payload calculation, options are optional res.yiaddr = ifp->ip; ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1 - while (p + 1 < end && p[0] != 255) { // Parse options - if (p[0] == 53 && p[1] == 1 && p + 2 < end) { // Message type + while (p < end && p[0] != 255) { // Parse options + if (p[0] == 0) { p++; continue; } // Pad + if ((size_t) (end - p) < 2 || (size_t) (end - p) < 2U + p[1]) break; + if (p[0] == 53) { // Message type + if (p[1] != 1) break; op = p[2]; } p += p[1] + 2; diff --git a/src/tls_builtin.c b/src/tls_builtin.c index 9b70ae59..b42a514f 100644 --- a/src/tls_builtin.c +++ b/src/tls_builtin.c @@ -1321,6 +1321,7 @@ static int mg_tls_client_recv_hello(struct mg_connection *c) { if (rio->len < 5 + 39 + 32 + 3 + 2) goto fail; msgsz = MG_LOAD_BE16(rio->buf + 3); + if (msgsz > rio->len - 5) goto fail; mg_sha256_update(&tls->sha256, rio->buf + 5, msgsz); ext_len = MG_LOAD_BE16(rio->buf + 5 + 39 + 32 + 3); @@ -2192,7 +2193,7 @@ static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end, // Long form length uint8_t len_bytes = len & 0x7F; MG_VERBOSE(("DER INT: long form, %d length bytes", len_bytes)); - if (end - *p < len_bytes) { + if (len_bytes == 0 || len_bytes > 4 || (size_t) (end - *p) < len_bytes) { MG_VERBOSE(("DER INT: not enough bytes for length")); return -1; } @@ -2205,7 +2206,7 @@ static int mg_rsa_parse_der_int(const uint8_t **p, const uint8_t *end, MG_VERBOSE(("DER INT: length=%u, remaining=%d", len, (int) (end - *p))); - if (end - *p < (long) len) { + if ((size_t) (end - *p) < len) { MG_VERBOSE(("DER INT: length exceeds remaining bytes")); return -1; } @@ -2306,7 +2307,7 @@ static int mg_rsa_parse_key(const uint8_t *der, size_t dersz, // Long form length uint8_t i, len_bytes = seq_len & 0x7F; MG_VERBOSE(("Long form length: %d bytes", len_bytes)); - if (end - p < len_bytes) { + if (len_bytes == 0 || len_bytes > 4 || (size_t) (end - p) < len_bytes) { MG_ERROR(("Not enough bytes for long form length")); return -1; } @@ -2320,7 +2321,7 @@ static int mg_rsa_parse_key(const uint8_t *der, size_t dersz, MG_VERBOSE( ("SEQUENCE length: %u, total DER size: %u", seq_len, (unsigned) dersz)); - if (end - p < (long) seq_len) { + if ((size_t) (end - p) < seq_len) { MG_ERROR(("SEQUENCE length exceeds buffer")); return -1; }