mirror of
https://github.com/torvalds/linux.git
synced 2026-10-07 19:16:02 +02:00
net: ipconfig: bound DHCP option construction
ic_dhcp_init_options() appends the hostname (option 12), vendor-class
(option 60) and client-ID (option 61) options into the fixed 312-byte
bootp_pkt.exten[] buffer. Only the client-ID branch checked the
remaining space; the hostname and vendor-class writes were unbounded.
A 64-byte hostname together with the maximum 252-byte dhcpclass=
identifier needs 18 + (2 + 64) + (2 + 252) = 338 of the 312 available
bytes even before the terminating END marker, so the vendor-class memcpy
runs past the end of exten[]. With CONFIG_FORTIFY_SOURCE this is
reported as a field-spanning write and, when the kernel is booted with
panic_on_warn=1, aborts boot with a panic.
Route the optional options through a common helper that makes sure the
option, its 2-byte header and the END marker all fit and drops an option
that would not. Configurations with short options keep sending exactly
the same bytes as before.
Fixes: 130c0f47fd ("ipconfig: send host-name in DHCP requests")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Assisted-by: LLM
Signed-off-by: Yuqi Xu <xuyuqiabc@gmail.com>
Reviewed-by: Ren Wei <weir@nebusec.ai>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/7808dfbfa2162dfd0b19f59aff5742d6e0db2abb.1789798023.git.xuyuqiabc@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
90c2e97ff8
commit
e47a1958e1
|
|
@ -676,6 +676,24 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 };
|
|||
|
||||
#ifdef IPCONFIG_DHCP
|
||||
|
||||
static bool __init
|
||||
ic_dhcp_add_option(u8 **options, const u8 *end, u8 type, const void *value,
|
||||
int len)
|
||||
{
|
||||
u8 *e = *options;
|
||||
|
||||
/* leave room for the option header and the END marker */
|
||||
if (len > U8_MAX || end - e < len + 3)
|
||||
return false;
|
||||
|
||||
*e++ = type;
|
||||
*e++ = len;
|
||||
memcpy(e, value, len);
|
||||
*options = e + len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __init
|
||||
ic_dhcp_init_options(u8 *options, struct ic_device *d)
|
||||
{
|
||||
|
|
@ -691,6 +709,7 @@ ic_dhcp_init_options(u8 *options, struct ic_device *d)
|
|||
42, /* NTP servers */
|
||||
};
|
||||
u8 mt = (ic_servaddr == NONE) ? DHCPDISCOVER : DHCPREQUEST;
|
||||
u8 *end = options + sizeof(((struct bootp_pkt *)0)->exten);
|
||||
u8 *e = options;
|
||||
int len;
|
||||
|
||||
|
|
@ -721,31 +740,19 @@ ic_dhcp_init_options(u8 *options, struct ic_device *d)
|
|||
e += sizeof(ic_req_params);
|
||||
|
||||
if (ic_host_name_set) {
|
||||
*e++ = 12; /* host-name */
|
||||
len = strlen(utsname()->nodename);
|
||||
*e++ = len;
|
||||
memcpy(e, utsname()->nodename, len);
|
||||
e += len;
|
||||
ic_dhcp_add_option(&e, end, 12, utsname()->nodename, len);
|
||||
}
|
||||
if (*vendor_class_identifier) {
|
||||
pr_info("DHCP: sending class identifier \"%s\"\n",
|
||||
vendor_class_identifier);
|
||||
*e++ = 60; /* Class-identifier */
|
||||
len = strlen(vendor_class_identifier);
|
||||
*e++ = len;
|
||||
memcpy(e, vendor_class_identifier, len);
|
||||
e += len;
|
||||
if (ic_dhcp_add_option(&e, end, 60, vendor_class_identifier, len))
|
||||
pr_info("DHCP: sending class identifier \"%s\"\n",
|
||||
vendor_class_identifier);
|
||||
}
|
||||
len = strlen(dhcp_client_identifier + 1);
|
||||
/* the minimum length of identifier is 2, include 1 byte type,
|
||||
* and can not be larger than the length of options
|
||||
*/
|
||||
if (len >= 1 && len < 312 - (e - options) - 1) {
|
||||
*e++ = 61;
|
||||
*e++ = len + 1;
|
||||
memcpy(e, dhcp_client_identifier, len + 1);
|
||||
e += len + 1;
|
||||
}
|
||||
/* the minimum length of identifier is 2, include 1 byte type */
|
||||
if (len >= 1)
|
||||
ic_dhcp_add_option(&e, end, 61, dhcp_client_identifier, len + 1);
|
||||
|
||||
*e++ = 255; /* End of the list */
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user