Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8624c1f6 authored by Kirill A. Shutemov's avatar Kirill A. Shutemov Committed by Ingo Molnar
Browse files

x86/mm: Add support for 5-level paging for KASLR



With 5-level paging randomization happens on P4D level instead of PUD.

Maximum amount of physical memory also bumped to 52-bits for 5-level
paging.

Signed-off-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arch@vger.kernel.org
Cc: linux-mm@kvack.org
Link: http://lkml.kernel.org/r/20170606113133.22974-13-kirill.shutemov@linux.intel.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 7e82ea94
Loading
Loading
Loading
Loading
+62 −19
Original line number Original line Diff line number Diff line
@@ -6,12 +6,12 @@
 *
 *
 * Entropy is generated using the KASLR early boot functions now shared in
 * Entropy is generated using the KASLR early boot functions now shared in
 * the lib directory (originally written by Kees Cook). Randomization is
 * the lib directory (originally written by Kees Cook). Randomization is
 * done on PGD & PUD page table levels to increase possible addresses. The
 * done on PGD & P4D/PUD page table levels to increase possible addresses.
 * physical memory mapping code was adapted to support PUD level virtual
 * The physical memory mapping code was adapted to support P4D/PUD level
 * addresses. This implementation on the best configuration provides 30,000
 * virtual addresses. This implementation on the best configuration provides
 * possible virtual addresses in average for each memory region. An additional
 * 30,000 possible virtual addresses in average for each memory region.
 * low memory page is used to ensure each CPU can start with a PGD aligned
 * An additional low memory page is used to ensure each CPU can start with
 * virtual address (for realmode).
 * a PGD aligned virtual address (for realmode).
 *
 *
 * The order of each memory region is not changed. The feature looks at
 * The order of each memory region is not changed. The feature looks at
 * the available space for the regions based on different configuration
 * the available space for the regions based on different configuration
@@ -70,7 +70,7 @@ static __initdata struct kaslr_memory_region {
	unsigned long *base;
	unsigned long *base;
	unsigned long size_tb;
	unsigned long size_tb;
} kaslr_regions[] = {
} kaslr_regions[] = {
	{ &page_offset_base, 64/* Maximum */ },
	{ &page_offset_base, 1 << (__PHYSICAL_MASK_SHIFT - TB_SHIFT) /* Maximum */ },
	{ &vmalloc_base, VMALLOC_SIZE_TB },
	{ &vmalloc_base, VMALLOC_SIZE_TB },
	{ &vmemmap_base, 1 },
	{ &vmemmap_base, 1 },
};
};
@@ -142,6 +142,9 @@ void __init kernel_randomize_memory(void)
		 */
		 */
		entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i);
		entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i);
		prandom_bytes_state(&rand_state, &rand, sizeof(rand));
		prandom_bytes_state(&rand_state, &rand, sizeof(rand));
		if (IS_ENABLED(CONFIG_X86_5LEVEL))
			entropy = (rand % (entropy + 1)) & P4D_MASK;
		else
			entropy = (rand % (entropy + 1)) & PUD_MASK;
			entropy = (rand % (entropy + 1)) & PUD_MASK;
		vaddr += entropy;
		vaddr += entropy;
		*kaslr_regions[i].base = vaddr;
		*kaslr_regions[i].base = vaddr;
@@ -151,27 +154,21 @@ void __init kernel_randomize_memory(void)
		 * randomization alignment.
		 * randomization alignment.
		 */
		 */
		vaddr += get_padding(&kaslr_regions[i]);
		vaddr += get_padding(&kaslr_regions[i]);
		if (IS_ENABLED(CONFIG_X86_5LEVEL))
			vaddr = round_up(vaddr + 1, P4D_SIZE);
		else
			vaddr = round_up(vaddr + 1, PUD_SIZE);
			vaddr = round_up(vaddr + 1, PUD_SIZE);
		remain_entropy -= entropy;
		remain_entropy -= entropy;
	}
	}
}
}


/*
static void __meminit init_trampoline_pud(void)
 * Create PGD aligned trampoline table to allow real mode initialization
 * of additional CPUs. Consume only 1 low memory page.
 */
void __meminit init_trampoline(void)
{
{
	unsigned long paddr, paddr_next;
	unsigned long paddr, paddr_next;
	pgd_t *pgd;
	pgd_t *pgd;
	pud_t *pud_page, *pud_page_tramp;
	pud_t *pud_page, *pud_page_tramp;
	int i;
	int i;


	if (!kaslr_memory_enabled()) {
		init_trampoline_default();
		return;
	}

	pud_page_tramp = alloc_low_page();
	pud_page_tramp = alloc_low_page();


	paddr = 0;
	paddr = 0;
@@ -192,3 +189,49 @@ void __meminit init_trampoline(void)
	set_pgd(&trampoline_pgd_entry,
	set_pgd(&trampoline_pgd_entry,
		__pgd(_KERNPG_TABLE | __pa(pud_page_tramp)));
		__pgd(_KERNPG_TABLE | __pa(pud_page_tramp)));
}
}

static void __meminit init_trampoline_p4d(void)
{
	unsigned long paddr, paddr_next;
	pgd_t *pgd;
	p4d_t *p4d_page, *p4d_page_tramp;
	int i;

	p4d_page_tramp = alloc_low_page();

	paddr = 0;
	pgd = pgd_offset_k((unsigned long)__va(paddr));
	p4d_page = (p4d_t *) pgd_page_vaddr(*pgd);

	for (i = p4d_index(paddr); i < PTRS_PER_P4D; i++, paddr = paddr_next) {
		p4d_t *p4d, *p4d_tramp;
		unsigned long vaddr = (unsigned long)__va(paddr);

		p4d_tramp = p4d_page_tramp + p4d_index(paddr);
		p4d = p4d_page + p4d_index(vaddr);
		paddr_next = (paddr & P4D_MASK) + P4D_SIZE;

		*p4d_tramp = *p4d;
	}

	set_pgd(&trampoline_pgd_entry,
		__pgd(_KERNPG_TABLE | __pa(p4d_page_tramp)));
}

/*
 * Create PGD aligned trampoline table to allow real mode initialization
 * of additional CPUs. Consume only 1 low memory page.
 */
void __meminit init_trampoline(void)
{

	if (!kaslr_memory_enabled()) {
		init_trampoline_default();
		return;
	}

	if (IS_ENABLED(CONFIG_X86_5LEVEL))
		init_trampoline_p4d();
	else
		init_trampoline_pud();
}