Skip to content

Commit b94f88d

Browse files
committed
Merge tag 'hyperv-fixes-signed-20250427' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull hyperv fixes from Wei Liu: - Bug fixes for the Hyper-V driver and kvp_daemon * tag 'hyperv-fixes-signed-20250427' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: Drivers: hv: Fix bad ref to hv_synic_eventring_tail when CPU goes offline tools/hv: update route parsing in kvp daemon Drivers: hv: Fix bad pointer dereference in hv_get_partition_id
2 parents b443265 + 14ae300 commit b94f88d

File tree

2 files changed

+90
-28
lines changed

2 files changed

+90
-28
lines changed

drivers/hv/hv_common.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ void __init hv_get_partition_id(void)
307307

308308
local_irq_save(flags);
309309
output = *this_cpu_ptr(hyperv_pcpu_input_arg);
310-
status = hv_do_hypercall(HVCALL_GET_PARTITION_ID, NULL, &output);
310+
status = hv_do_hypercall(HVCALL_GET_PARTITION_ID, NULL, output);
311311
pt_id = output->partition_id;
312312
local_irq_restore(flags);
313313

@@ -566,9 +566,11 @@ int hv_common_cpu_die(unsigned int cpu)
566566
* originally allocated memory is reused in hv_common_cpu_init().
567567
*/
568568

569-
synic_eventring_tail = this_cpu_ptr(hv_synic_eventring_tail);
570-
kfree(*synic_eventring_tail);
571-
*synic_eventring_tail = NULL;
569+
if (hv_root_partition()) {
570+
synic_eventring_tail = this_cpu_ptr(hv_synic_eventring_tail);
571+
kfree(*synic_eventring_tail);
572+
*synic_eventring_tail = NULL;
573+
}
572574

573575
return 0;
574576
}

tools/hv/hv_kvp_daemon.c

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <sys/poll.h>
2626
#include <sys/utsname.h>
27+
#include <stdbool.h>
2728
#include <stdio.h>
2829
#include <stdlib.h>
2930
#include <unistd.h>
@@ -677,6 +678,88 @@ static void kvp_process_ipconfig_file(char *cmd,
677678
pclose(file);
678679
}
679680

681+
static bool kvp_verify_ip_address(const void *address_string)
682+
{
683+
char verify_buf[sizeof(struct in6_addr)];
684+
685+
if (inet_pton(AF_INET, address_string, verify_buf) == 1)
686+
return true;
687+
if (inet_pton(AF_INET6, address_string, verify_buf) == 1)
688+
return true;
689+
return false;
690+
}
691+
692+
static void kvp_extract_routes(const char *line, void **output, size_t *remaining)
693+
{
694+
static const char needle[] = "via ";
695+
const char *match, *haystack = line;
696+
697+
while ((match = strstr(haystack, needle))) {
698+
const char *address, *next_char;
699+
700+
/* Address starts after needle. */
701+
address = match + strlen(needle);
702+
703+
/* The char following address is a space or end of line. */
704+
next_char = strpbrk(address, " \t\\");
705+
if (!next_char)
706+
next_char = address + strlen(address) + 1;
707+
708+
/* Enough room for address and semicolon. */
709+
if (*remaining >= (next_char - address) + 1) {
710+
memcpy(*output, address, next_char - address);
711+
/* Terminate string for verification. */
712+
memcpy(*output + (next_char - address), "", 1);
713+
if (kvp_verify_ip_address(*output)) {
714+
/* Advance output buffer. */
715+
*output += next_char - address;
716+
*remaining -= next_char - address;
717+
718+
/* Each address needs a trailing semicolon. */
719+
memcpy(*output, ";", 1);
720+
*output += 1;
721+
*remaining -= 1;
722+
}
723+
}
724+
haystack = next_char;
725+
}
726+
}
727+
728+
static void kvp_get_gateway(void *buffer, size_t buffer_len)
729+
{
730+
static const char needle[] = "default ";
731+
FILE *f;
732+
void *output = buffer;
733+
char *line = NULL;
734+
size_t alloc_size = 0, remaining = buffer_len - 1;
735+
ssize_t num_chars;
736+
737+
/* Show route information in a single line, for each address family */
738+
f = popen("ip --oneline -4 route show;ip --oneline -6 route show", "r");
739+
if (!f) {
740+
/* Convert buffer into C-String. */
741+
memcpy(output, "", 1);
742+
return;
743+
}
744+
while ((num_chars = getline(&line, &alloc_size, f)) > 0) {
745+
/* Skip short lines. */
746+
if (num_chars <= strlen(needle))
747+
continue;
748+
/* Skip lines without default route. */
749+
if (memcmp(line, needle, strlen(needle)))
750+
continue;
751+
/* Remove trailing newline to simplify further parsing. */
752+
if (line[num_chars - 1] == '\n')
753+
line[num_chars - 1] = '\0';
754+
/* Search routes after match. */
755+
kvp_extract_routes(line + strlen(needle), &output, &remaining);
756+
}
757+
/* Convert buffer into C-String. */
758+
memcpy(output, "", 1);
759+
free(line);
760+
pclose(f);
761+
}
762+
680763
static void kvp_get_ipconfig_info(char *if_name,
681764
struct hv_kvp_ipaddr_value *buffer)
682765
{
@@ -685,30 +768,7 @@ static void kvp_get_ipconfig_info(char *if_name,
685768
char *p;
686769
FILE *file;
687770

688-
/*
689-
* Get the address of default gateway (ipv4).
690-
*/
691-
sprintf(cmd, "%s %s", "ip route show dev", if_name);
692-
strcat(cmd, " | awk '/default/ {print $3 }'");
693-
694-
/*
695-
* Execute the command to gather gateway info.
696-
*/
697-
kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
698-
(MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
699-
700-
/*
701-
* Get the address of default gateway (ipv6).
702-
*/
703-
sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
704-
strcat(cmd, " | awk '/default/ {print $3 }'");
705-
706-
/*
707-
* Execute the command to gather gateway info (ipv6).
708-
*/
709-
kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
710-
(MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
711-
771+
kvp_get_gateway(buffer->gate_way, sizeof(buffer->gate_way));
712772

713773
/*
714774
* Gather the DNS state.

0 commit comments

Comments
 (0)