Linux-HyperV List
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Wei Hu" <weh@linux.microsoft.com>
Cc: linux-hyperv@vger.kernel.org
Subject: Re: [PATCH v4 1/9] mshv: retain memory regions until unmap succeeds
Date: Mon, 31 Aug 2026 11:48:33 +0000	[thread overview]
Message-ID: <20260831114834.586961F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260831112704.2851147-2-weh@linux.microsoft.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [Critical] Early return in MMU interval notifier allows guest-to-host use-after-free because it falsely signals that guest access has been revoked before the hypervisor unmap completes.
- [High] ABBA deadlock between `mreg_remap_lock` rwsem fair-queueing and HMM sequence counter invalidation due to holding locks across a retry loop.

Pre-existing issues:
- [Critical] mshv_region_interval_invalidate() returns false for blockable ranges if remapping fails, leading to silent UAF.
- [Critical] Incorrect MMIO physical address mapped for user memory region, allowing arbitrary physical memory access.
--

commit bdfaa07680341c254374f6fa979c3fcd550c4840
Author: Wei Hu <weh@microsoft.com>

mshv: retain memory regions until unmap succeeds

Do not remove a region from the partition list or unpin its pages until
a checked UnmapGpaPages hypercall has completed. Validate repetition
progress so malformed zero or oversized completion counts cannot spin or
conceal partial state.

[ ... ]

> diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
> index 6d65e5b421529..9feb49d9d9d49 100644
> --- a/drivers/hv/mshv_regions.c
> +++ b/drivers/hv/mshv_regions.c

[ ... ]

