Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1672587 > unrolled thread
| Started by | "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
|---|---|
| First post | 2017-06-22 14:30 +0200 |
| Last post | 2017-06-30 15:20 +0200 |
| Articles | 9 — 5 participants |
Back to article view | Back to linux.kernel
[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
| From | "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
|---|---|
| Date | 2017-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]
| From | "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
|---|---|
| Date | 2017-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]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2017-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]
| From | "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
|---|---|
| Date | 2017-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]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2017-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]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2017-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]
| From | "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
|---|---|
| Date | 2017-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]
| From | Kees Cook <keescook@chromium.org> |
|---|---|
| Date | 2017-06-28 20:00 +0200 |
| Subject | Re: [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]
| From | "tip-bot for Kirill A. Shutemov" <tipbot@zytor.com> |
|---|---|
| Date | 2017-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