RE: [PATCH] tools/hv: fix parse_ip_val_buffer out-of-bounds write

From: Michael Kelley

Date: Thu Apr 23 2026 - 16:28:32 EST


From: unknownbbqrx <dev@xxxxxxxxxxxxxxx> Sent: Thursday, April 23, 2026 11:07 AM
>
>
> parse_ip_val_buffer() validates the parsed token length against out_len,
> but several callers passed MAX_IP_ADDR_SIZE * 2 while the destination
> buffers are much smaller stack arrays (e.g. INET6_ADDRSTRLEN).
>
> This can lead to out-of-bounds writes via strcpy() when a long token is
> parsed from host-provided IP/subnet strings.
>
> Use size_t for out_len, switch to bounded copy with memcpy() + explicit
> NUL termination, and pass the actual destination buffer sizes at all
> call sites.
>
> Signed-off-by: unknownbbqrx <dev@xxxxxxxxxxxxxxx>

Linux kernel patches must be signed off by a real person's name,
not an unknown alias. In the kernel source code tree, see
Documentation/process/submitting-patches.rst and specifically
the section entitled "Sign your work - the Developer's Certificate
of Origin". It specifies that the signoff must be done by "a
known identity (sorry, no anonymous contributions)".

Michael

> ---
> tools/hv/hv_kvp_daemon.c | 22 ++++++++++++----------
> 1 file changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
> index c02f8a341..ecf123bce 100644
> --- a/tools/hv/hv_kvp_daemon.c
> +++ b/tools/hv/hv_kvp_daemon.c
> @@ -1188,10 +1188,11 @@ static int is_ipv4(char *addr)
> }
>
> static int parse_ip_val_buffer(char *in_buf, int *offset,
> - char *out_buf, int out_len)
> + char *out_buf, size_t out_len)
> {
> char *x;
> char *start;
> + size_t copy_len;
>
> /*
> * in_buf has sequence of characters that are separated by
> @@ -1214,8 +1215,10 @@ static int parse_ip_val_buffer(char *in_buf, int *offset,
> while (start[i] == ' ')
> i++;
>
> - if ((x - start) <= out_len) {
> - strcpy(out_buf, (start + i));
> + copy_len = x - (start + i);
> + if (copy_len < out_len) {
> + memcpy(out_buf, start + i, copy_len);
> + out_buf[copy_len] = '\0';
> *offset += (x - start) + 1;
> return 1;
> }
> @@ -1249,7 +1252,7 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
> memset(addr, 0, sizeof(addr));
>
> while (parse_ip_val_buffer(ip_string, &offset, addr,
> - (MAX_IP_ADDR_SIZE * 2))) {
> + sizeof(addr))) {
>
> sub_str[0] = 0;
> if (is_ipv4(addr)) {
> @@ -1374,7 +1377,7 @@ static int process_dns_gateway_nm(FILE *f, char *ip_string,
> int type,
> memset(addr, 0, sizeof(addr));
>
> if (!parse_ip_val_buffer(ip_string, &ip_offset, addr,
> - (MAX_IP_ADDR_SIZE * 2)))
> + sizeof(addr)))
> break;
>
> ip_ver = ip_version_check(addr);
> @@ -1426,12 +1429,11 @@ static int process_ip_string_nm(FILE *f, char *ip_string,
> char *subnet,
> memset(subnet_addr, 0, sizeof(subnet_addr));
>
> while (parse_ip_val_buffer(ip_string, &ip_offset, addr,
> - (MAX_IP_ADDR_SIZE * 2)) &&
> + sizeof(addr)) &&
> parse_ip_val_buffer(subnet,
> - &subnet_offset,
> - subnet_addr,
> - (MAX_IP_ADDR_SIZE *
> - 2))) {
> + &subnet_offset,
> + subnet_addr,
> + sizeof(subnet_addr))) {
> ip_ver = ip_version_check(addr);
> if (ip_ver < 0)
> continue;
>
> base-commit: 2e68039281932e6dc37718a1ea7cbb8e2cda42e6
> prerequisite-patch-id: b61dd51dee390277603975bf729a687113185c3a
> prerequisite-patch-id: df28525061dd528875c7c75880b4684d80f4aa7d
> prerequisite-patch-id: 64c48c6f2222781631304d9d4d7d1c712c002610
> prerequisite-patch-id: 9be258692732026bf560ed9887adbd02a8887263
> --
> 2.53.0
>
>
>