Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1672587 > unrolled thread

[PATCH 0/5] Last bits for initial 5-level paging enabling

Started by"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
First post2017-06-22 14:30 +0200
Last post2017-06-30 15:20 +0200
Articles 9 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/5] Last bits for initial 5-level paging enabling "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> - 2017-06-22 14:30 +0200
    [PATCH 3/5] x86/mpx: Do not allow MPX if we have mappings above 47-bit "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> - 2017-06-22 14:30 +0200
    Re: [PATCH 0/5] Last bits for initial 5-level paging enabling Ingo Molnar <mingo@kernel.org> - 2017-06-23 11:10 +0200
      Re: [PATCH 0/5] Last bits for initial 5-level paging enabling "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> - 2017-06-23 16:50 +0200
        Re: [PATCH 0/5] Last bits for initial 5-level paging enabling "Kirill A. Shutemov" <kirill@shutemov.name> - 2017-06-29 17:10 +0200
          Re: [PATCH 0/5] Last bits for initial 5-level paging enabling Ingo Molnar <mingo@kernel.org> - 2017-06-30 09:00 +0200
    [PATCH 6/5] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> - 2017-06-28 14:20 +0200
      Re: [PATCH 6/5] x86/KASLR: Fix detection 32/64 bit bootloaders for  5-level paging Kees Cook <keescook@chromium.org> - 2017-06-28 20:00 +0200
      [tip:x86/mm] x86/KASLR: Fix detection 32/64 bit bootloaders for  5-level paging "tip-bot for Kirill A. Shutemov" <tipbot@zytor.com> - 2017-06-30 15:20 +0200

#1672587 — [PATCH 0/5] Last bits for initial 5-level paging enabling

From"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date2017-06-22 14:30 +0200
Subject[PATCH 0/5] Last bits for initial 5-level paging enabling
Message-ID<tV9pf-4DF-3@gated-at.bofh.it>
As Ingo requested I've split and updated last two patches for my previous
patchset.

Please review and consider applying.

Kirill A. Shutemov (5):
  x86: Enable 5-level paging support
  x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
  x86/mpx: Do not allow MPX if we have mappings above 47-bit
  x86/mm: Prepare to expose larger address space to userspace
  x86/mm: Allow userspace have mapping above 47-bit

 Documentation/x86/x86_64/5level-paging.txt | 64 ++++++++++++++++++++++++++++++
 arch/x86/Kconfig                           | 18 +++++++++
 arch/x86/include/asm/elf.h                 |  6 +--
 arch/x86/include/asm/mpx.h                 |  9 +++++
 arch/x86/include/asm/processor.h           | 12 ++++--
 arch/x86/kernel/sys_x86_64.c               | 30 ++++++++++++--
 arch/x86/mm/hugetlbpage.c                  | 27 +++++++++++--
 arch/x86/mm/mmap.c                         | 12 +++---
 arch/x86/mm/mpx.c                          | 33 ++++++++++++++-
 arch/x86/xen/Kconfig                       |  3 ++
 10 files changed, 193 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/x86/x86_64/5level-paging.txt

-- 
2.11.0

[toc] | [next] | [standalone]


#1672592 — [PATCH 3/5] x86/mpx: Do not allow MPX if we have mappings above 47-bit

From"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date2017-06-22 14:30 +0200
Subject[PATCH 3/5] x86/mpx: Do not allow MPX if we have mappings above 47-bit
Message-ID<tV9pg-4DF-29@gated-at.bofh.it>
In reply to#1672587
MPX (without MAWA extension) cannot handle addresses above 47-bit, so we
need to make sure that MPX cannot be enabled if we already have VMA above
the boundary and forbid creating such VMAs once MPX is enabled.

The patch implements mpx_unmapped_area_check() which is called from all
variants of get_unmapped_area() to check if the requested address fits
mpx.

On enabling MPX, we check if we already have any vma above 47-bit
boundary and forbit the enabling if we do.

As long as DEFAULT_MAP_WINDOW is equal to TASK_SIZE_MAX, the change is
nop. It will change when we allow userspace to have mappings above
47-bits.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
---
 arch/x86/include/asm/mpx.h       |  9 +++++++++
 arch/x86/include/asm/processor.h |  3 +++
 arch/x86/kernel/sys_x86_64.c     |  9 +++++++++
 arch/x86/mm/hugetlbpage.c        |  6 ++++++
 arch/x86/mm/mpx.c                | 33 ++++++++++++++++++++++++++++++++-
 5 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h
index a0d662be4c5b..7d7404756bb4 100644
--- a/arch/x86/include/asm/mpx.h
+++ b/arch/x86/include/asm/mpx.h
@@ -73,6 +73,9 @@ static inline void mpx_mm_init(struct mm_struct *mm)
 }
 void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
 		      unsigned long start, unsigned long end);
+
+unsigned long mpx_unmapped_area_check(unsigned long addr, unsigned long len,
+		unsigned long flags);
 #else
 static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs)
 {
@@ -94,6 +97,12 @@ static inline void mpx_notify_unmap(struct mm_struct *mm,
 				    unsigned long start, unsigned long end)
 {
 }
+
+static inline unsigned long mpx_unmapped_area_check(unsigned long addr,
+		unsigned long len, unsigned long flags)
+{
+	return addr;
+}
 #endif /* CONFIG_X86_INTEL_MPX */
 
 #endif /* _ASM_X86_MPX_H */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index f3b1b27f1c0a..97e9cada4945 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -803,6 +803,7 @@ static inline void spin_lock_prefetch(const void *x)
 #define IA32_PAGE_OFFSET	PAGE_OFFSET
 #define TASK_SIZE		PAGE_OFFSET
 #define TASK_SIZE_MAX		TASK_SIZE
+#define DEFAULT_MAP_WINDOW	TASK_SIZE
 #define STACK_TOP		TASK_SIZE
 #define STACK_TOP_MAX		STACK_TOP
 
@@ -844,6 +845,8 @@ static inline void spin_lock_prefetch(const void *x)
  */
 #define TASK_SIZE_MAX	((1UL << 47) - PAGE_SIZE)
 
+#define DEFAULT_MAP_WINDOW	TASK_SIZE_MAX
+
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 89bd0d6460e1..f840e895d871 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -21,6 +21,7 @@
 #include <asm/compat.h>
 #include <asm/ia32.h>
 #include <asm/syscalls.h>
+#include <asm/mpx.h>
 
 /*
  * Align a virtual address to avoid aliasing in the I$ on AMD F15h.
@@ -132,6 +133,10 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
 	struct vm_unmapped_area_info info;
 	unsigned long begin, end;
 
+	addr = mpx_unmapped_area_check(addr, len, flags);
+	if (IS_ERR_VALUE(addr))
+		return addr;
+
 	if (flags & MAP_FIXED)
 		return addr;
 
@@ -171,6 +176,10 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 	unsigned long addr = addr0;
 	struct vm_unmapped_area_info info;
 
+	addr = mpx_unmapped_area_check(addr, len, flags);
+	if (IS_ERR_VALUE(addr))
+		return addr;
+
 	/* requested length too big for entire address space */
 	if (len > TASK_SIZE)
 		return -ENOMEM;
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index 93bfd6d7ce1c..afd5f2152300 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -18,6 +18,7 @@
 #include <asm/tlbflush.h>
 #include <asm/pgalloc.h>
 #include <asm/elf.h>
+#include <asm/mpx.h>
 
 #if 0	/* This is just for testing */
 struct page *
@@ -135,6 +136,11 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 
 	if (len & ~huge_page_mask(h))
 		return -EINVAL;
+
+	addr = mpx_unmapped_area_check(addr, len, flags);
+	if (IS_ERR_VALUE(addr))
+		return addr;
+
 	if (len > TASK_SIZE)
 		return -ENOMEM;
 
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
index 1c34b767c84c..8c8da27e8549 100644
--- a/arch/x86/mm/mpx.c
+++ b/arch/x86/mm/mpx.c
@@ -355,10 +355,19 @@ int mpx_enable_management(void)
 	 */
 	bd_base = mpx_get_bounds_dir();
 	down_write(&mm->mmap_sem);
+
+	/* MPX doesn't support addresses above 47-bits yet. */
+	if (find_vma(mm, DEFAULT_MAP_WINDOW)) {
+		pr_warn_once("%s (%d): MPX cannot handle addresses "
+				"above 47-bits. Disabling.",
+				current->comm, current->pid);
+		ret = -ENXIO;
+		goto out;
+	}
 	mm->context.bd_addr = bd_base;
 	if (mm->context.bd_addr == MPX_INVALID_BOUNDS_DIR)
 		ret = -ENXIO;
-
+out:
 	up_write(&mm->mmap_sem);
 	return ret;
 }
@@ -1030,3 +1039,25 @@ void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
 	if (ret)
 		force_sig(SIGSEGV, current);
 }
+
+/* MPX cannot handle addresses above 47-bits yet. */
+unsigned long mpx_unmapped_area_check(unsigned long addr, unsigned long len,
+		unsigned long flags)
+{
+	if (!kernel_managing_mpx_tables(current->mm))
+		return addr;
+	if (addr + len <= DEFAULT_MAP_WINDOW)
+		return addr;
+	if (flags & MAP_FIXED)
+		return -ENOMEM;
+
+	/*
+	 * Requested len is larger than whole area we're allowed to map in.
+	 * Resetting hinting address wouldn't do much good -- fail early.
+	 */
+	if (len > DEFAULT_MAP_WINDOW)
+		return -ENOMEM;
+
+	/* Look for unmap area within DEFAULT_MAP_WINDOW */
+	return 0;
+}
-- 
2.11.0

[toc] | [prev] | [next] | [standalone]


#1673405

FromIngo Molnar <mingo@kernel.org>
Date2017-06-23 11:10 +0200
Message-ID<tVsLg-eC-19@gated-at.bofh.it>
In reply to#1672587
* Kirill A. Shutemov <kirill.shutemov@linux.intel.com> wrote:

> As Ingo requested I've split and updated last two patches for my previous
> patchset.
> 
> Please review and consider applying.
> 
> Kirill A. Shutemov (5):
>   x86: Enable 5-level paging support
>   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
>   x86/mpx: Do not allow MPX if we have mappings above 47-bit
>   x86/mm: Prepare to expose larger address space to userspace
>   x86/mm: Allow userspace have mapping above 47-bit

Ok, looks pretty neat now.

Can I apply them in this order cleanly, without breaking bisection:

>   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
>   x86/mpx: Do not allow MPX if we have mappings above 47-bit
>   x86/mm: Prepare to expose larger address space to userspace
>   x86/mm: Allow userspace have mapping above 47-bit
>   x86: Enable 5-level paging support

?

I.e. I'd like to move the first patch last.

The reason is that we should first get all quirks and assumptions fixed, all 
facilities implemented - and only then enable 5-level paging as a final step which 
produces a well working kernel.

(This should also make it slightly easier to analyze any potential regressions in 
earlier patches.)

Thanks,

	Ingo

[toc] | [prev] | [next] | [standalone]


#1673617

From"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date2017-06-23 16:50 +0200
Message-ID<tVy4i-3pQ-17@gated-at.bofh.it>
In reply to#1673405
On Fri, Jun 23, 2017 at 11:06:01AM +0200, Ingo Molnar wrote:
> 
> * Kirill A. Shutemov <kirill.shutemov@linux.intel.com> wrote:
> 
> > As Ingo requested I've split and updated last two patches for my previous
> > patchset.
> > 
> > Please review and consider applying.
> > 
> > Kirill A. Shutemov (5):
> >   x86: Enable 5-level paging support
> >   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
> >   x86/mpx: Do not allow MPX if we have mappings above 47-bit
> >   x86/mm: Prepare to expose larger address space to userspace
> >   x86/mm: Allow userspace have mapping above 47-bit
> 
> Ok, looks pretty neat now.
> 
> Can I apply them in this order cleanly, without breaking bisection:
> 
> >   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
> >   x86/mpx: Do not allow MPX if we have mappings above 47-bit
> >   x86/mm: Prepare to expose larger address space to userspace
> >   x86/mm: Allow userspace have mapping above 47-bit
> >   x86: Enable 5-level paging support
> 
> ?
> 
> I.e. I'd like to move the first patch last.
> 
> The reason is that we should first get all quirks and assumptions fixed, all 
> facilities implemented - and only then enable 5-level paging as a final step which 
> produces a well working kernel.
> 
> (This should also make it slightly easier to analyze any potential regressions in 
> earlier patches.)

Just checked bisectability with this order on allmodconfig -- works fine.

-- 
 Kirill A. Shutemov

[toc] | [prev] | [next] | [standalone]


#1677847

From"Kirill A. Shutemov" <kirill@shutemov.name>
Date2017-06-29 17:10 +0200
Message-ID<tXJeV-IJ-3@gated-at.bofh.it>
In reply to#1673617
On Fri, Jun 23, 2017 at 05:49:15PM +0300, Kirill A. Shutemov wrote:
> On Fri, Jun 23, 2017 at 11:06:01AM +0200, Ingo Molnar wrote:
> > 
> > * Kirill A. Shutemov <kirill.shutemov@linux.intel.com> wrote:
> > 
> > > As Ingo requested I've split and updated last two patches for my previous
> > > patchset.
> > > 
> > > Please review and consider applying.
> > > 
> > > Kirill A. Shutemov (5):
> > >   x86: Enable 5-level paging support
> > >   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
> > >   x86/mpx: Do not allow MPX if we have mappings above 47-bit
> > >   x86/mm: Prepare to expose larger address space to userspace
> > >   x86/mm: Allow userspace have mapping above 47-bit
> > 
> > Ok, looks pretty neat now.
> > 
> > Can I apply them in this order cleanly, without breaking bisection:
> > 
> > >   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
> > >   x86/mpx: Do not allow MPX if we have mappings above 47-bit
> > >   x86/mm: Prepare to expose larger address space to userspace
> > >   x86/mm: Allow userspace have mapping above 47-bit
> > >   x86: Enable 5-level paging support
> > 
> > ?
> > 
> > I.e. I'd like to move the first patch last.
> > 
> > The reason is that we should first get all quirks and assumptions fixed, all 
> > facilities implemented - and only then enable 5-level paging as a final step which 
> > produces a well working kernel.
> > 
> > (This should also make it slightly easier to analyze any potential regressions in 
> > earlier patches.)
> 
> Just checked bisectability with this order on allmodconfig -- works fine.

Ingo, if there's no objections, can we get these applied?

-- 
 Kirill A. Shutemov

[toc] | [prev] | [next] | [standalone]


#1678539

FromIngo Molnar <mingo@kernel.org>
Date2017-06-30 09:00 +0200
Message-ID<tXY4i-23t-19@gated-at.bofh.it>
In reply to#1677847
* Kirill A. Shutemov <kirill@shutemov.name> wrote:

> > > Can I apply them in this order cleanly, without breaking bisection:
> > > 
> > > >   x86/mm: Rename tasksize_32bit/64bit to task_size_32bit/64bit
> > > >   x86/mpx: Do not allow MPX if we have mappings above 47-bit
> > > >   x86/mm: Prepare to expose larger address space to userspace
> > > >   x86/mm: Allow userspace have mapping above 47-bit
> > > >   x86: Enable 5-level paging support
> > > 
> > > ?
> > > 
> > > I.e. I'd like to move the first patch last.
> > > 
> > > The reason is that we should first get all quirks and assumptions fixed, all 
> > > facilities implemented - and only then enable 5-level paging as a final step which 
> > > produces a well working kernel.
> > > 
> > > (This should also make it slightly easier to analyze any potential regressions in 
> > > earlier patches.)
> > 
> > Just checked bisectability with this order on allmodconfig -- works fine.
> 
> Ingo, if there's no objections, can we get these applied?

Just this week, which is the final week of the development window, we had two 
fixes for the 5-level pagetables commits, so we need to delay the rest to right 
after -rc1.

Could you please resend them them (and any followup patches), in the suggested 
order? I don't see any conceptual problems, so this is only about timing and 
maximizing stability.

Thanks,

	Ingo

[toc] | [prev] | [next] | [standalone]


#1676611 — [PATCH 6/5] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging

From"Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date2017-06-28 14:20 +0200
Subject[PATCH 6/5] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging
Message-ID<tXk6S-6H0-11@gated-at.bofh.it>
In reply to#1672587
KASLR uses hack to detect whether we booted via startup_32() or
startup_64(): it checks what is loaded into cr3 and compares it to
_pgtables. _pgtables is the array of page tables where early code
allocates page table from.

KASLR expects cr3 to point to _pgtables if we booted via startup_32(), but
that's not true if we booted with 5-level paging enabled. In this case top
level page table is allocated separately and only the first p4d page table
is allocated from the array.

Let's modify the check to cover both 4- and 5-level paging cases.

The patch also renames 'level4p' to 'top_level_pgt' as it now can hold
page table for 4th or 5th level, depending on configuration.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/pagetable.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c
index 8e69df96492e..da4cf44d4aac 100644
--- a/arch/x86/boot/compressed/pagetable.c
+++ b/arch/x86/boot/compressed/pagetable.c
@@ -63,7 +63,7 @@ static void *alloc_pgt_page(void *context)
 static struct alloc_pgt_data pgt_data;
 
 /* The top level page table entry pointer. */
-static unsigned long level4p;
+static unsigned long top_level_pgt;
 
 /*
  * Mapping information structure passed to kernel_ident_mapping_init().
@@ -91,9 +91,15 @@ void initialize_identity_maps(void)
 	 * If we came here via startup_32(), cr3 will be _pgtable already
 	 * and we must append to the existing area instead of entirely
 	 * overwriting it.
+	 *
+	 * With 5-level paging, we use _pgtable allocate p4d page table,
+	 * top-level page table is allocated separately.
+	 *
+	 * p4d_offset(top_level_pgt, 0) would cover both 4- and 5-level
+	 * cases. On 4-level paging it's equal to top_level_pgt.
 	 */
-	level4p = read_cr3_pa();
-	if (level4p == (unsigned long)_pgtable) {
+	top_level_pgt = read_cr3_pa();
+	if (p4d_offset((pgd_t *)top_level_pgt, 0) == (p4d_t *)_pgtable) {
 		debug_putstr("booted via startup_32()\n");
 		pgt_data.pgt_buf = _pgtable + BOOT_INIT_PGT_SIZE;
 		pgt_data.pgt_buf_size = BOOT_PGT_SIZE - BOOT_INIT_PGT_SIZE;
@@ -103,7 +109,7 @@ void initialize_identity_maps(void)
 		pgt_data.pgt_buf = _pgtable;
 		pgt_data.pgt_buf_size = BOOT_PGT_SIZE;
 		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
-		level4p = (unsigned long)alloc_pgt_page(&pgt_data);
+		top_level_pgt = (unsigned long)alloc_pgt_page(&pgt_data);
 	}
 }
 
@@ -123,7 +129,7 @@ void add_identity_map(unsigned long start, unsigned long size)
 		return;
 
 	/* Build the mapping. */
-	kernel_ident_mapping_init(&mapping_info, (pgd_t *)level4p,
+	kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt,
 				  start, end);
 }
 
@@ -134,5 +140,5 @@ void add_identity_map(unsigned long start, unsigned long size)
  */
 void finalize_identity_maps(void)
 {
-	write_cr3(level4p);
+	write_cr3(top_level_pgt);
 }
-- 
2.11.0

[toc] | [prev] | [next] | [standalone]


#1676940 — Re: [PATCH 6/5] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging

FromKees Cook <keescook@chromium.org>
Date2017-06-28 20:00 +0200
SubjectRe: [PATCH 6/5] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging
Message-ID<tXppZ-t5-99@gated-at.bofh.it>
In reply to#1676611
On Wed, Jun 28, 2017 at 5:17 AM, Kirill A. Shutemov
<kirill.shutemov@linux.intel.com> wrote:
> KASLR uses hack to detect whether we booted via startup_32() or
> startup_64(): it checks what is loaded into cr3 and compares it to
> _pgtables. _pgtables is the array of page tables where early code
> allocates page table from.
>
> KASLR expects cr3 to point to _pgtables if we booted via startup_32(), but
> that's not true if we booted with 5-level paging enabled. In this case top
> level page table is allocated separately and only the first p4d page table
> is allocated from the array.
>
> Let's modify the check to cover both 4- and 5-level paging cases.
>
> The patch also renames 'level4p' to 'top_level_pgt' as it now can hold
> page table for 4th or 5th level, depending on configuration.
>
> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> Cc: Kees Cook <keescook@chromium.org>

This looks good, thanks!

Acked-by: Kees Cook <keescook@chromium.org>

-Kees

> ---
>  arch/x86/boot/compressed/pagetable.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c
> index 8e69df96492e..da4cf44d4aac 100644
> --- a/arch/x86/boot/compressed/pagetable.c
> +++ b/arch/x86/boot/compressed/pagetable.c
> @@ -63,7 +63,7 @@ static void *alloc_pgt_page(void *context)
>  static struct alloc_pgt_data pgt_data;
>
>  /* The top level page table entry pointer. */
> -static unsigned long level4p;
> +static unsigned long top_level_pgt;
>
>  /*
>   * Mapping information structure passed to kernel_ident_mapping_init().
> @@ -91,9 +91,15 @@ void initialize_identity_maps(void)
>          * If we came here via startup_32(), cr3 will be _pgtable already
>          * and we must append to the existing area instead of entirely
>          * overwriting it.
> +        *
> +        * With 5-level paging, we use _pgtable allocate p4d page table,
> +        * top-level page table is allocated separately.
> +        *
> +        * p4d_offset(top_level_pgt, 0) would cover both 4- and 5-level
> +        * cases. On 4-level paging it's equal to top_level_pgt.
>          */
> -       level4p = read_cr3_pa();
> -       if (level4p == (unsigned long)_pgtable) {
> +       top_level_pgt = read_cr3_pa();
> +       if (p4d_offset((pgd_t *)top_level_pgt, 0) == (p4d_t *)_pgtable) {
>                 debug_putstr("booted via startup_32()\n");
>                 pgt_data.pgt_buf = _pgtable + BOOT_INIT_PGT_SIZE;
>                 pgt_data.pgt_buf_size = BOOT_PGT_SIZE - BOOT_INIT_PGT_SIZE;
> @@ -103,7 +109,7 @@ void initialize_identity_maps(void)
>                 pgt_data.pgt_buf = _pgtable;
>                 pgt_data.pgt_buf_size = BOOT_PGT_SIZE;
>                 memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
> -               level4p = (unsigned long)alloc_pgt_page(&pgt_data);
> +               top_level_pgt = (unsigned long)alloc_pgt_page(&pgt_data);
>         }
>  }
>
> @@ -123,7 +129,7 @@ void add_identity_map(unsigned long start, unsigned long size)
>                 return;
>
>         /* Build the mapping. */
> -       kernel_ident_mapping_init(&mapping_info, (pgd_t *)level4p,
> +       kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt,
>                                   start, end);
>  }
>
> @@ -134,5 +140,5 @@ void add_identity_map(unsigned long start, unsigned long size)
>   */
>  void finalize_identity_maps(void)
>  {
> -       write_cr3(level4p);
> +       write_cr3(top_level_pgt);
>  }
> --
> 2.11.0
>



-- 
Kees Cook
Pixel Security

[toc] | [prev] | [next] | [standalone]


#1678813 — [tip:x86/mm] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging

From"tip-bot for Kirill A. Shutemov" <tipbot@zytor.com>
Date2017-06-30 15:20 +0200
Subject[tip:x86/mm] x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging
Message-ID<tY403-5YH-31@gated-at.bofh.it>
In reply to#1676611
Commit-ID:  a24261d70e00e4ce03cf45bbf18398f52a7b9229
Gitweb:     http://git.kernel.org/tip/a24261d70e00e4ce03cf45bbf18398f52a7b9229
Author:     Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
AuthorDate: Wed, 28 Jun 2017 15:17:30 +0300
Committer:  Ingo Molnar <mingo@kernel.org>
CommitDate: Fri, 30 Jun 2017 08:56:53 +0200

x86/KASLR: Fix detection 32/64 bit bootloaders for 5-level paging

KASLR uses hack to detect whether we booted via startup_32() or
startup_64(): it checks what is loaded into cr3 and compares it to
_pgtables. _pgtables is the array of page tables where early code
allocates page table from.

KASLR expects cr3 to point to _pgtables if we booted via startup_32(), but
that's not true if we booted with 5-level paging enabled. In this case top
level page table is allocated separately and only the first p4d page table
is allocated from the array.

Let's modify the check to cover both 4- and 5-level paging cases.

The patch also renames 'level4p' to 'top_level_pgt' as it now can hold
page table for 4th or 5th level, depending on configuration.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Kees Cook <keescook@chromium.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Dave Hansen <dave.hansen@intel.com>
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/20170628121730.43079-1-kirill.shutemov@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
 arch/x86/boot/compressed/pagetable.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/arch/x86/boot/compressed/pagetable.c b/arch/x86/boot/compressed/pagetable.c
index 8e69df9..28029be 100644
--- a/arch/x86/boot/compressed/pagetable.c
+++ b/arch/x86/boot/compressed/pagetable.c
@@ -63,7 +63,7 @@ static void *alloc_pgt_page(void *context)
 static struct alloc_pgt_data pgt_data;
 
 /* The top level page table entry pointer. */
-static unsigned long level4p;
+static unsigned long top_level_pgt;
 
 /*
  * Mapping information structure passed to kernel_ident_mapping_init().
@@ -91,9 +91,15 @@ void initialize_identity_maps(void)
 	 * If we came here via startup_32(), cr3 will be _pgtable already
 	 * and we must append to the existing area instead of entirely
 	 * overwriting it.
+	 *
+	 * With 5-level paging, we use '_pgtable' to allocate the p4d page table,
+	 * the top-level page table is allocated separately.
+	 *
+	 * p4d_offset(top_level_pgt, 0) would cover both the 4- and 5-level
+	 * cases. On 4-level paging it's equal to 'top_level_pgt'.
 	 */
-	level4p = read_cr3_pa();
-	if (level4p == (unsigned long)_pgtable) {
+	top_level_pgt = read_cr3_pa();
+	if (p4d_offset((pgd_t *)top_level_pgt, 0) == (p4d_t *)_pgtable) {
 		debug_putstr("booted via startup_32()\n");
 		pgt_data.pgt_buf = _pgtable + BOOT_INIT_PGT_SIZE;
 		pgt_data.pgt_buf_size = BOOT_PGT_SIZE - BOOT_INIT_PGT_SIZE;
@@ -103,7 +109,7 @@ void initialize_identity_maps(void)
 		pgt_data.pgt_buf = _pgtable;
 		pgt_data.pgt_buf_size = BOOT_PGT_SIZE;
 		memset(pgt_data.pgt_buf, 0, pgt_data.pgt_buf_size);
-		level4p = (unsigned long)alloc_pgt_page(&pgt_data);
+		top_level_pgt = (unsigned long)alloc_pgt_page(&pgt_data);
 	}
 }
 
@@ -123,7 +129,7 @@ void add_identity_map(unsigned long start, unsigned long size)
 		return;
 
 	/* Build the mapping. */
-	kernel_ident_mapping_init(&mapping_info, (pgd_t *)level4p,
+	kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt,
 				  start, end);
 }
 
@@ -134,5 +140,5 @@ void add_identity_map(unsigned long start, unsigned long size)
  */
 void finalize_identity_maps(void)
 {
-	write_cr3(level4p);
+	write_cr3(top_level_pgt);
 }

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web