Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
@ 2026-11-02 11:31 Pankaj Gupta
  2026-11-02 11:41 ` Ard Biesheuvel
  2026-11-03 11:31 ` sashiko-bot
  0 siblings, 2 replies; 8+ messages in thread
From: Pankaj Gupta @ 2026-11-02 11:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Ard Biesheuvel, Kiryl Shutsemau,
	linux-kernel, Mike Rapoport, linux-mm, Pankaj.gupta, Pankaj Gupta

The EFI stub builds the unaccepted memory bitmap before the kernel parses
its command line.  Option memmap=<size>$<addr> removes RAM from the E820
map while its bits are still set in the bitmap.

The removed range, such as a memmap=...$... hole, is then still treated as
unaccepted RAM and accept_memory() tries to accept it.  The hole is not
mapped, so on SEV-SNP the PVALIDATE faults and the guest crashes early in
the boot:

  BUG: unable to handle page fault for address: ffff8a14bfe00000
  RIP: 0010:pvalidate_pages+0xc0/0x250
   set_pages_state+0x41a/0x440
   snp_accept_memory+0x3e/0x50
   accept_memory+0x186/0x260
   __free_pages_core+0xd2/0x240
   memblock_free_pages+0x1b/0x30
   memblock_free_all+0x275/0x2d0

This was seen with memmap=2M$0x1ffe00000, a 2 MiB hole in RAM, on a 19 GiB
SNP guest with lazy acceptance.

Fixes: 2053bc57f367 ("efi: Add unaccepted memory support")
Signed-off-by: Pankaj Gupta <pankaj.gupta@amd.com>
---
 arch/x86/include/asm/unaccepted_memory.h | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
index f5937e9866ac..744f1a993352 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -2,10 +2,11 @@
 #define _ASM_X86_UNACCEPTED_MEMORY_H
 
 #include <linux/efi.h>
+#include <asm/e820/api.h>
 #include <asm/tdx.h>
 #include <asm/sev.h>
 
-static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
+static inline void __arch_accept_memory(phys_addr_t start, phys_addr_t end)
 {
 	/* Platform-specific memory-acceptance call goes here */
 	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
@@ -18,6 +19,26 @@ static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
 	}
 }
 
