Linux kernel -stable discussions
 help / color / mirror / Atom feed
* [PATCH v2 0/3] KVM: arm64: Fix the hyp pool size on large machines, plus two hardening patches
@ 2026-11-05 22:59 Xuheng Li via B4 Relay
  2026-11-05 22:59 ` [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits Xuheng Li via B4 Relay
  0 siblings, 1 reply; 5+ messages in thread
From: Xuheng Li via B4 Relay @ 2026-11-05 22:59 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton
  Cc: Quentin Perret, Will Deacon, Catalin Marinas, Mark Rutland,
	Fuad Tabba, Joey Gouly, Steffen Eiden, Suzuki K Poulose,
	Zenghui Yu, kvmarm, linux-arm-kernel, linux-kernel, Xuheng Li,
	stable

Three changes for issues we found in pKVM as part of our research
project.

Patch 1 fixes 32-bit size computations in hyp_early_alloc_contig()
and hyp_pool_init().  The hyp page-table and host stage-2 regions reach
4 GiB on machines with about 2 TiB of RAM; the early allocator then
carves them too small, so the two pools overlap and can hand out the
same page twice.

Patch 2 checks the host stage-2 PGD allocation for NULL before using
it.  With patch 1 applied that allocation cannot fail, so this only
turns a mis-sized pool into a clean -ENOMEM instead of a hyp panic.

Patch 3 makes hyp_map_walker() refuse to replace a valid block mapping
with a table, which would skip break-before-make and unmap the rest of
the block.  Nothing in mainline maps into an existing hyp block, so this
is hardening; Android's interface for EL2 modules to map pages can reach
it.

Signed-off-by: Xuheng Li <xuheng@cs.columbia.edu>
---
Changes in v2:
- Patch 1: also fix the same overflow in hyp_early_alloc_contig(), which
  makes hpool and host_s2_pool overlap (reported by the Sashiko review of
  v1); describe that in the commit message and add its Fixes: tag.
- Link to v1: https://lore.kernel.org/r/20261105-hyp-pool-and-map-v1-0-756bb5d8e067@cs.columbia.edu

---
Xuheng Li (3):
      KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits
      KVM: arm64: Check the host stage-2 PGD allocation for NULL
      KVM: arm64: Don't replace a valid hyp block mapping with a table

 arch/arm64/kvm/hyp/nvhe/early_alloc.c | 2 +-
 arch/arm64/kvm/hyp/nvhe/mem_protect.c | 3 +++
 arch/arm64/kvm/hyp/nvhe/page_alloc.c  | 6 +++---
 arch/arm64/kvm/hyp/pgtable.c          | 7 +++++++
 4 files changed, 14 insertions(+), 4 deletions(-)
---
base-commit: 05441d697f7f9a927264f4058cbbc6a03dfcac9d
change-id: 20261105-hyp-pool-and-map-b5e7be9a1191

Best regards,
-- 
Xuheng Li <xuheng@cs.columbia.edu>



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits
  2026-11-05 22:59 [PATCH v2 0/3] KVM: arm64: Fix the hyp pool size on large machines, plus two hardening patches Xuheng Li via B4 Relay
@ 2026-11-05 22:59 ` Xuheng Li via B4 Relay
  2026-11-06 11:31   ` Fuad Tabba
  0 siblings, 1 reply; 5+ messages in thread
From: Xuheng Li via B4 Relay @ 2026-11-05 22:59 UTC (permalink / raw)
  To: Marc Zyngier, Oliver Upton
  Cc: Quentin Perret, Will Deacon, Catalin Marinas, Mark Rutland,
	Fuad Tabba, Joey Gouly, Steffen Eiden, Suzuki K Poulose,
	Zenghui Yu, kvmarm, linux-arm-kernel, linux-kernel, Xuheng Li,
	stable

From: Xuheng Li <xuheng@cs.columbia.edu>

hyp_early_alloc_contig() and hyp_pool_init() both take a page count as
an unsigned int and compute the size in bytes as nr_pages << PAGE_SHIFT
in 32 bits.  For 4 GiB or more (nr_pages >= 2^20 with 4 KiB pages) the
shift overflows.

Two of the regions that pKVM carves out at boot are sized from the
amount of memory: hyp_s1_pgtable_pages() for the hyp page tables (hpool)
and host_s2_pgtable_pages() for the host stage-2 pool both provision
page-granular tables for all of memory, about one page per 2 MiB of
RAM, so they reach 4 GiB on a machine with about 2 TiB of RAM.  Arm
systems of that size exist, for example AWS Graviton4 x8g.metal-48xl
instances (3 TiB) and Ampere Altra Max servers (up to 4 TiB per
socket).

On such a machine, divide_memory_pool() gets a truncated hyp page-table
region from hyp_early_alloc_contig(), so the host stage-2 region and the
FF-A proxy pages that follow it start inside the range that hpool will
own.  hyp_pool_init() then attaches all nr_pages pages of each pool to
its free lists, so hpool and host_s2_pool share pages and the same page
can be handed out twice, for example as a hyp stage-1 table and as a
host stage-2 table.  hyp_pool_init() also derives range_end and
max_order from the truncated size, so most of each pool is treated as
external order-0 pages; on a host whose IPA size makes the host stage-2
PGD a multi-page allocation (for example a 42-bit PARange), that
allocation fails and host_s2_zalloc_pages_exact() uses the NULL result.

Compute both sizes in 64 bits.

Fixes: e75960408723 ("KVM: arm64: Introduce an early Hyp page allocator")
Fixes: 8e17c66249e9 ("KVM: arm64: Introduce a Hyp buddy page allocator")
Cc: stable@vger.kernel.org
Signed-off-by: Xuheng Li <xuheng@cs.columbia.edu>
---
 arch/arm64/kvm/hyp/nvhe/early_alloc.c | 2 +-
 arch/arm64/kvm/hyp/nvhe/page_alloc.c  | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/early_alloc.c b/arch/arm64/kvm/hyp/nvhe/early_alloc.c
index 00de04153..f435f89be 100644
--- a/arch/arm64/kvm/hyp/nvhe/early_alloc.c
+++ b/arch/arm64/kvm/hyp/nvhe/early_alloc.c
@@ -23,7 +23,7 @@ unsigned long hyp_early_alloc_nr_used_pages(void)
 
 void *hyp_early_alloc_contig(unsigned int nr_pages)
 {
-	unsigned long size = (nr_pages << PAGE_SHIFT);
+	unsigned long size = (unsigned long)nr_pages << PAGE_SHIFT;
 	void *ret = (void *)cur;
 
 	if (!nr_pages)
diff --git a/arch/arm64/kvm/hyp/nvhe/page_alloc.c b/arch/arm64/kvm/hyp/nvhe/page_alloc.c
index 57f86aa0f..e7c10d2f7 100644
--- a/arch/arm64/kvm/hyp/nvhe/page_alloc.c
+++ b/arch/arm64/kvm/hyp/nvhe/page_alloc.c
@@ -233,16 +233,16 @@ int hyp_pool_init(struct hyp_pool *pool, u64 pfn, unsigned int nr_pages,
 		  unsigned int reserved_pages)
 {
 	phys_addr_t phys = hyp_pfn_to_phys(pfn);
+	u64 size = (u64)nr_pages << PAGE_SHIFT;
 	struct hyp_page *p;
 	int i;
 
 	hyp_spin_lock_init(&pool->lock);
-	pool->max_order = min(MAX_PAGE_ORDER,
-			      get_order(nr_pages << PAGE_SHIFT));
+	pool->max_order = min(MAX_PAGE_ORDER, get_order(size));
 	for (i = 0; i <= pool->max_order; i++)
 		INIT_LIST_HEAD(&pool->free_area[i]);
 	pool->range_start = phys;
-	pool->range_end = phys + (nr_pages << PAGE_SHIFT);
+	pool->range_end = phys + size;
 
 	/* Init the vmemmap portion */
 	p = hyp_phys_to_page(phys);

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits
  2026-11-05 22:59 ` [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits Xuheng Li via B4 Relay
@ 2026-11-06 11:31   ` Fuad Tabba
  2026-11-06 14:02     ` Mostafa Saleh
  0 siblings, 1 reply; 5+ messages in thread
From: Fuad Tabba @ 2026-11-06 11:31 UTC (permalink / raw)
  To: xuheng
  Cc: Marc Zyngier, Oliver Upton, Quentin Perret, Will Deacon,
	Catalin Marinas, Mark Rutland, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Zenghui Yu, kvmarm, linux-arm-kernel,
	linux-kernel, stable, Mostafa Saleh

Hi Xuheng,

On Thu, 05 Nov 2026 22:59:48 +0000, Xuheng Li <xuheng@cs.columbia.edu> wrote:
> hyp_early_alloc_contig() and hyp_pool_init() both take a page count as
> an unsigned int and compute the size in bytes as nr_pages << PAGE_SHIFT
> in 32 bits.  For 4 GiB or more (nr_pages >= 2^20 with 4 KiB pages) the
> shift overflows.

Mostafa (Cc'd) posted a fix for the same truncation in July [1],
widening the parameters to unsigned long instead. Would you be OK
picking up his patch for v3, keeping him as the author and your
description and tags?

> Two of the regions that pKVM carves out at boot are sized from the
> amount of memory: hyp_s1_pgtable_pages() for the hyp page tables (hpool)
> and host_s2_pgtable_pages() for the host stage-2 pool both provision
> page-granular tables for all of memory, about one page per 2 MiB of
> RAM, so they reach 4 GiB on a machine with about 2 TiB of RAM.  Arm
> systems of that size exist, for example AWS Graviton4 x8g.metal-48xl
> instances (3 TiB) and Ampere Altra Max servers (up to 4 TiB per
> socket).

Could you also list the hyp vmemmap here? It's sized the same way and
overflows at 2 TiB too.

> On such a machine, divide_memory_pool() gets a truncated hyp page-table
> region from hyp_early_alloc_contig(), so the host stage-2 region and the
> FF-A proxy pages that follow it start inside the range that hpool will
> own.  hyp_pool_init() then attaches all nr_pages pages of each pool to
> its free lists, so hpool and host_s2_pool share pages and the same page
> can be handed out twice, for example as a hyp stage-1 table and as a
> host stage-2 table.  hyp_pool_init() also derives range_end and
> max_order from the truncated size, so most of each pool is treated as
> external order-0 pages; on a host whose IPA size makes the host stage-2
> PGD a multi-page allocation (for example a 42-bit PARange), that
> allocation fails and host_s2_zalloc_pages_exact() uses the NULL result.

Could you describe here what actually happens? I think pKVM init fails
before any page is handed out twice. Just below 2 TiB, hyp_pool_init()
for host_s2_pool hits the BUG_ON() in hyp_set_page_refcounted() on
hpool's page-table pages, and from 2 TiB up hyp_back_vmemmap() zeroes
the new hyp page tables while they're being built.

Cheers,
/fuad

[1] https://lore.kernel.org/all/20260715150125.2798116-1-smostafa@google.com/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits
  2026-11-06 11:31   ` Fuad Tabba
@ 2026-11-06 14:02     ` Mostafa Saleh
  2026-11-06 14:31       ` Xuheng Li
  0 siblings, 1 reply; 5+ messages in thread
From: Mostafa Saleh @ 2026-11-06 14:02 UTC (permalink / raw)
  To: Fuad Tabba
  Cc: xuheng, Marc Zyngier, Oliver Upton, Quentin Perret, Will Deacon,
	Catalin Marinas, Mark Rutland, Joey Gouly, Steffen Eiden,
	Suzuki K Poulose, Zenghui Yu, kvmarm, linux-arm-kernel,
	linux-kernel, stable

On Fri, Nov 06, 2026 at 11:31:57AM +0000, Fuad Tabba wrote:
> Hi Xuheng,
> 
> On Thu, 05 Nov 2026 22:59:48 +0000, Xuheng Li <xuheng@cs.columbia.edu> wrote:
> > hyp_early_alloc_contig() and hyp_pool_init() both take a page count as
> > an unsigned int and compute the size in bytes as nr_pages << PAGE_SHIFT
> > in 32 bits.  For 4 GiB or more (nr_pages >= 2^20 with 4 KiB pages) the
> > shift overflows.
> 
> Mostafa (Cc'd) posted a fix for the same truncation in July [1],
> widening the parameters to unsigned long instead. Would you be OK
> picking up his patch for v3, keeping him as the author and your
> description and tags?
> 

I was preparing v3 anyway, I can post it today.

Thanks,
Mostafa

> > Two of the regions that pKVM carves out at boot are sized from the
> > amount of memory: hyp_s1_pgtable_pages() for the hyp page tables (hpool)
> > and host_s2_pgtable_pages() for the host stage-2 pool both provision
> > page-granular tables for all of memory, about one page per 2 MiB of
> > RAM, so they reach 4 GiB on a machine with about 2 TiB of RAM.  Arm
> > systems of that size exist, for example AWS Graviton4 x8g.metal-48xl
> > instances (3 TiB) and Ampere Altra Max servers (up to 4 TiB per
> > socket).
> 
> Could you also list the hyp vmemmap here? It's sized the same way and
> overflows at 2 TiB too.
> 
> > On such a machine, divide_memory_pool() gets a truncated hyp page-table
> > region from hyp_early_alloc_contig(), so the host stage-2 region and the
> > FF-A proxy pages that follow it start inside the range that hpool will
> > own.  hyp_pool_init() then attaches all nr_pages pages of each pool to
> > its free lists, so hpool and host_s2_pool share pages and the same page
> > can be handed out twice, for example as a hyp stage-1 table and as a
> > host stage-2 table.  hyp_pool_init() also derives range_end and
> > max_order from the truncated size, so most of each pool is treated as
> > external order-0 pages; on a host whose IPA size makes the host stage-2
> > PGD a multi-page allocation (for example a 42-bit PARange), that
> > allocation fails and host_s2_zalloc_pages_exact() uses the NULL result.
> 
> Could you describe here what actually happens? I think pKVM init fails
> before any page is handed out twice. Just below 2 TiB, hyp_pool_init()
> for host_s2_pool hits the BUG_ON() in hyp_set_page_refcounted() on
> hpool's page-table pages, and from 2 TiB up hyp_back_vmemmap() zeroes
> the new hyp page tables while they're being built.
> 
> Cheers,
> /fuad
> 
> [1] https://lore.kernel.org/all/20260715150125.2798116-1-smostafa@google.com/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits
  2026-11-06 14:02     ` Mostafa Saleh
@ 2026-11-06 14:31       ` Xuheng Li
  0 siblings, 0 replies; 5+ messages in thread
From: Xuheng Li @ 2026-11-06 14:31 UTC (permalink / raw)
  To: Mostafa Saleh
  Cc: Fuad Tabba, Marc Zyngier, Oliver Upton, Quentin Perret,
	Will Deacon, Catalin Marinas, Mark Rutland, Joey Gouly,
	Steffen Eiden, Suzuki K Poulose, Zenghui Yu, kvmarm,
	linux-arm-kernel, linux-kernel, stable

Hi Mostafa, Fuad,

On Fri, Nov 06, 2026 at 02:02:40PM +0000, Mostafa Saleh wrote:
> I was preparing v3 anyway, I can post it today.

Thanks Mostafa, and thanks Fuad for the pointer and the correction.
I'll drop my patch 1 in favour of Mostafa's updated patch. Fuad's
description of what happens (pKVM init failing at the BUG_ON() in
hyp_set_page_refcounted() just below 2 TiB, and in hyp_back_vmemmap()
from 2 TiB up) is more accurate than mine, and the hyp vmemmap
overflows the same way. Mostafa, feel free to reuse any of my commit
message.

Thanks,
Xuheng

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-11-06 14:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 22:59 [PATCH v2 0/3] KVM: arm64: Fix the hyp pool size on large machines, plus two hardening patches Xuheng Li via B4 Relay
2026-11-05 22:59 ` [PATCH v2 1/3] KVM: arm64: Compute hyp early-allocation and pool sizes in 64 bits Xuheng Li via B4 Relay
2026-11-06 11:31   ` Fuad Tabba
2026-11-06 14:02     ` Mostafa Saleh
2026-11-06 14:31       ` Xuheng Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox