net/dhcp: Allow overloading legacy bootfile and name field

DHCP specifies a special dummy option OVERLOAD, to allow DHCP options to
spill over into the (legacy) BOOTFILE and SNAME fields.

Parse and handle this option properly.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Andrei Borzenkov 2019-03-07 15:14:09 +00:00 committed by Daniel Kiper
parent 4c44bbd835
commit bd21d6465e
2 changed files with 59 additions and 1 deletions

View file

@ -25,11 +25,19 @@
#include <grub/net/udp.h>
#include <grub/datetime.h>
enum
{
GRUB_DHCP_OPT_OVERLOAD_FILE = 1,
GRUB_DHCP_OPT_OVERLOAD_SNAME = 2,
};
static const void *
find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
grub_uint8_t opt_code, grub_uint8_t *opt_len)
{
const grub_uint8_t *ptr;
grub_uint8_t overload = 0;
int end = 0;
grub_size_t i;
if (opt_len)
@ -54,6 +62,7 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
size -= sizeof (*bp);
i = sizeof (grub_uint32_t);
again:
while (i < size)
{
grub_uint8_t tagtype;
@ -67,7 +76,10 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
/* End tag. */
if (tagtype == GRUB_NET_BOOTP_END)
break;
{
end = 1;
break;
}
if (i >= size)
return NULL;
@ -84,9 +96,54 @@ find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
return &ptr[i];
}
if (tagtype == GRUB_NET_DHCP_OVERLOAD && taglength == 1)
overload = ptr[i];
i += taglength;
}
if (!end)
return NULL;
/* RFC2131, 4.1, 23ff:
* If the options in a DHCP message extend into the 'sname' and 'file'
* fields, the 'option overload' option MUST appear in the 'options'
* field, with value 1, 2 or 3, as specified in RFC 1533. If the
* 'option overload' option is present in the 'options' field, the
* options in the 'options' field MUST be terminated by an 'end' option,
* and MAY contain one or more 'pad' options to fill the options field.
* The options in the 'sname' and 'file' fields (if in use as indicated
* by the 'options overload' option) MUST begin with the first octet of
* the field, MUST be terminated by an 'end' option, and MUST be
* followed by 'pad' options to fill the remainder of the field. Any
* individual option in the 'options', 'sname' and 'file' fields MUST be
* entirely contained in that field. The options in the 'options' field
* MUST be interpreted first, so that any 'option overload' options may
* be interpreted. The 'file' field MUST be interpreted next (if the
* 'option overload' option indicates that the 'file' field contains
* DHCP options), followed by the 'sname' field.
*
* FIXME: We do not explicitly check for trailing 'pad' options here.
*/
end = 0;
if (overload & GRUB_DHCP_OPT_OVERLOAD_FILE)
{
overload &= ~GRUB_DHCP_OPT_OVERLOAD_FILE;
ptr = (grub_uint8_t *) &bp->boot_file[0];
size = sizeof (bp->boot_file);
i = 0;
goto again;
}
if (overload & GRUB_DHCP_OPT_OVERLOAD_SNAME)
{
overload &= ~GRUB_DHCP_OPT_OVERLOAD_SNAME;
ptr = (grub_uint8_t *) &bp->server_name[0];
size = sizeof (bp->server_name);
i = 0;
goto again;
}
return NULL;
}

View file

@ -457,6 +457,7 @@ enum
GRUB_NET_BOOTP_DOMAIN = 0x0f,
GRUB_NET_BOOTP_ROOT_PATH = 0x11,
GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
GRUB_NET_DHCP_OVERLOAD = 52,
GRUB_NET_BOOTP_END = 0xff
};