+static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
+{
+	u32 i;
+
+	for (i = 0; i < e820_table->nr_entries; i++) {
+		struct e820_entry *entry = &e820_table->entries[i];
+		phys_addr_t s, e;
+
+		if (entry->type != E820_TYPE_RAM)
+			continue;
+
+		s = max_t(phys_addr_t, start, entry->addr);
+		e = min_t(phys_addr_t, end, entry->addr + entry->size);
+		if (s >= e)
+			continue;
+
+		__arch_accept_memory(s, e);
+	}
+}
+
 static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void)
 {
 	if (efi.unaccepted == EFI_INVALID_TABLE_ADDR)
-- 
2.34.1



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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-02 11:31 [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM Pankaj Gupta
@ 2026-11-02 11:41 ` Ard Biesheuvel
  2026-11-02 11:51   ` Gupta, Pankaj
  2026-11-03 11:31 ` sashiko-bot
  1 sibling, 1 reply; 8+ messages in thread
From: Ard Biesheuvel @ 2026-11-02 11:41 UTC (permalink / raw)
  To: Pankaj Gupta, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Kiryl Shutsemau (Meta),
	linux-kernel, Mike Rapoport, linux-mm

Hello Pankaj,

On Mon, 2 Nov 2026, at 12:31, Pankaj Gupta wrote:
> The EFI stub builds the unaccepted memory bitmap before the kernel parses
> its command line.  Option memmap=<size>$<addr> removes RAM from the E820
> map while its bits are still set in the bitmap.
>
> The removed range, such as a memmap=...$... hole, is then still treated as
> unaccepted RAM and accept_memory() tries to accept it.  The hole is not
> mapped, so on SEV-SNP the PVALIDATE faults and the guest crashes early in
> the boot:
>
>   BUG: unable to handle page fault for address: ffff8a14bfe00000
>   RIP: 0010:pvalidate_pages+0xc0/0x250
>    set_pages_state+0x41a/0x440
>    snp_accept_memory+0x3e/0x50
>    accept_memory+0x186/0x260
>    __free_pages_core+0xd2/0x240
>    memblock_free_pages+0x1b/0x30
>    memblock_free_all+0x275/0x2d0
>
> This was seen with memmap=2M$0x1ffe00000, a 2 MiB hole in RAM, on a 19 GiB
> SNP guest with lazy acceptance.
>
> Fixes: 2053bc57f367 ("efi: Add unaccepted memory support")
> Signed-off-by: Pankaj Gupta <pankaj.gupta@amd.com>
> ---
>  arch/x86/include/asm/unaccepted_memory.h | 23 ++++++++++++++++++++++-
>  1 file changed, 22 insertions(+), 1 deletion(-)
>

Can we just disallow memmap= when running in a confidential VM?



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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-02 11:41 ` Ard Biesheuvel
@ 2026-11-02 11:51   ` Gupta, Pankaj
  2026-11-02 12:01     ` Gupta, Pankaj
  0 siblings, 1 reply; 8+ messages in thread
From: Gupta, Pankaj @ 2026-11-02 11:51 UTC (permalink / raw)
  To: Ard Biesheuvel, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Kiryl Shutsemau (Meta),
	linux-kernel, Mike Rapoport, linux-mm

Hi Ard,

> Hello Pankaj,
>
> On Mon, 2 Nov 2026, at 12:31, Pankaj Gupta wrote:
>> The EFI stub builds the unaccepted memory bitmap before the kernel parses
>> its command line.  Option memmap=<size>$<addr> removes RAM from the E820
>> map while its bits are still set in the bitmap.
>>
>> The removed range, such as a memmap=...$... hole, is then still treated as
>> unaccepted RAM and accept_memory() tries to accept it.  The hole is not
>> mapped, so on SEV-SNP the PVALIDATE faults and the guest crashes early in
>> the boot:
>>
>>    BUG: unable to handle page fault for address: ffff8a14bfe00000
>>    RIP: 0010:pvalidate_pages+0xc0/0x250
>>     set_pages_state+0x41a/0x440
>>     snp_accept_memory+0x3e/0x50
>>     accept_memory+0x186/0x260
>>     __free_pages_core+0xd2/0x240
>>     memblock_free_pages+0x1b/0x30
>>     memblock_free_all+0x275/0x2d0
>>
>> This was seen with memmap=2M$0x1ffe00000, a 2 MiB hole in RAM, on a 19 GiB
>> SNP guest with lazy acceptance.
>>
>> Fixes: 2053bc57f367 ("efi: Add unaccepted memory support")
>> Signed-off-by: Pankaj Gupta <pankaj.gupta@amd.com>
>> ---
>>   arch/x86/include/asm/unaccepted_memory.h | 23 ++++++++++++++++++++++-
>>   1 file changed, 22 insertions(+), 1 deletion(-)
>>
> Can we just disallow memmap= when running in a confidential VM?

My experiments showed: memmap itself don't have a problem but memap with 
a hole is causing crash.

There might be some usecases which are already using this, e.g:

https://lore.kernel.org/all/20261029-cma-multi-v1-0-2cbced8b5cb7@kernel.org/

Thanks,

Pankaj


>


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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-02 11:51   ` Gupta, Pankaj
@ 2026-11-02 12:01     ` Gupta, Pankaj
  2026-11-02 12:11       ` Ard Biesheuvel
  0 siblings, 1 reply; 8+ messages in thread
From: Gupta, Pankaj @ 2026-11-02 12:01 UTC (permalink / raw)
  To: Ard Biesheuvel, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Kiryl Shutsemau (Meta),
	linux-kernel, Mike Rapoport, linux-mm

>>>
>> Can we just disallow memmap= when running in a confidential VM?
>
> My experiments showed: memmap itself don't have a problem but memap 
> with a hole is causing crash.
>
> There might be some usecases which are already using this, e.g:
>
> https://lore.kernel.org/all/20261029-cma-multi-v1-0-2cbced8b5cb7@kernel.org/ 
>
>
Its also good to have a general safeguard to not accept memory that is 
not marked as RAM in e820?

Thanks,

Pankaj



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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-02 12:01     ` Gupta, Pankaj
@ 2026-11-02 12:11       ` Ard Biesheuvel
  2026-11-03 11:31         ` Gupta, Pankaj
  0 siblings, 1 reply; 8+ messages in thread
From: Ard Biesheuvel @ 2026-11-02 12:11 UTC (permalink / raw)
  To: Pankaj Gupta, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Kiryl Shutsemau (Meta),
	linux-kernel, Mike Rapoport, linux-mm



On Mon, 2 Nov 2026, at 13:01, Gupta, Pankaj wrote:
>>>>
>>> Can we just disallow memmap= when running in a confidential VM?
>>
>> My experiments showed: memmap itself don't have a problem but memap 
>> with a hole is causing crash.
>>
>> There might be some usecases which are already using this, e.g:
>>
>> https://lore.kernel.org/all/20261029-cma-multi-v1-0-2cbced8b5cb7@kernel.org/ 
>>
>>
> Its also good to have a general safeguard to not accept memory that is 
> not marked as RAM in e820?
>

Personally, I think all these command line hacks should be avoided in
confidential VMs, on the basis that the firmware's view of memory should
be in sync with the OS.



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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-02 12:11       ` Ard Biesheuvel
@ 2026-11-03 11:31         ` Gupta, Pankaj
  0 siblings, 0 replies; 8+ messages in thread
From: Gupta, Pankaj @ 2026-11-03 11:31 UTC (permalink / raw)
  To: Ard Biesheuvel, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Kiryl Shutsemau (Meta),
	linux-kernel, Mike Rapoport, linux-mm

>>>> Can we just disallow memmap= when running in a confidential VM?
>>> My experiments showed: memmap itself don't have a problem but memap
>>> with a hole is causing crash.
>>>
>>> There might be some usecases which are already using this, e.g:
>>>
>>> https://lore.kernel.org/all/20261029-cma-multi-v1-0-2cbced8b5cb7@kernel.org/
>>>
>>>
>> Its also good to have a general safeguard to not accept memory that is
>> not marked as RAM in e820?
>>
> Personally, I think all these command line hacks should be avoided in
> confidential VMs, on the basis that the firmware's view of memory should
> be in sync with the OS.
Fair enough. I can post a separate on top RFC patch to disable memmap= 
holes completely
for confidential guests and see if anybody objects.

That said, this patch fixes a real crash with memmap= holes 
functionality in confidential guests today,
and should be backported to stable kernels as well. It also hardens the 
existing code to only accept the
e820 RAM regions.

Thanks for having a look!

Pankaj



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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-02 11:31 [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM Pankaj Gupta
  2026-11-02 11:41 ` Ard Biesheuvel
@ 2026-11-03 11:31 ` sashiko-bot
  2026-11-04 11:41   ` Gupta, Pankaj
  1 sibling, 1 reply; 8+ messages in thread
From: sashiko-bot @ 2026-11-03 11:31 UTC (permalink / raw)
  To: Pankaj Gupta, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Ard Biesheuvel, Kiryl Shutsemau,
	Mike Rapoport, linux-mm

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] x86/unaccepted_memory: arch_accept_memory() desynchronizes unaccepted bitmap
- [High] x86/unaccepted_memory: unaligned E820 bounds passed to __arch_accept_memory()
--

commit f56630bdf157fa53e09d29e75f1fc454adb6cd1e
Author: Pankaj Gupta <pankaj.gupta@amd.com>

x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM

This commit updates arch_accept_memory() on x86 to iterate over e820_table
and only accept subranges that are marked as E820_TYPE_RAM. This avoids
attempting to accept memory holes removed via the memmap= command-line
parameter.

> diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
> index f5937e9866ac1..744f1a993352c 100644
> --- a/arch/x86/include/asm/unaccepted_memory.h
> +++ b/arch/x86/include/asm/unaccepted_memory.h
> @@ -2,10 +2,11 @@
>  #define _ASM_X86_UNACCEPTED_MEMORY_H
>  
>  #include <linux/efi.h>
> +#include <asm/e820/api.h>
>  #include <asm/tdx.h>
>  #include <asm/sev.h>
>  
> -static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
> +static inline void __arch_accept_memory(phys_addr_t start, phys_addr_t end)
>  {
>  	/* Platform-specific memory-acceptance call goes here */
>  	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
> @@ -18,6 +19,26 @@ static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
>  	}
>  }
>  
> +static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
> +{
> +	u32 i;
> +
> +	for (i = 0; i < e820_table->nr_entries; i++) {
> +		struct e820_entry *entry = &e820_table->entries[i];
> +		phys_addr_t s, e;
> +
> +		if (entry->type != E820_TYPE_RAM)
> +			continue;

[Severity: High]
Does skipping non-E820_TYPE_RAM ranges here desynchronize unaccepted->bitmap
from the actual hardware page acceptance state across kdump and kexec?

In drivers/firmware/efi/unaccepted_memory.c:accept_memory(), unit_size-aligned
range ends are extended by an extra unit_size to act as a guard page for
load_unaligned_zeropad(), and the bits in unaccepted->bitmap are cleared
unconditionally after arch_accept_memory() returns:

drivers/firmware/efi/unaccepted_memory.c:accept_memory() {
	...
	/*
	 * load_unaligned_zeropad() can lead to unwanted loads across page
	 * boundaries. The unwanted loads are typically harmless. Map an
	 * extra unit if the end of the requested range is aligned to
	 * unit_size to avoid page faults on unaccepted memory.
	 */
	if (!(end % unit_size))
		end += unit_size;
	...
		arch_accept_memory(phys_start, phys_end);

		spin_lock(&unaccepted_memory_lock);
		bitmap_clear(unaccepted->bitmap, range_start, len);
	...
}

When arch_accept_memory() skips a range that is not E820_TYPE_RAM in
e820_table, accept_memory() still clears its bit in unaccepted->bitmap even
though the pages were never accepted in hardware.

In a kdump kernel, e820_table only contains the crashkernel reservation as
E820_TYPE_RAM while the panicked kernel's remaining RAM is omitted from
e820_table. When the crash kernel accepts memory up to the 2 MiB-aligned end
of crashk_res, accept_memory() extends end by unit_size into the panicked
kernel's adjacent unaccepted RAM. arch_accept_memory() skips that range, but
accept_memory() clears its bit in unaccepted->bitmap. Later, when /proc/vmcore
is read, unaccepted_memory_vmcore_pfn_is_ram() checks
!pfn_is_unaccepted_memory(pfn), sees the cleared bit, and reads the
unaccepted page via read_from_oldmem(), crashing the kdump kernel.

A similar mismatch occurs with kexec: e820__memory_setup() populates
e820_table_kexec before parse_early_param() applies memmap= or mem= options
to e820_table, andarch/x86/kernel/kexec-bzimage64.c:setup_e820_entries()
passes e820_table_kexec to the next kernel while sharing the physical
efi.unaccepted table. Both kernel/kexec_core.c:sanity_check_segment_list()
(which calls accept_memory() on kexec segment destinations placed in
e820_table_kexec RAM) and the unit_size extension at the boundary before a
memmap= hole will clear bits in unaccepted->bitmap without accepting the
memory in hardware, causing the kexec load or the next kernel to fault on
those pages.

> +
> +		s = max_t(phys_addr_t, start, entry->addr);
> +		e = min_t(phys_addr_t, end, entry->addr + entry->size);
> +		if (s >= e)
> +			continue;
> +
> +		__arch_accept_memory(s, e);

[Severity: High]
What happens if entry->addr or entry->addr + entry->size is not aligned to
PAGE_SIZE?

Entries in e820_table can have byte-granular boundaries from firmware or
command-line options such as memmap= and mem=. When memblock is set up in
arch/x86/kernel/e820.c:e820__memblock_setup(), partial pages are trimmed via
memblock_trim_memory(PAGE_SIZE) and left unmapped in the direct map, whereas
e820_table retains the unaligned addresses.

Clamping s and e directly to entry->addr and entry->addr + entry->size can
therefore pass non-page-aligned boundaries to __arch_accept_memory(s, e):

1. On TDX, tdx_accept_memory() -> try_accept_one() requires start to be
   aligned to at least PG_LEVEL_4K and len to be at least PAGE_SIZE:

   arch/x86/coco/tdx/tdx-shared.c:try_accept_one() {
   	...
   	if (!IS_ALIGNED(start, accept_size))
   		return 0;

   	if (len < accept_size)
   		return 0;
   	...
   }

   An unaligned s or a trailing sub-page remainder causes tdx_accept_memory()
   to return false and __arch_accept_memory() to call
   panic("TDX: Failed to accept memory\n").

2. On SEV-SNP, snp_accept_memory() passes vaddr = (unsigned long)__va(start)
   and npages = (end - start) >> PAGE_SHIFT to set_pages_state(), which
   masks vaddr with PAGE_MASK. If s is not page-aligned, vaddr & PAGE_MASK
   rounds down into the unmapped partial page trimmed by
   memblock_trim_memory(PAGE_SIZE) and faults in pvalidate_pages(), while
   (e - s) >> PAGE_SHIFT can truncate npages and leave the last full page
   unaccepted.

Should s be rounded up with PAGE_ALIGN(s) and e rounded down with
PAGE_ALIGN_DOWN(e) before checking s >= e?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261102113127.161823-1-pankaj.gupta@amd.com?part=1


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

* Re: [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
  2026-11-03 11:31 ` sashiko-bot
@ 2026-11-04 11:41   ` Gupta, Pankaj
  0 siblings, 0 replies; 8+ messages in thread
From: Gupta, Pankaj @ 2026-11-04 11:41 UTC (permalink / raw)
  To: sashiko-reviews, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86
  Cc: H . Peter Anvin, Tom Lendacky, Ard Biesheuvel, Kiryl Shutsemau,
	Mike Rapoport, linux-mm


> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] x86/unaccepted_memory: arch_accept_memory() desynchronizes unaccepted bitmap
> - [High] x86/unaccepted_memory: unaligned E820 bounds passed to __arch_accept_memory()
> --
>
> commit f56630bdf157fa53e09d29e75f1fc454adb6cd1e
> Author: Pankaj Gupta <pankaj.gupta@amd.com>
>
> x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM
>
> This commit updates arch_accept_memory() on x86 to iterate over e820_table
> and only accept subranges that are marked as E820_TYPE_RAM. This avoids
> attempting to accept memory holes removed via the memmap= command-line
> parameter.
>
>> diff --git a/arch/x86/include/asm/unaccepted_memory.h b/arch/x86/include/asm/unaccepted_memory.h
>> index f5937e9866ac1..744f1a993352c 100644
>> --- a/arch/x86/include/asm/unaccepted_memory.h
>> +++ b/arch/x86/include/asm/unaccepted_memory.h
>> @@ -2,10 +2,11 @@
>>   #define _ASM_X86_UNACCEPTED_MEMORY_H
>>   
>>   #include <linux/efi.h>
>> +#include <asm/e820/api.h>
>>   #include <asm/tdx.h>
>>   #include <asm/sev.h>
>>   
>> -static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
>> +static inline void __arch_accept_memory(phys_addr_t start, phys_addr_t end)
>>   {
>>   	/* Platform-specific memory-acceptance call goes here */
>>   	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
>> @@ -18,6 +19,26 @@ static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
>>   	}
>>   }
>>   
>> +static inline void arch_accept_memory(phys_addr_t start, phys_addr_t end)
>> +{
>> +	u32 i;
>> +
>> +	for (i = 0; i < e820_table->nr_entries; i++) {
>> +		struct e820_entry *entry = &e820_table->entries[i];
>> +		phys_addr_t s, e;
>> +
>> +		if (entry->type != E820_TYPE_RAM)
>> +			continue;
> [Severity: High]
> Does skipping non-E820_TYPE_RAM ranges here desynchronize unaccepted->bitmap
> from the actual hardware page acceptance state across kdump and kexec?
>
> In drivers/firmware/efi/unaccepted_memory.c:accept_memory(), unit_size-aligned
> range ends are extended by an extra unit_size to act as a guard page for
> load_unaligned_zeropad(), and the bits in unaccepted->bitmap are cleared
> unconditionally after arch_accept_memory() returns:
>
> drivers/firmware/efi/unaccepted_memory.c:accept_memory() {
> 	...
> 	/*
> 	 * load_unaligned_zeropad() can lead to unwanted loads across page
> 	 * boundaries. The unwanted loads are typically harmless. Map an
> 	 * extra unit if the end of the requested range is aligned to
> 	 * unit_size to avoid page faults on unaccepted memory.
> 	 */
> 	if (!(end % unit_size))
> 		end += unit_size;
> 	...
> 		arch_accept_memory(phys_start, phys_end);
>
> 		spin_lock(&unaccepted_memory_lock);
> 		bitmap_clear(unaccepted->bitmap, range_start, len);
> 	...
> }
>
> When arch_accept_memory() skips a range that is not E820_TYPE_RAM in
> e820_table, accept_memory() still clears its bit in unaccepted->bitmap even
> though the pages were never accepted in hardware.
>
> In a kdump kernel, e820_table only contains the crashkernel reservation as
> E820_TYPE_RAM while the panicked kernel's remaining RAM is omitted from
> e820_table. When the crash kernel accepts memory up to the 2 MiB-aligned end
> of crashk_res, accept_memory() extends end by unit_size into the panicked
> kernel's adjacent unaccepted RAM. arch_accept_memory() skips that range, but
> accept_memory() clears its bit in unaccepted->bitmap. Later, when /proc/vmcore
> is read, unaccepted_memory_vmcore_pfn_is_ram() checks
> !pfn_is_unaccepted_memory(pfn), sees the cleared bit, and reads the
> unaccepted page via read_from_oldmem(), crashing the kdump kernel.
>
> A similar mismatch occurs with kexec: e820__memory_setup() populates
> e820_table_kexec before parse_early_param() applies memmap= or mem= options
> to e820_table, andarch/x86/kernel/kexec-bzimage64.c:setup_e820_entries()
> passes e820_table_kexec to the next kernel while sharing the physical
> efi.unaccepted table. Both kernel/kexec_core.c:sanity_check_segment_list()
> (which calls accept_memory() on kexec segment destinations placed in
> e820_table_kexec RAM) and the unit_size extension at the boundary before a
> memmap= hole will clear bits in unaccepted->bitmap without accepting the
> memory in hardware, causing the kexec load or the next kernel to fault on
> those pages.

Valid bug. In v2, I will clear the bits only for the units in which 
memory was actually accepted.

>
>> +
>> +		s = max_t(phys_addr_t, start, entry->addr);
>> +		e = min_t(phys_addr_t, end, entry->addr + entry->size);
>> +		if (s >= e)
>> +			continue;
>> +
>> +		__arch_accept_memory(s, e);
> [Severity: High]
> What happens if entry->addr or entry->addr + entry->size is not aligned to
> PAGE_SIZE?
>
> Entries in e820_table can have byte-granular boundaries from firmware or
> command-line options such as memmap= and mem=. When memblock is set up in
> arch/x86/kernel/e820.c:e820__memblock_setup(), partial pages are trimmed via
> memblock_trim_memory(PAGE_SIZE) and left unmapped in the direct map, whereas
> e820_table retains the unaligned addresses.
>
> Clamping s and e directly to entry->addr and entry->addr + entry->size can
> therefore pass non-page-aligned boundaries to __arch_accept_memory(s, e):
>
> 1. On TDX, tdx_accept_memory() -> try_accept_one() requires start to be
>     aligned to at least PG_LEVEL_4K and len to be at least PAGE_SIZE:
>
>     arch/x86/coco/tdx/tdx-shared.c:try_accept_one() {
>     	...
>     	if (!IS_ALIGNED(start, accept_size))
>     		return 0;
>
>     	if (len < accept_size)
>     		return 0;
>     	...
>     }
>
>     An unaligned s or a trailing sub-page remainder causes tdx_accept_memory()
>     to return false and __arch_accept_memory() to call
>     panic("TDX: Failed to accept memory\n").
>
> 2. On SEV-SNP, snp_accept_memory() passes vaddr = (unsigned long)__va(start)
>     and npages = (end - start) >> PAGE_SHIFT to set_pages_state(), which
>     masks vaddr with PAGE_MASK. If s is not page-aligned, vaddr & PAGE_MASK
>     rounds down into the unmapped partial page trimmed by
>     memblock_trim_memory(PAGE_SIZE) and faults in pvalidate_pages(), while
>     (e - s) >> PAGE_SHIFT can truncate npages and leave the last full page
>     unaccepted.
>
> Should s be rounded up with PAGE_ALIGN(s) and e rounded down with
> PAGE_ALIGN_DOWN(e) before checking s >= e?

Also valid bug. I will address the alignment issue in v2.

Thanks!

Pankaj


>


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

end of thread, other threads:[~2026-11-04 11:43 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-02 11:31 [PATCH] x86/unaccepted_memory: Do not accept ranges that are no longer E820 RAM Pankaj Gupta
2026-11-02 11:41 ` Ard Biesheuvel
2026-11-02 11:51   ` Gupta, Pankaj
2026-11-02 12:01     ` Gupta, Pankaj
2026-11-02 12:11       ` Ard Biesheuvel
2026-11-03 11:31         ` Gupta, Pankaj
2026-11-03 11:31 ` sashiko-bot
2026-11-04 11:41   ` Gupta, Pankaj

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