[PATCH] net: dhcpv6: Prevent out-of-bounds reads while parsing options
Jerome Forissier
jerome.forissier at arm.com
Tue May 19 11:30:07 CEST 2026
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 <fberder at outlook.fr>
> ---
> 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 <jerome.forissier at arm.com>
...and added to the net queue. Thanks!
--
Jerome
More information about the U-Boot
mailing list