From: sashiko-bot@kernel.org
To: "Wei Hu" <weh@linux.microsoft.com>
Cc: linux-hyperv@vger.kernel.org
Subject: Re: [PATCH v2 12/13] hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader)
Date: Mon, 10 Aug 2026 13:05:53 +0000 [thread overview]
Message-ID: <20260810130553.D21291F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260810124527.1409634-13-weh@linux.microsoft.com>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] Secure Boot bypass and arbitrary memory overwrite via `hyperv_resvd=` early parameter.
- [High] Uninitialized stack variable `ret` used across trust boundary in `mshv_launch`.
- [High] EFI stub passes unmerged hypervisor memory ranges to the kernel, overflowing command-line and parser limits.
- [High] Logic error in `hv_parse_hyperv_resvd_new` rejects valid physical address 0.
- [Medium] Incorrect variadic argument forwarding in `mshv_efi_reboot`.
- [Medium] State corruption in `hv_parse_hyperv_resvd_new` overwriting head without clearing the tail.
- [Low] Incomplete implementation/Dead code: `SETUP_MSHV` is built but never parsed.
--
--- Patch [12]: [PATCH v2 12/13] hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader) ---
commit d68b02782397b0c67109138fd120320cacae1537
Author: Wei Hu <weh@microsoft.com>
hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader)
Port the EFI HvLoader protocol handshake (efi-mshv stub + SETUP_MSHV) and
the hyperv_resvd_new memory reservation so an upstream kernel can boot as
a Microsoft Hypervisor (MSHV) root partition.
> diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
> index 185d4f677ec0f..63504b22b5ba8 100644
> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
[ ... ]
> +static int __init hv_parse_hyperv_resvd(char *arg)
> +{
> + int idx, max = ARRAY_SIZE(hv_resvd_ranges);
> + int i = 0;
[ ... ]
> + while (get_option(&arg, &idx)) {
> + if (i >= max) {
> + pr_err("Hyper-V: resvd ranges tbl full %d\n", idx);
> + break;
> + }
> +
> + hv_resvd_ranges[i++] = idx;
> + }
> +
> + return 0;
> +}
> +early_param("hyperv_resvd", hv_parse_hyperv_resvd);
> +
> +/*
> + * Reserve memory that the hypervisor is using early on. The ranges are marked
> + * reserved by a custom bootloader, change that to usable and reserve that
> + * range. Note, the bootloader sanitizes the e820 before passing on here.
> + */
> +static void __init hv_resv_mshv_memory(void)
> +{
> + u64 start, end, size;
> + int i, idx, max = ARRAY_SIZE(hv_resvd_ranges);
> + int resource_index = 0;
> +
> + for (i = 0; i < max && hv_resvd_ranges[i] != -1; i++) {
> + idx = hv_resvd_ranges[i];
[ ... ]
> + start = e820_table->entries[idx].addr;
> + size = e820_table->entries[idx].size;
> + end = start + size - 1;
> +
> + memblock_reserve(start, size);
> + e820_table->entries[idx].type = E820_TYPE_RAM;
> + pr_info("Hyper-V reserve [mem %#018Lx-%#018Lx]\n", start, end);
> +
> + hv_mshv_res[resource_index].name = "Hypervisor Code and Data";
> + hv_mshv_res[resource_index].flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM;
> + hv_mshv_res[resource_index].start = start;
> + hv_mshv_res[resource_index++].end = end;
> + }
> +}
[Severity: Critical]
Does this allow bypassing kernel lockdown?
The hv_parse_hyperv_resvd() function takes an unauthenticated index from the
kernel command line. Then hv_resv_mshv_memory() blindly converts that e820
entry to E820_TYPE_RAM and IORESOURCE_SYSTEM_RAM without bounds checks.
Could a user with access to the bootloader command line use this to target
reserved ACPI or firmware regions, map them as System RAM, and overwrite them
via kexec_file_load?
> diff --git a/drivers/firmware/efi/libstub/efi-mshv-common.c b/drivers/firmware/efi/libstub/efi-mshv-common.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/efi-mshv-common.c
[ ... ]
> +efi_status_t mshv_launch(void)
> +{
> + struct hvl_return_data ret;
> +
> + if (!efi_mshv)
> + return EFI_SUCCESS;
> +
> + efi_mshv->launch_hv(NULL, &ret);
> + /* TODO: Where/how do we dump the hv loader logs? */
> + if (ret.launch_data.launch_status != 0)
> + efi_rt_call(reset_system, EFI_RESET_COLD, EFI_ABORTED, 0, NULL);
> + return EFI_SUCCESS;
> +}
[Severity: High]
Can this result in evaluating uninitialized stack memory?
The ret structure is allocated on the stack but not zeroed before being
passed to efi_mshv->launch_hv(). If the hypervisor loader protocol fails
early or neglects to fully populate the structure, does checking
ret.launch_data.launch_status read stack garbage and trigger an unexpected
cold reboot?
> diff --git a/drivers/firmware/efi/libstub/efi-mshv.h b/drivers/firmware/efi/libstub/efi-mshv.h
> new file mode 100644
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/efi-mshv.h
[ ... ]
> +static inline void mshv_efi_reboot(const char *fmt, ...)
> +{
> + va_list args;
> +
> + va_start(args, fmt);
> + efi_printk(fmt, args);
> + va_end(args);
> +
> + efi_bs_call(stall, 5 * EFI_USEC_PER_SEC);
> + efi_rt_call(reset_system, EFI_RESET_COLD, EFI_ABORTED, 0, NULL);
> +}
[Severity: Medium]
Is args correctly passed to efi_printk() here?
efi_printk() is a variadic function rather than a vprintf-style function.
Passing a va_list directly to it as the first argument will cause it to
interpret the va_list structure itself as the format argument, which prints
garbage memory values instead of the actual error codes.
> diff --git a/drivers/firmware/efi/libstub/x86-efi-mshv.c b/drivers/firmware/efi/libstub/x86-efi-mshv.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/x86-efi-mshv.c
[ ... ]
> +efi_status_t mshv_efi_setup(struct boot_params *boot_params)
> +{
[ ... ]
> + for (i = 0, nr_ranges = 0; i < nr_desc; i++) {
[ ... ]
> + mshv_range->name = "Hypervisor Code and Data";
> + mshv_range->flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM;
> + mshv_range->start = d->phys_addr;
> + mshv_range->end = d->phys_addr + (d->num_pages << PAGE_SHIFT) - 1;
> +
> + prev = mshv_range++;
> + nr_ranges++;
[ ... ]
> + }
> +
> + status = mshv_populate_ranges(boot_params, mem_map, map_sz, desc_sz);
[Severity: High]
Does this pass the unmerged EFI memory map to the command line?
The code successfully merges adjacent EFI descriptors into the mshv_reserved
array above, but then passes the raw, unmerged mem_map array into
mshv_populate_ranges().
Since mshv_efi_update_cmdline() serializes every descriptor, could this
exceed the 32-range limit (HV_MAX_RESVD_RANGES) in hv_parse_hyperv_resvd_new()
if the unmerged map is highly fragmented, causing the kernel to silently
drop the remaining ranges?
> + if (status != EFI_SUCCESS)
> + mshv_efi_reboot("failed to update command line with code %d",
> + status);
> +
> + /* Build an indirect setup_data for each mshv reserved range. */
> + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
> + nr_ranges * sizeof(struct mshv_setup_data),
> + (void **)&sd_block);
> + if (status != EFI_SUCCESS)
> + mshv_efi_reboot("failed to allocate space for hv ranges: error code %d", status);
[ ... ]
> + for (i = 0; i < nr_ranges; i++) {
> + start = mshv_reserved[i].start;
> + end = mshv_reserved[i].end;
> +
> + sd_block[i].sd.type = SETUP_INDIRECT;
> + sd_block[i].sd.len = sizeof(struct setup_indirect);
> + sd_block[i].sd.next = (__u64)&sd_block[i + 1];
> +
> + sd_block[i].si.type = SETUP_MSHV;
> + sd_block[i].si.reserved = 0;
> + sd_block[i].si.len = end - start + 1;
> + sd_block[i].si.addr = start;
> + }
[Severity: Low]
Is the SETUP_MSHV data parsed by the kernel later?
The stub builds a SETUP_INDIRECT chain wrapping SETUP_MSHV elements, but it
doesn't look like there is any logic added in the kernel to parse SETUP_MSHV.
Does this leave unused structures in boot memory?
> diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
> index 6b67ac6167891..ab301dd602fbc 100644
> --- a/drivers/hv/hv_common.c
> +++ b/drivers/hv/hv_common.c
[ ... ]
> +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 (kstrtoull(range, 16, ®ion_sz) || !region_sz ||
> + kstrtoull(addr_str, 16, ®ion_start) || !region_start) {
[Severity: High]
Does the !region_start check reject physical address 0?
If the hypervisor reserves a range starting at the beginning of physical
address space (page 0), region_start will be 0. This check will treat it
as a validation failure and break out of the parsing loop.
> + pr_err("Hyper-V: invalid format for hyperv_resvd_new\n");
> + break;
> + }
> +
> + memblock_reserve(region_start, region_sz);
> +
> + hv_mshv_res[i].name = "Hypervisor Code and Data";
> + hv_mshv_res[i].flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM;
> + hv_mshv_res[i].start = region_start;
> + hv_mshv_res[i].end = region_start + region_sz - 1;
> +
> + ++i;
> + }
> +
> + ranges_nr = i;
> +
> + return 0;
> +}
> +early_param("hyperv_resvd_new", hv_parse_hyperv_resvd_new);
[ ... ]
> +void __init hv_mark_resources(void)
> +{
> + int i, max = ARRAY_SIZE(hv_mshv_res);
> +
> + for (i = 0; i < max && hv_mshv_res[i].end; i++)
[Severity: Medium]
Can stale entries in hv_mshv_res be read during resource marking?
If hv_parse_hyperv_resvd_new() is invoked multiple times (e.g. appended by
bootloader and supplied by user), the local index i resets to 0, overwriting
the head of hv_mshv_res without clearing the tail.
Because hv_mark_resources() iterates until hv_mshv_res[i].end == 0 rather
than using ranges_nr, it will process the remaining stale tail entries from
the previous parse.
> + insert_resource(&iomem_resource, &hv_mshv_res[i]);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260810124527.1409634-1-weh@linux.microsoft.com?part=12
next prev parent reply other threads:[~2026-08-10 13:05 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 12:44 [PATCH v2 00/13] mshv: add SEV-SNP support for MSHV root partitions Wei Hu
2026-08-10 12:44 ` [PATCH v2 01/13] mshv: add SEV-SNP UAPI definitions Wei Hu
2026-08-10 12:59 ` sashiko-bot
2026-08-10 12:44 ` [PATCH v2 02/13] mshv: add SEV-SNP PSP request hypercall Wei Hu
2026-08-10 12:44 ` [PATCH v2 03/13] mshv: add SEV-SNP isolated page hypercalls Wei Hu
2026-08-10 12:58 ` sashiko-bot
2026-08-10 12:44 ` [PATCH v2 04/13] mshv: wire SEV-SNP partition ioctls Wei Hu
2026-08-10 13:07 ` sashiko-bot
2026-08-10 12:44 ` [PATCH v2 05/13] hyperv: fix hv_input_get_system_property layout for SNP status Wei Hu
2026-08-10 18:59 ` Wei Liu
2026-08-10 12:45 ` [PATCH v2 06/13] mshv: detect and report SEV-SNP support at init Wei Hu
2026-08-10 12:55 ` sashiko-bot
2026-08-10 18:53 ` Wei Liu
2026-08-10 12:45 ` [PATCH v2 07/13] mshv: default to safe partition CPU features Wei Hu
2026-08-10 12:57 ` sashiko-bot
2026-08-10 12:45 ` [PATCH v2 08/13] mshv: accept partial CPU feature banks Wei Hu
2026-08-10 12:45 ` [PATCH v2 09/13] mshv: define full processor and xsave feature masks Wei Hu
2026-08-10 12:45 ` [PATCH v2 10/13] mshv: unmap SNP memory before state teardown Wei Hu
2026-08-10 13:13 ` sashiko-bot
2026-08-10 12:45 ` [PATCH v2 11/13] mshv: unlock SNP pages on panic for crashdump collection Wei Hu
2026-08-10 13:10 ` sashiko-bot
2026-08-10 12:45 ` [PATCH v2 12/13] hyperv: add MSHV Dom0 root-partition boot enablement (EFI HvLoader) Wei Hu
2026-08-10 13:05 ` sashiko-bot [this message]
2026-08-10 18:50 ` Wei Liu
2026-08-10 12:45 ` [PATCH v2 13/13] mshv: set up own SynIC registers on a nested root partition Wei Hu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260810130553.D21291F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=weh@linux.microsoft.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.