Thread (25 messages) flat view 25 messages, 2 authors, 2026-08-07

Re: [PATCH v1 12/13] hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader)

From: sashiko-bot@kernel.org
Date: 2026-08-07 16:22:51

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [Critical] The x86 EFI stub stores the command line in a `.bss` static buffer which is wiped by the kernel decompressor.
- [High] Unconditional increment of `cmdline_len` with `snprintf` return value leads to buffer overflow.
- [High] Incorrect linked list traversal causes truncation of the existing `setup_data` chain.
- [Medium] Missing NULL pointer check before calling `strlen` on the command line.
- [Medium] Skipping invalid e820 indices leaves uninitialized holes in `hv_mshv_res`, breaking resource registration.
- [Medium] MSHV root partition boot enablement is completely unreachable on ARM64.
- [Low] Memory leak of `mshv_reserved` array in x86 EFI stub.
- [Low] Memory leak of `mem_map` in ARM64 EFI stub.
- [Low] Parsing error in `hyperv_resvd_new` bypasses state updates, silencing previous valid ranges.
--
--- Patch [12]: [PATCH v1 12/13] hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader) ---
commit fcbf57de7557f7a5bf335c4003de65861d33a7c5
Author: Wei Hu [off-list ref]

hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader)

This commit ports the EFI HvLoader protocol handshake and the hyperv_resvd_new
memory reservation. It provides the Linux-side enablement necessary to boot an
upstream kernel as a Microsoft Hypervisor (MSHV) root partition.
quoted hunk ↗ jump to hunk
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -496,6 +499,75 @@ EXPORT_SYMBOL_GPL(hv_get_hypervisor_version);
+static void __init hv_resv_mshv_memory(void)
+{
+	u64 start, end, size;
+	int i, idx, max = ARRAY_SIZE(hv_resvd_ranges);
+
+	for (i = 0; i < max && hv_resvd_ranges[i] != -1; i++) {
+		idx = hv_resvd_ranges[i];
+		if (idx < 0 || idx >= e820_table->nr_entries) {
+			pr_info("Hyper-V: invalid resvd idx %d\n", idx);
+			continue;
[Severity: Medium]
Does skipping the invalid index here leave the hv_mshv_res array
zero-initialized for this slot?

Later on, hv_mark_resources() iterates over this array using:
    for (i = 0; i < max && hv_mshv_res[i].end; i++)

Could this cause the registration loop to terminate prematurely when it hits
the hole, silently dropping all subsequent valid memory ranges?
+		}
+
+		start = e820_table->entries[idx].addr;
quoted hunk ↗ jump to hunk
--- /dev/null
+++ b/drivers/firmware/efi/libstub/arm64-efi-mshv.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/setup.h>
+
+#include "efistub.h"
+#include "efi-mshv.h"
+
+efi_status_t mshv_efi_setup(char **cmdline_ptr)
+{
[Severity: Medium]
Is this function ever invoked? It appears to be defined here but never hooked
into the ARM64 EFI stub entry point, making the ARM64 MSHV boot enablement
unreachable code.
+	efi_status_t status;
+	efi_memory_desc_t *mem_map;
+	unsigned long map_sz, desc_sz, new_cmdline_addr;
+
+	status = mshv_efi_init();
+	if (status == EFI_NOT_FOUND) // we are in a standard Linux boot
+		return EFI_SUCCESS;
+
+	map_sz = 0;
+	mshv_get_hv_ranges((void *)&mem_map, &map_sz, &desc_sz);
+
+	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, COMMAND_LINE_SIZE,
+			     (void **)&new_cmdline_addr);
[Severity: Low]
Does this code leak the mem_map pool allocation? Unlike the x86 implementation
in this patch, it doesn't appear to be freed before returning EFI_SUCCESS.
+	if (status != EFI_SUCCESS)
quoted hunk ↗ jump to hunk
--- /dev/null
+++ b/drivers/firmware/efi/libstub/efi-mshv-common.c
[ ... ]
+void mshv_efi_update_cmdline(efi_memory_desc_t *mem_map,
+			     unsigned long map_sz, unsigned long desc_sz, char *old_cmdline,
+		char *buf, unsigned long buf_sz)
+{
+	int i, cmdline_len, nr_desc;
+
+	cmdline_len = strlen(old_cmdline);
[Severity: Medium]
Can old_cmdline be NULL if the kernel is booted without a command line?
If so, passing it directly to strlen() would lead to a NULL pointer
dereference.
+	memcpy(buf, old_cmdline, cmdline_len + 1);
+
+	cmdline_len += snprintf(buf + cmdline_len,
+				buf_sz - cmdline_len,
+				" hyperv_resvd_new=");
+
+	nr_desc = map_sz / desc_sz;
+	for (i = 0; i < nr_desc; ++i) {
+		efi_memory_desc_t *d;
+		u64 start, end, sz;
+
+		d = efi_memdesc_ptr(mem_map, desc_sz, i);
+		start = d->phys_addr;
+		sz = d->num_pages << PAGE_SHIFT;
+		end = start + sz - 1;
+
+		cmdline_len += snprintf(buf + cmdline_len,
+					buf_sz - cmdline_len,
+					"%s0x%llx!0x%llx", i > 0 ? "," : "",
+					sz, start);
[Severity: High]
Could this result in a buffer overflow?

If the appended string exceeds buf_sz, snprintf returns the number of
characters that would have been written, not the number actually written. 
Adding this value to cmdline_len could cause buf_sz - cmdline_len to underflow
into a very large unsigned integer.

Will the next loop iteration then write out of bounds via buf + cmdline_len?
+	}
quoted hunk ↗ jump to hunk
--- /dev/null
+++ b/drivers/firmware/efi/libstub/x86-efi-mshv.c
[ ... ]
+static efi_status_t mshv_populate_ranges(struct boot_params *boot_params,
+					 efi_memory_desc_t *mem_map, unsigned long map_sz,
+			unsigned long desc_sz)
+{
+	unsigned long cmdline_ptr;
+	u32 cmdline_size;
+	static u8 mshv_cmdline[COMMAND_LINE_SIZE];
[Severity: Critical]
Will this static buffer be placed in the .bss segment and subsequently
destroyed?

When the EFI stub hands over control to the kernel decompressor
(e.g. startup_64), the decompressor zeroes its .bss segment before the command
line is parsed. Using a static buffer here might cause the entire kernel
command line to be lost.
+
+	memset(mshv_cmdline, 0, sizeof(mshv_cmdline));
+
+	cmdline_ptr = boot_params->hdr.cmd_line_ptr;
+	cmdline_ptr |= (u64)boot_params->ext_cmd_line_ptr << 32;
+	cmdline_size = boot_params->hdr.cmdline_size;
+
+	mshv_efi_update_cmdline(mem_map, map_sz, desc_sz,
+				(char *)cmdline_ptr,
+				(char *)mshv_cmdline, COMMAND_LINE_SIZE);
+
+	boot_params->hdr.cmd_line_ptr = (u32)((unsigned long)mshv_cmdline);
[ ... ]
+efi_status_t mshv_efi_setup(struct boot_params *boot_params)
+{
[ ... ]
+	/*
+	 * Build an array of kernel 'struct resource' objects that contain mshv
+	 * reserved ranges. This array is populated via a command line parameter
+	 * called 'hyperv_resvd_new'.
+	 */
+
+	status = mshv_realloc_ranges(&mshv_reserved,
+				     &mshv_reserved_sz,
+				MSHV_RESERVED_RANGES_COUNT);
[Severity: Low]
Does this code leak the mshv_reserved array memory? It is dynamically
allocated here and possibly reallocated during the loop, but it doesn't appear
to be freed at the end of the function.

[ ... ]
+	setup_data_itr = (struct setup_data **)&boot_params->hdr.setup_data;
+
+	while (*setup_data_itr && (*setup_data_itr)->next)
+		setup_data_itr = (struct setup_data **)&(*setup_data_itr)->next;
+
+	*setup_data_itr = (struct setup_data *)sd_block;
[Severity: High]
Does this loop terminate one node early?

Because it checks (*setup_data_itr)->next in the while condition, it exits
when pointing to the last node. Overwriting *setup_data_itr here seems to
overwrite the pointer to the last element rather than appending to it, which
could drop critical boot parameters passed by the bootloader.
+
+	for (i = 0; i < nr_ranges; i++) {
quoted hunk ↗ jump to hunk
--- a/drivers/hv/hv_common.c
+++ b/drivers/hv/hv_common.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -863,3 +867,81 @@ const char *hv_result_to_string(u64 status)
+static int __init hv_parse_hyperv_resvd_new(char *arg)
+{
+	int i = 0;
+
+	if (is_kdump_kernel())
+		return 0;
+
+	while (arg && *arg) {
+		unsigned long long region_start, region_sz;
+		char *range, *addr_str;
+
+		if (i >= HV_MAX_RESVD_RANGES) {
+			pr_err("Hyper-V: too many hyperv_resvd_new ranges specified\n");
+			return 0;
+		}
+
+		/* Each range is "<size>!<address>", ranges separated by ','. */
+		range = strsep(&arg, ",");
+		addr_str = strchr(range, '!');
+		if (!addr_str) {
+			pr_err("Hyper-V: invalid format for hyperv_resvd_new: %s\n", range);
+			return 0;
[Severity: Low]
If an invalid format is encountered, does this early return bypass updating
the global ranges_nr counter?

By returning early instead of breaking the loop, ranges_nr = i is skipped,
which might cause any previously parsed valid memory ranges to be silently
ignored by hv_dump_mshv_memory() later.
+		}
-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260807135134.303943-1-weh@linux.microsoft.com?part=12
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help