From: Sascha Hauer <s.hauer@pengutronix.de>
To: BAREBOX <barebox@lists.infradead.org>
Cc: "Claude Opus 4.6 \(1M context\)" <noreply@anthropic.com>
Subject: [PATCH v2 1/3] net: dhcp: add bounds checking to DHCP option parsing
Date: Thu, 02 Apr 2026 08:59:57 +0200 [thread overview]
Message-ID: <20260402-net-dhcp-buffer-overflows-v2-1-fe4ca7c4b718@pengutronix.de> (raw)
In-Reply-To: <20260402-net-dhcp-buffer-overflows-v2-0-fe4ca7c4b718@pengutronix.de>
dhcp_message_type() walks DHCP options with no end-of-buffer check. A
malicious DHCP server can craft a packet without a 0xff terminator or
with large option length fields, causing reads past the packet buffer
boundary.
Similarly, dhcp_options_process() computes its end bound from fixed
struct sizes rather than the actual received packet length, which could
parse past the real packet data.
Fix both functions by passing the actual packet length and computing
proper bounds. Validate that option type and length bytes are within
bounds before reading them, and that the option data region doesn't
extend past the packet.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
net/dhcp.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/net/dhcp.c b/net/dhcp.c
index e25b64842d..1cb3fef5d7 100644
--- a/net/dhcp.c
+++ b/net/dhcp.c
@@ -318,30 +318,39 @@ static void dhcp_options_handle(unsigned char option, void *popt,
}
}
-static void dhcp_options_process(unsigned char *popt, struct bootp *bp)
+static void dhcp_options_process(unsigned char *popt, struct bootp *bp,
+ unsigned int len)
{
- unsigned char *end = popt + sizeof(*bp) + OPT_SIZE;
+ unsigned char *end = (unsigned char *)bp + len;
int oplen;
unsigned char option;
- while (popt < end && *popt != 0xff) {
+ while (popt + 1 < end && *popt != 0xff) {
oplen = *(popt + 1);
option = *popt;
+ if (popt + 2 + oplen > end)
+ break;
+
dhcp_options_handle(option, popt + 2, oplen, bp);
popt += oplen + 2; /* Process next option */
}
}
-static int dhcp_message_type(unsigned char *popt)
+static int dhcp_message_type(unsigned char *popt, unsigned int len)
{
+ unsigned char *end = popt + len;
+
+ if (len < 4)
+ return -1;
+
if (net_read_uint32((uint32_t *)popt) != htonl(BOOTP_VENDOR_MAGIC))
return -1;
popt += 4;
- while (*popt != 0xff) {
- if (*popt == 53) /* DHCP Message Type */
+ while (popt + 1 < end && *popt != 0xff) {
+ if (*popt == 53 && popt + 2 < end)
return *(popt + 2);
popt += *(popt + 1) + 2; /* Scan through all options */
}
@@ -415,7 +424,7 @@ static void dhcp_handler(void *ctx, char *packet, unsigned int len)
dhcp_state = REQUESTING;
if (net_read_uint32(&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
- dhcp_options_process((u8 *)&bp->bp_vend[4], bp);
+ dhcp_options_process((u8 *)&bp->bp_vend[4], bp, len);
bootp_copy_net_params(bp); /* Store net params from reply */
@@ -426,9 +435,10 @@ static void dhcp_handler(void *ctx, char *packet, unsigned int len)
case REQUESTING:
debug("%s: State REQUESTING\n", __func__);
- if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK ) {
+ if (dhcp_message_type((u8 *)bp->bp_vend,
+ len - offsetof(struct bootp, bp_vend)) == DHCP_ACK) {
if (net_read_uint32(&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
- dhcp_options_process(&bp->bp_vend[4], bp);
+ dhcp_options_process(&bp->bp_vend[4], bp, len);
bootp_copy_net_params(bp); /* Store net params from reply */
dhcp_state = BOUND;
dev_info(&dhcp_edev->dev, "DHCP client bound to address %pI4\n", &dhcp_result->ip);
--
2.47.3
next prev parent reply other threads:[~2026-04-02 7:00 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-02 6:59 [PATCH v2 0/3] net: dhcp: fix buffer overflows Sascha Hauer
2026-04-02 6:59 ` Sascha Hauer [this message]
2026-04-02 6:59 ` [PATCH v2 2/3] net: dhcp: use xstrndup for bp_file to prevent read past field Sascha Hauer
2026-04-02 6:59 ` [PATCH v2 3/3] net: dhcp: cap DHCP option string length to 255 bytes Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260402-net-dhcp-buffer-overflows-v2-1-fe4ca7c4b718@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
--cc=noreply@anthropic.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox