Skip to contentSkip to conversation

x86/mm/KASLR: Fix the size of vmemmap section

PATCH In review Baoquan He 3 participants 5 messages May 23, 2019 – Jun 8, 2019 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore

Baoquan He

author
#0 lore raw

PATCH v5 1/1 x86/mm/KASLR: Fix the size of vmemmap section

kernel_randomize_memory() hardcodes the size of vmemmap section as 1 TB, to support the maximum amount of system RAM in 4-level paging mode, 64 TB.

However, 1 TB is not enough for vmemmap in 5-level paging mode. Assuming the size of struct page is 64 Bytes, to support 4 PB system RAM in 5-level, 64 TB of vmemmap area is needed. The wrong hardcoding may cause vmemmap stamping into the following cpu_entry_area section, if KASLR puts vmemmap very close to cpu_entry_area , and the actual area of vmemmap is much bigger than 1 TB.

So here calculate the actual size of vmemmap region, then align up to 1 TB boundary. In 4-level it's always 1 TB. In 5-level it's adjusted on demand. The current code reserves 0.5 PB for vmemmap in 5-level. In this new way, the left space can be saved to join randomization to increase the entropy.

Fiexes: eedb92abb9bb ("x86/mm: Make virtual memory layout dynamic for CONFIG_X86_5LEVEL=y")

---
v4->v5:
Add Fixes tag and Cc to stable.
v3->v4:
Fix the incorrect style of code comment;
Add ack tags from Kirill and Kees.
v3 discussion is here:
http://lkml.kernel.org/r/[email protected]

 arch/x86/mm/kaslr.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/mm/kaslr.c +10 -1
index dc3f058bdf9b..c0eedb85a92f 100644
@@ -52,7 +52,7 @@ static __initdata struct kaslr_memory_region {
 } kaslr_regions[] = {
 	{ &page_offset_base, 0 },
 	{ &vmalloc_base, 0 },
-	{ &vmemmap_base, 1 },
+	{ &vmemmap_base, 0 },
 };
 
 /* Get size in bytes used by the memory region */
@@ -78,6 +78,7 @@ void __init kernel_randomize_memory(void)
 	unsigned long rand, memory_tb;
 	struct rnd_state rand_state;
 	unsigned long remain_entropy;
+	unsigned long vmemmap_size;
 
 	vaddr_start = pgtable_l5_enabled() ? __PAGE_OFFSET_BASE_L5 : __PAGE_OFFSET_BASE_L4;
 	vaddr = vaddr_start;
@@ -109,6 +110,14 @@ void __init kernel_randomize_memory(void)
 	if (memory_tb < kaslr_regions[0].size_tb)
 		kaslr_regions[0].size_tb = memory_tb;
 
+	/*
+	 * Calculate how many TB vmemmap region needs, and aligned to
+	 * 1TB boundary.
+	 */
+	vmemmap_size = (kaslr_regions[0].size_tb << (TB_SHIFT - PAGE_SHIFT)) *
+		sizeof(struct page);
+	kaslr_regions[2].size_tb = DIV_ROUND_UP(vmemmap_size, 1UL << TB_SHIFT);
+
 	/* Calculate entropy available between regions */
 	remain_entropy = vaddr_end - vaddr_start;
 	for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++)
Signature · 1 line
2.17.2

A message that is not in the archive (sent off-list or not yet received): [email protected]

author
#2 lore raw

Hi,

Quoted 8 lines · Sasha Levin

Hi,

[This is an automated email]

This commit has been processed because it contains a -stable tag. The stable tag indicates that it's relevant for the following trees: all

The bot has tested the following trees: v5.1.4, v5.0.18, v4.19.45, v4.14.121, v4.9.178, v4.4.180, v3.18.140.

I marked below commit with 'Fixes' tag.
Fiexes: eedb92abb9bb ("x86/mm: Make virtual memory layout dynamic for CONFIG_X86_5LEVEL=y")

[bhe@ linux]$ git describe --contains eedb92abb9bb v4.17-rc1~171^2~51

You can see that it was added in kernel 4.17-rc1, as above. Can we just apply this patch to stable trees after 4.17?

Quoted 4 lines

v5.1.4: Build OK!
v5.0.18: Build OK!
v4.19.45: Build OK!

We just apply it to above three trees which are after 4.17, and the build for them is OK. Can we?

Thanks
Baoquan

Quoted 73 lines

v4.14.121: Failed to apply! Possible dependencies:

    4c2b4058ab325 ("x86/mm: Initialize 'pgtable_l5_enabled' at boot-time")
    4fa5662b6b496 ("x86/mm: Initialize 'page_offset_base' at boot-time")
    5c7919bb1994f ("x86/mm: Make LDT_BASE_ADDR dynamic")
    a7412546d8cb5 ("x86/mm: Adjust vmalloc base and size at boot-time")
    b16e770bfa534 ("x86/mm: Initialize 'pgdir_shift' and 'ptrs_per_p4d' at boot-time")
    c65e774fb3f6a ("x86/mm: Make PGDIR_SHIFT and PTRS_PER_P4D variable")
    e626e6bb0dfac ("x86/mm: Introduce 'pgtable_l5_enabled'")
    eedb92abb9bb0 ("x86/mm: Make virtual memory layout dynamic for CONFIG_X86_5LEVEL=y")

v4.9.178: Failed to apply! Possible dependencies:

    4c7c44837be77 ("x86/mm: Define virtual memory map for 5-level paging")
    5c7919bb1994f ("x86/mm: Make LDT_BASE_ADDR dynamic")
    69218e47994da ("x86: Remap GDT tables in the fixmap section")
    92a0f81d89571 ("x86/cpu_entry_area: Move it out of the fixmap")
    a7412546d8cb5 ("x86/mm: Adjust vmalloc base and size at boot-time")
    aaeed3aeb39c1 ("x86/entry/gdt: Put per-CPU GDT remaps in ascending order")
    b23adb7d3f7d1 ("x86/xen/gdt: Use X86_FEATURE_XENPV instead of globals for the GDT fixup")
    b7ffc44d5b2ea ("x86/kvm/vmx: Defer TR reload after VM exit")
    b9b1a9c363ff7 ("x86/boot/smp/32: Fix initial idle stack location on 32-bit kernels")
    ed1bbc40a0d10 ("x86/cpu_entry_area: Move it to a separate unit")
    ef8813ab28050 ("x86/mm/fixmap: Generalize the GDT fixmap mechanism, introduce struct cpu_entry_area")

v4.4.180: Failed to apply! Possible dependencies:

    021182e52fe01 ("x86/mm: Enable KASLR for physical mapping memory regions")
    0483e1fa6e09d ("x86/mm: Implement ASLR for kernel memory regions")
    071a74930e60d ("x86/KASLR: Add virtual address choosing function")
    206f25a8319b3 ("x86/KASLR: Remove unneeded boot_params argument")
    2bc1cd39fa9f6 ("x86/boot: Clean up pointer casting")
    3a94707d7a7bb ("x86/KASLR: Build identity mappings on demand")
    4252db10559fc ("x86/KASLR: Update description for decompressor worst case size")
    4c7c44837be77 ("x86/mm: Define virtual memory map for 5-level paging")
    5c7919bb1994f ("x86/mm: Make LDT_BASE_ADDR dynamic")
    6655e0aaf768c ("x86/boot: Rename "real_mode" to "boot_params"")
    7de828dfe6070 ("x86/KASLR: Clarify purpose of kaslr.c")
    8665e6ff21072 ("x86/boot: Clean up indenting for asm/boot.h")
    9016875df408f ("x86/KASLR: Rename "random" to "random_addr"")
    92a0f81d89571 ("x86/cpu_entry_area: Move it out of the fixmap")
    9b238748cb6e9 ("x86/KASLR: Rename aslr.c to kaslr.c")
    9dc1969c24eff ("x86/KASLR: Consolidate mem_avoid[] entries")
    a7412546d8cb5 ("x86/mm: Adjust vmalloc base and size at boot-time")
    d2d3462f9f08d ("x86/KASLR: Clarify purpose of each get_random_long()")
    d899a7d146a2e ("x86/mm: Refactor KASLR entropy functions")
    ed09acde44e30 ("x86/KASLR: Improve comments around the mem_avoid[] logic")

v3.18.140: Failed to apply! Possible dependencies:

    021182e52fe01 ("x86/mm: Enable KASLR for physical mapping memory regions")
    0b24becc810dc ("kasan: add kernel address sanitizer infrastructure")
    2aa79af642631 ("locking/qspinlock: Revert to test-and-set on hypervisors")
    3a94707d7a7bb ("x86/KASLR: Build identity mappings on demand")
    4c7c44837be77 ("x86/mm: Define virtual memory map for 5-level paging")
    4ea1636b04dbd ("x86/asm/tsc: Rename native_read_tsc() to rdtsc()")
    5c7919bb1994f ("x86/mm: Make LDT_BASE_ADDR dynamic")
    87be28aaf1458 ("x86/asm/tsc: Replace rdtscll() with native_read_tsc()")
    9261e050b686c ("x86/asm/tsc, x86/paravirt: Remove read_tsc() and read_tscp() paravirt hooks")
    92a0f81d89571 ("x86/cpu_entry_area: Move it out of the fixmap")
    9b238748cb6e9 ("x86/KASLR: Rename aslr.c to kaslr.c")
    a33fda35e3a76 ("locking/qspinlock: Introduce a simple generic 4-byte queued spinlock")
    a7412546d8cb5 ("x86/mm: Adjust vmalloc base and size at boot-time")
    c6e5ca35c4685 ("x86/asm/tsc: Inline native_read_tsc() and remove __native_read_tsc()")
    cf991de2f614f ("x86/asm/msr: Make wrmsrl_safe() a function")
    d6f2d75a7ae06 ("x86/kasan: Move KASAN_SHADOW_OFFSET to the arch Kconfig")
    d73a33973f16a ("locking/qspinlock, x86: Enable x86-64 to use queued spinlocks")
    d84b6728c54dc ("locking/mcs: Better differentiate between MCS variants")
    ef7f0d6a6ca8c ("x86_64: add KASan support")
    f233f7f1581e7 ("locking/pvqspinlock, x86: Implement the paravirt qspinlock call patching")

How should we proceed with this patch?

--
Thanks,
Sasha

#3 lore raw

[tip:x86/urgent] x86/mm/KASLR: Compute the size of the vmemmap section properly

In reply to Baoquan He
x86/mm/KASLR: Compute the size of the vmemmap section properly
Commit-ID:  00e5a2bbcc31d5fea853f8daeba0f06c1c88c3ff
Gitweb:     https://git.kernel.org/tip/00e5a2bbcc31d5fea853f8daeba0f06c1c88c3ff
Author:     Baoquan He <[email protected]>
AuthorDate: Thu, 23 May 2019 10:57:44 +0800
Committer:  Borislav Petkov <[email protected]>
CommitDate: Fri, 7 Jun 2019 23:12:13 +0200

x86/mm/KASLR: Compute the size of the vmemmap section properly

The size of the vmemmap section is hardcoded to 1 TB to support the maximum amount of system RAM in 4-level paging mode - 64 TB.

However, 1 TB is not enough for vmemmap in 5-level paging mode. Assuming the size of struct page is 64 Bytes, to support 4 PB system RAM in 5-level, 64 TB of vmemmap area is needed:

4 * 1000^5 PB / 4096 bytes page size * 64 bytes per page struct / 1000^4 TB = 62.5 TB.

This hardcoding may cause vmemmap to corrupt the following cpu_entry_area section, if KASLR puts vmemmap very close to it and the actual vmemmap size is bigger than 1 TB.

So calculate the actual size of the vmemmap region needed and then align it up to 1 TB boundary.

In 4-level paging mode it is always 1 TB. In 5-level it's adjusted on demand. The current code reserves 0.5 PB for vmemmap on 5-level. With this change, the space can be saved and thus used to increase entropy for the randomization.

[ bp: Spell out how the 64 TB needed for vmemmap is computed and massage commit
message. ]

Fixes eedb92abb9bb ("x86/mm: Make virtual memory layout dynamic for CONFIG_X86_5LEVEL=y")
Cc Andy Lutomirski <[email protected]>
Cc Dave Hansen <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc stable <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc x86-ml <[email protected]>
---
 arch/x86/mm/kaslr.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/mm/kaslr.c +10 -1
index dc3f058bdf9b..dc6182eecefa 100644
@@ -52,7 +52,7 @@ static __initdata struct kaslr_memory_region {
 } kaslr_regions[] = {
 	{ &page_offset_base, 0 },
 	{ &vmalloc_base, 0 },
-	{ &vmemmap_base, 1 },
+	{ &vmemmap_base, 0 },
 };
 
 /* Get size in bytes used by the memory region */
@@ -78,6 +78,7 @@ void __init kernel_randomize_memory(void)
 	unsigned long rand, memory_tb;
 	struct rnd_state rand_state;
 	unsigned long remain_entropy;
+	unsigned long vmemmap_size;
 
 	vaddr_start = pgtable_l5_enabled() ? __PAGE_OFFSET_BASE_L5 : __PAGE_OFFSET_BASE_L4;
 	vaddr = vaddr_start;
@@ -109,6 +110,14 @@ void __init kernel_randomize_memory(void)
 	if (memory_tb < kaslr_regions[0].size_tb)
 		kaslr_regions[0].size_tb = memory_tb;
 
+	/*
+	 * Calculate the vmemmap region size in TBs, aligned to a TB
+	 * boundary.
+	 */
+	vmemmap_size = (kaslr_regions[0].size_tb << (TB_SHIFT - PAGE_SHIFT)) *
+			sizeof(struct page);
+	kaslr_regions[2].size_tb = DIV_ROUND_UP(vmemmap_size, 1UL << TB_SHIFT);
+
 	/* Calculate entropy available between regions */
 	remain_entropy = vaddr_end - vaddr_start;
 	for (i = 0; i < ARRAY_SIZE(kaslr_regions); i++)
author
#4 lore raw

Re: [tip:x86/urgent] x86/mm/KASLR: Compute the size of the vmemmap section properly

Quoted 9 lines · tip-bot for Baoquan He
Commit-ID:  00e5a2bbcc31d5fea853f8daeba0f06c1c88c3ff
Gitweb:     https://git.kernel.org/tip/00e5a2bbcc31d5fea853f8daeba0f06c1c88c3ff
Author:     Baoquan He <[email protected]>
AuthorDate: Thu, 23 May 2019 10:57:44 +0800
Committer:  Borislav Petkov <[email protected]>
CommitDate: Fri, 7 Jun 2019 23:12:13 +0200

x86/mm/KASLR: Compute the size of the vmemmap section properly

Quoted 8 lines

The size of the vmemmap section is hardcoded to 1 TB to support the maximum amount of system RAM in 4-level paging mode - 64 TB.

However, 1 TB is not enough for vmemmap in 5-level paging mode. Assuming the size of struct page is 64 Bytes, to support 4 PB system RAM in 5-level, 64 TB of vmemmap area is needed:

4 * 1000^5 PB / 4096 bytes page size * 64 bytes per page struct / 1000^4 TB = 62.5 TB.

Thanks for picking this, Boris.

Here, 4PB = 4*2^50 = 4*1024^5, the vmemmap should be 64 TB, am I right?

Quoted 4 lines

This hardcoding may cause vmemmap to corrupt the following cpu_entry_area section, if KASLR puts vmemmap very close to it and the actual vmemmap size is bigger than 1 TB.

#5 lore raw

Re: [tip:x86/urgent] x86/mm/KASLR: Compute the size of the vmemmap section properly

Quoted 1 line · Baoquan He

Here, 4PB = 4*2^50 = 4*1024^5, the vmemmap should be 64 TB, am I right?

PB is 1000^5 petabytes.

1024^5 is PiB or pebibytes.

https://en.wikipedia.org/wiki/Petabyte

Signature · 5 lines
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Mary Higgins, Sri Rasiah, HRB 21284 (AG Nürnberg)
--