This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new edf07e434 netutils/dhcpd: prevent out-of-bounds DHCP option read
edf07e434 is described below
commit edf07e434eb9a354bcbdc4222f0489461e840942
Author: chao an <[email protected]>
AuthorDate: Thu Oct 22 22:06:58 2026 +0800
netutils/dhcpd: prevent out-of-bounds DHCP option read
dhcpd_parseoptions() read the option length byte for every non-PAD/non-END
option without first checking that two bytes remained in the current options
field. A malformed packet ending with a single non-PAD option byte could
therefore read one byte past the end of the options array.
Check that the option header is present before reading the length byte, and
reject options whose declared length extends beyond the current field. Also
allow options that exactly consume the remaining field bytes, and avoid
using
a stale option length when switching to overloaded file/sname option fields.
This prevents malformed DHCP client requests from causing out-of-bounds
reads
during DHCP server option parsing.
---
netutils/dhcpd/dhcpd.c | 42 +++++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/netutils/dhcpd/dhcpd.c b/netutils/dhcpd/dhcpd.c
index 9fdca8cc9..d6673d6b2 100644
--- a/netutils/dhcpd/dhcpd.c
+++ b/netutils/dhcpd/dhcpd.c
@@ -546,6 +546,7 @@ static inline bool dhcpd_parseoptions(void)
{
uint32_t tmp;
uint8_t *ptr;
+ uint8_t option;
#ifndef CONFIG_NET_DHCP_LIGHT
uint8_t overloaded;
uint8_t currfield;
@@ -584,18 +585,37 @@ static inline bool dhcpd_parseoptions(void)
do
{
+ option = ptr[DHCPD_OPTION_CODE];
+
+ if (option == DHCP_OPTION_PAD)
+ {
+ optlen = 1;
+ }
+ else if (option != DHCP_OPTION_END)
+ {
+ if (remaining < 2)
+ {
+ return false;
+ }
+
+ optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
+ if (optlen > remaining)
+ {
+ return false;
+ }
+ }
+
/* The form of an option is:
* code - 1 byte
* length - 1 byte
* data - variable number of bytes
*/
- switch (ptr[DHCPD_OPTION_CODE])
+ switch (option)
{
/* Skip over any padding bytes */
case DHCP_OPTION_PAD:
- optlen = 1;
break;
/* the Overload option is used to indicate that the DHCP 'sname'
@@ -617,8 +637,7 @@ static inline bool dhcpd_parseoptions(void)
#ifndef CONFIG_NET_DHCP_LIGHT
case DHCP_OPTION_OVERLOAD:
- optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
- if (optlen >= 3 && optlen < remaining)
+ if (optlen >= 3)
{
overloaded = ptr[DHCPD_OPTION_DATA];
}
@@ -633,6 +652,7 @@ static inline bool dhcpd_parseoptions(void)
ptr = g_state.ds_inpacket.file;
remaining = sizeof(g_state.ds_inpacket.file);
currfield = DHCPD_FILE_FIELD;
+ continue;
}
else if (currfield == DHCPD_FILE_FIELD &&
(overloaded & DHCPD_SNAME_FIELD) != 0)
@@ -640,6 +660,7 @@ static inline bool dhcpd_parseoptions(void)
ptr = g_state.ds_inpacket.sname;
remaining = sizeof(g_state.ds_inpacket.sname);
currfield = DHCPD_SNAME_FIELD;
+ continue;
}
else
{
@@ -651,8 +672,7 @@ static inline bool dhcpd_parseoptions(void)
#endif
case DHCP_OPTION_REQ_IPADDR: /* Requested IP Address */
- optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
- if (optlen >= 6 && optlen < remaining)
+ if (optlen >= 6)
{
memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4);
g_state.ds_optreqip = (in_addr_t)ntohl(tmp);
@@ -660,8 +680,7 @@ static inline bool dhcpd_parseoptions(void)
break;
case DHCP_OPTION_LEASE_TIME: /* IP address lease time */
- optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
- if (optlen >= 6 && optlen < remaining)
+ if (optlen >= 6)
{
memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4);
g_state.ds_optleasetime = ntohl(tmp);
@@ -669,16 +688,14 @@ static inline bool dhcpd_parseoptions(void)
break;
case DHCP_OPTION_MSG_TYPE: /* DHCP message type */
- optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
- if (optlen >= 3 && optlen < remaining)
+ if (optlen >= 3)
{
g_state.ds_optmsgtype = ptr[DHCPD_OPTION_DATA];
}
break;
case DHCP_OPTION_SERVER_ID: /* Server identifier */
- optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
- if (optlen >= 6 && optlen < remaining)
+ if (optlen >= 6)
{
memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4);
g_state.ds_optserverip = (in_addr_t)ntohl(tmp);
@@ -689,7 +706,6 @@ static inline bool dhcpd_parseoptions(void)
/* Skip over unsupported options */
- optlen = ptr[DHCPD_OPTION_LENGTH] + 2;
break;
}