On 15/05/2026 18:53, Francois Berder wrote: > dhcp6_parse_options() verifies that an option's declared data fits > within the packet, but does not check that option_len is large > enough for the fixed-size read each case performs. A malicious > DHCP server can send an ADVERTISE with a zero-length IA_NA, > STATUS_CODE, SOL_MAX_RT, or BOOTFILE_PARAM option, causing the > parser to read 2-4 bytes past the option's declared data. > > Check option_len value before each dereference of option_ptr. > > Signed-off-by: Francois Berder <[email protected]> > --- > net/dhcpv6.c | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/net/dhcpv6.c b/net/dhcpv6.c > index 51f44979f8e..640f089a2e1 100644 > --- a/net/dhcpv6.c > +++ b/net/dhcpv6.c > @@ -339,6 +339,11 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned > int len) > break; > case DHCP6_OPTION_IA_TA: > case DHCP6_OPTION_IA_NA: > + if (option_len < sizeof(u32)) { > + debug("Invalid IA_NA/IA_TA option length\n"); > + break; > + } > + > /* check the IA_ID */ > if (*((u32 *)option_ptr) != htonl(sm_params.ia_id)) { > debug("IA_ID mismatch 0x%08x 0x%08x\n", > @@ -347,6 +352,10 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned > int len) > } > > if (ntohs(option_hdr->option_id) == DHCP6_OPTION_IA_NA) > { > + if (option_len < 3 * sizeof(u32)) { > + debug("Invalid IA_NA option length\n"); > + break; > + } > /* skip past IA_ID/T1/T2 */ > option_ptr += 3 * sizeof(u32); > } else if (ntohs(option_hdr->option_id) == > DHCP6_OPTION_IA_TA) { > @@ -358,12 +367,20 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned > int len) > break; > case DHCP6_OPTION_STATUS_CODE: > debug("DHCP6_OPTION_STATUS_CODE FOUND\n"); > + if (option_len < sizeof(u16)) { > + debug("Invalid status code option length\n"); > + break; > + } > sm_params.rx_status.status_code = ntohs(*((u16 > *)option_ptr)); > debug("DHCP6 top-level status code %d\n", > sm_params.rx_status.status_code); > debug("DHCP6 status message: %.*s\n", len, option_ptr + > 2); > break; > case DHCP6_OPTION_SOL_MAX_RT: > debug("DHCP6_OPTION_SOL_MAX_RT FOUND\n"); > + if (option_len != sizeof(u32)) { > + debug("Invalid SOL_MAX_RT option length\n"); > + break; > + } > sol_max_rt_sec = ntohl(*((u32 *)option_ptr)); > > /* A DHCP client MUST ignore any SOL_MAX_RT option > values that are less > @@ -394,6 +411,12 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned > int len) > case DHCP6_OPTION_OPT_BOOTFILE_PARAM: > if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION)) { > debug("DHCP6_OPTION_OPT_BOOTFILE_PARAM > FOUND\n"); > + > + if (option_len < sizeof(u16)) { > + debug("Invalid BOOTFILE_PARAM option > length\n"); > + break; > + } > + > /* if CONFIG_DHCP6_PXE_DHCP_OPTION is set the > PXE config file path > * is contained in the first OPT_BOOTFILE_PARAM > argument > */ > @@ -419,6 +442,10 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned > int len) > break; > case DHCP6_OPTION_PREFERENCE: > debug("DHCP6_OPTION_PREFERENCE FOUND\n"); > + if (option_len != 1) { > + debug("Invalid preference option length\n"); > + break; > + } > sm_params.rx_status.preference = *option_ptr; > break; > default:
Ackeded-by: Jerome Forissier <[email protected]> ...and added to the net queue. Thanks! -- Jerome

