[PATCH] net: bootp: extend ProxyDHCP support to read bootfile name
Jerome Forissier
jerome at forissier.org
Wed May 27 16:49:10 CEST 2026
Hi Ryan,
[Replying from my personal address because for some reason my email is
rejected by the Arm email servers: "messages to GMX.DE; are blocked by
your organization [...]"]
On 5/20/26 23:59, Ryan Persée wrote:
> When CONFIG_SERVERIP_FROM_PROXYDHCP is enabled, a ProxyDHCP server
> responds with a zero yiaddr and supplies PXE-specific parameters such
> as the TFTP server address. However, the bootfile name was only read
> from the BOOTP legacy 'bp_file' header field. Modern ProxyDHCP servers
> (e.g. dnsmasq, iPXE) advertise the bootfile via DHCP option 67 instead,
> which was previously ignored.
>
> Furthermore, once the ProxyDHCP bootfile was stored, it could be silently
> overwritten by a subsequent DHCP OFFER or ACK from the main DHCP server
> if that packet also carried a bootfile (via option 67 or bp_file).
>
> This patch makes three minimal changes within the existing
> CONFIG_SERVERIP_FROM_PROXYDHCP guards:
>
> 1. Add store_proxydhcp_bootfile(), a targeted helper that walks the DHCP
> vendor options of a ProxyDHCP response and extracts only option 67.
> All other options are deliberately ignored so that the ProxyDHCP
> server cannot alter the client's network configuration (gateway, DNS,
> etc.), which remains the main DHCP server's responsibility.
> Option 67 takes precedence over the legacy bp_file header field;
> bp_file is used as a fallback via the existing store_bootp_params().
>
> 2. Add a !net_boot_file_name[0] guard in store_bootp_params() and in
> dhcp_process_options() case 67 so that a bootfile already set by the
> ProxyDHCP response is not overwritten by the main DHCP exchange.
>
> 3. Extend the ProxyDHCP wait condition in the SELECTING state to also
> delay when the bootfile has not yet been received, mirroring the
> existing delay for the server IP address.
>
> Signed-off-by: Ryan Persée <98691129+rpersee at users.noreply.github.com>
> ---
> net/bootp.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 49 insertions(+), 3 deletions(-)
>
> diff --git a/net/bootp.c b/net/bootp.c
> index 8976936b184..a16245cc7e8 100644
> --- a/net/bootp.c
> +++ b/net/bootp.c
> @@ -161,7 +161,11 @@ static void store_bootp_params(struct bootp_hdr *bp)
> !(dhcp_option_overload & OVERLOAD_FILE) &&
> #endif
> (strlen(bp->bp_file) > 0) &&
> - !net_boot_file_name_explicit) {
> + !net_boot_file_name_explicit
> +#if defined(CONFIG_SERVERIP_FROM_PROXYDHCP)
> + && !net_boot_file_name[0]
> +#endif
> + ) {
> copy_filename(net_boot_file_name, bp->bp_file,
> sizeof(net_boot_file_name));
> }
> @@ -935,7 +939,11 @@ static void dhcp_process_options(uchar *popt, uchar *end)
> case 66: /* Ignore TFTP server name */
> break;
> case 67: /* Bootfile option */
> - if (!net_boot_file_name_explicit) {
> + if (!net_boot_file_name_explicit
> +#if defined(CONFIG_SERVERIP_FROM_PROXYDHCP)
> + && !net_boot_file_name[0]
> +#endif
> + ) {
> size = truncate_sz("Bootfile",
> sizeof(net_boot_file_name),
> oplen);
> @@ -1080,6 +1088,43 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
> net_send_packet(net_tx_packet, pktlen);
> }
>
> +#if defined(CONFIG_SERVERIP_FROM_PROXYDHCP)
> +/*
> + * Extract bootfile name from DHCP option 67 in a ProxyDHCP response.
> + * Only option 67 is read; all other options are intentionally ignored to
> + * avoid letting the ProxyDHCP server alter the client's network config
> + * (gateway, DNS, etc.) which is the main DHCP server's responsibility.
> + */
> +static void store_proxydhcp_bootfile(struct bootp_hdr *bp)
> +{
> + uchar *popt = (uchar *)&bp->bp_vend[4];
> + uchar *end = (uchar *)bp + BOOTP_HDR_SIZE;
> + int oplen, size;
> +
> + if (net_read_u32((u32 *)&bp->bp_vend[0]) != htonl(BOOTP_VENDOR_MAGIC))
> + return;
> +
> + while (popt < end && *popt != 0xff) {
> + if (*popt == 0) {
> + popt++;
> + continue;
> + }
I believe you need this to avoid a potential OOB read:
if (popt + 1 >= end)
break;
> + oplen = *(popt + 1);
> + if (popt + 2 + oplen > end)
> + break;
> + if (*popt == 67 && !net_boot_file_name_explicit &&
> + !net_boot_file_name[0]) {
> + size = truncate_sz("Bootfile",
> + sizeof(net_boot_file_name), oplen);
> + memcpy(net_boot_file_name, popt + 2, size);
> + net_boot_file_name[size] = 0;
> + break;
> + }
> + popt += oplen + 2;
> + }
> +}
> +#endif
> +
> /*
> * Handle DHCP received packets.
> */
> @@ -1100,6 +1145,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
>
> if (net_read_ip(&bp->bp_yiaddr).s_addr == 0) {
> #if defined(CONFIG_SERVERIP_FROM_PROXYDHCP)
> + store_proxydhcp_bootfile(bp);
> store_bootp_params(bp);
> #endif
> return;
> @@ -1130,7 +1176,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
> efi_net_set_dhcp_ack(pkt, len);
>
> #if defined(CONFIG_SERVERIP_FROM_PROXYDHCP)
> - if (!net_server_ip.s_addr)
> + if (!net_server_ip.s_addr || !net_boot_file_name[0])
Shouldn't !net_boot_file_name[0] be (!net_boot_file_name_explicit &&
!net_boot_file_name[0])?
> udelay(CONFIG_SERVERIP_FROM_PROXYDHCP_DELAY_MS *
> 1000);
> #endif /* CONFIG_SERVERIP_FROM_PROXYDHCP */
Other than that, LGTM.
Thanks,
--
Jerome
More information about the U-Boot
mailing list