> @@ -452,12 +458,35 @@ static int mshv_region_range_fault(struct mshv_mem_region *region,
>  	range.start = region->start_uaddr + page_offset * HV_HYP_PAGE_SIZE;
>  	range.end = range.start + page_count * HV_HYP_PAGE_SIZE;
>  
> +	/*
> +	 * Pin the mm while the remap gate still guarantees that the interval
> +	 * notifier is registered. Do not acquire mmap_lock while holding the
> +	 * gate: invalidation enters with mmap_lock held for write.
> +	 */
> +	down_read(&region->mreg_remap_lock);
> +	if (READ_ONCE(region->remap_blocked) ||
> +	    !mmget_not_zero(region->mreg_mni.mm)) {
> +		up_read(&region->mreg_remap_lock);
> +		ret = -ECANCELED;
> +		goto out;
> +	}
> +	mm = region->mreg_mni.mm;
> +	up_read(&region->mreg_remap_lock);
> +
> +	/* Lock order: mmap_lock -> mreg_remap_lock -> mreg_mutex. */
> +	mmap_read_lock(mm);
> +	down_read(&region->mreg_remap_lock);
> +	if (READ_ONCE(region->remap_blocked)) {
> +		ret = -ECANCELED;
> +		goto out_unlock_remap;
> +	}
> +
>  	do {
>  		ret = mshv_region_hmm_fault_and_lock(region, &range);
>  	} while (ret == -EBUSY);

[Severity: High]
Does holding mreg_remap_lock across this retry loop create an ABBA deadlock?

If a concurrent page fault and region unmap occur:
1. The fault handler acquires mreg_remap_lock for read and blocks here waiting
   for mmu_interval_read_retry() to clear.
2. The unmap thread queues for the mreg_remap_lock write lock in
   mshv_unmap_user_memory(), blocking new readers due to fair-queueing.
3. The MMU interval invalidation callback mshv_region_interval_invalidate()
   (which would clear the retry loop) attempts to acquire mreg_remap_lock for
   read, but gets stuck behind the queued writer.

Can the fault handler loop forever holding the read lock, freezing the host
kernel?

[ ... ]

> @@ -524,6 +558,17 @@ static bool mshv_region_interval_invalidate(struct mmu_interval_notifier *mni,
>  	unsigned long mstart, mend;
>  	int ret = -EPERM;
>  
> +	if (mmu_notifier_range_blockable(range))
> +		down_read(&region->mreg_remap_lock);
> +	else if (!down_read_trylock(&region->mreg_remap_lock))
> +		return false;
> +
> +	/* A completed checked unmap makes notifier remapping unnecessary. */
> +	if (READ_ONCE(region->remap_blocked)) {
> +		up_read(&region->mreg_remap_lock);
> +		return true;
> +	}

[Severity: Critical]
Does this early return falsely signal that guest access has been revoked before
the hypervisor unmap completes?

If mshv_unmap_user_memory() sets remap_blocked = true but has not yet acquired
the mreg_remap_lock write lock to issue the hypervisor unmap, a racing MMU
invalidation could acquire the read lock first, see remap_blocked == true, and
immediately return true.

Could the MM subsystem then free the page while the hypervisor unmap has not
yet executed, leading to a guest-to-host use-after-free?

[ ... ]

>  out_unlock:
>  	mutex_unlock(&region->mreg_mutex);
>  out_fail:
> +	up_read(&region->mreg_remap_lock);
>  	WARN_ONCE(ret,
>  		  "Failed to invalidate region %#llx-%#llx (range %#lx-%#lx, event: %u, pages %#llx-%#llx, mm: %#llx): %d\n",
>  		  region->start_uaddr,

[Severity: Critical]
This is a pre-existing issue, but does mshv_region_interval_invalidate()
return false on a blockable range if mshv_region_remap_pages() fails?

The core MM __mmu_notifier_invalidate_range_start() explicitly ignores the
return value of blockable notifiers. By returning false instead of ensuring
the mapping is torn down, the driver silently fails the invalidation contract.

Does this allow the core MM subsystem to free or reuse a host page while the
guest VM retains mapped access to it, resulting in a guest-to-host
use-after-free?

[ ... ]

> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index cc2cfce2aefdb..1ca14660f9985 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c

[ ... ]

> @@ -1397,13 +1398,15 @@ mshv_map_user_memory(struct mshv_partition *partition,
>  		ret = hv_call_map_gpa_pages(partition->pt_id,
>  					    region->start_gfn,
>  					    region->nr_pages,
> -					    HV_MAP_GPA_NO_ACCESS, NULL);
> +					    HV_MAP_GPA_NO_ACCESS, NULL,
> +					    &region->mapping_may_exist);
>  		break;
>  	case MSHV_REGION_TYPE_MMIO:
>  		ret = hv_call_map_mmio_pages(partition->pt_id,
>  					     region->start_gfn,
>  					     mmio_pfn,
> -					     region->nr_pages);
> +					     region->nr_pages,
> +					     &region->mapping_may_exist);
>  		break;
>  	}

[Severity: Critical]
This is a pre-existing issue, but does mshv_map_user_memory() allow mapping of
arbitrary physical memory by passing an unadjusted MMIO PFN and unvalidated
size directly to the hypervisor?

By using vma->vm_pgoff directly without adding the intra-VMA offset
corresponding to the userspace_addr, and by failing to validate that the
requested size fits inside vma->vm_end:

drivers/hv/mshv_root_main.c:mshv_map_user_memory() {
	vma = vma_lookup(current->mm, mem->userspace_addr);
	is_mmio = vma ? !!(vma->vm_flags & (VM_IO | VM_PFNMAP)) : 0;
	mmio_pfn = is_mmio ? vma->vm_pgoff : 0;
    ...
}

Could a malicious userspace process set userspace_addr to an offset within a
legitimate MMIO VMA (or beyond it) and map arbitrary contiguous physical
memory into the guest VM?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260831112704.2851147-1-weh@linux.microsoft.com?part=1

  reply	other threads:[~2026-08-31 11:48 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-25  4:04 [PATCH v3 0/7] mshv: add SEV-SNP support for MSHV root partitions Wei Hu
2026-08-25  4:04 ` [PATCH v3 1/7] mshv: add SEV-SNP UAPI definitions Wei Hu
2026-08-25  4:04 ` [PATCH v3 2/7] mshv: add SEV-SNP PSP request hypercall Wei Hu
2026-08-25  4:17   ` sashiko-bot
2026-08-25  4:04 ` [PATCH v3 3/7] mshv: add SEV-SNP isolated page hypercalls Wei Hu
2026-08-25  4:04 ` [PATCH v3 4/7] mshv: wire SEV-SNP partition ioctls Wei Hu
2026-08-25  4:22   ` sashiko-bot
2026-08-25  4:04 ` [PATCH v3 5/7] mshv: detect and report SEV-SNP support at init Wei Hu
2026-08-25  4:19   ` sashiko-bot
2026-08-25  4:04 ` [PATCH v3 6/7] mshv: use safe partition CPU feature defaults Wei Hu
2026-08-25  4:04 ` [PATCH v3 7/7] mshv: set up own SynIC registers on a nested root partition Wei Hu
2026-08-25  4:20   ` sashiko-bot
2026-08-31 11:26 ` [PATCH v4 0/9] mshv: add SEV-SNP support for MSHV root partitions Wei Hu
2026-08-31 11:26   ` [PATCH v4 1/9] mshv: retain memory regions until unmap succeeds Wei Hu
2026-08-31 11:48     ` sashiko-bot [this message]
2026-09-01 12:04       ` [EXTERNAL] " Wei Hu
2026-08-31 11:26   ` [PATCH v4 2/9] mshv: clear SynIC mappings before freeing them Wei Hu
2026-08-31 11:26   ` [PATCH v4 3/9] mshv: add SEV-SNP UAPI definitions Wei Hu
2026-08-31 11:26   ` [PATCH v4 4/9] mshv: add SEV-SNP PSP request hypercall Wei Hu
2026-08-31 11:26   ` [PATCH v4 5/9] mshv: add SEV-SNP isolated page hypercalls Wei Hu
2026-08-31 11:53     ` sashiko-bot
2026-08-31 11:26   ` [PATCH v4 6/9] mshv: wire SEV-SNP partition ioctls Wei Hu
2026-08-31 12:07     ` sashiko-bot
2026-08-31 11:26   ` [PATCH v4 7/9] mshv: detect and report SEV-SNP support at init Wei Hu
2026-08-31 11:26   ` [PATCH v4 8/9] mshv: use safe partition CPU feature defaults Wei Hu
2026-08-31 11:26   ` [PATCH v4 9/9] mshv: set up own SynIC registers on a nested root partition Wei Hu
2026-08-31 12:09     ` sashiko-bot

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=20260831114834.586961F000E9@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox