Re: [patch V163 27/51] x86/mm/pti: Populate user PGD

From: Juergen Gross
Date: Wed Dec 20 2017 - 11:26:30 EST


On 20/12/17 01:22, Thomas Gleixner wrote:
> On Tue, 19 Dec 2017, Thomas Gleixner wrote:
>> On Tue, 19 Dec 2017, Ingo Molnar wrote:
>> We don't run out of space, but the 0-day robot triggered a nasty issue.
>>
>> The fixmap bottom address, which contains the early_ioremap fixmap area, is:
>>
>> vaddr_bt = FIXADDR_TOP - FIX_BTMAP_BEGIN * PAGE_SIZE
>>
>> If that address is lower than:
>>
>> vaddr_end = __START_KERNEL_map + KERNEL_IMAGE_SIZE;
>>
>> then cleanup_highmap() will happily 0 out the PMD entry for the PTE page of
>> FIX_BTMAP. That entry was set up earlier in early_ioremap_init().
>>
>> As a consequence the first call to __early_set_fixmap() which tries to
>> install a PTE for early_ioremap() will crash and burn.
>>
>> Below is a nasty hack which fixes the problem. Ideally we get all of this
>> cpu_entry_stuff out of the fixmap. I'll look into that later, but for now
>> the patch 'fixes' the issue.
>
> I had a stab on moving the cpu_entry_area to some other place.
>
> The patch below works, but:
>
> - it breaks i386 build because I have not yet found a way to place the
> CPU_ENTRY_AREA_BASE without creating include recursion hell
>
> - it probably does not work on XEN_PV, but I'm too tired now to figure
> that out.

The attached patch lets the system come up as XEN_PV.


Juergen
diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c
index e4a6fe8354f0..577fa8adb785 100644
--- a/arch/x86/entry/vsyscall/vsyscall_64.c
+++ b/arch/x86/entry/vsyscall/vsyscall_64.c
@@ -37,6 +37,7 @@
#include <asm/unistd.h>
#include <asm/fixmap.h>
#include <asm/traps.h>
+#include <asm/paravirt.h>

#define CREATE_TRACE_POINTS
#include "vsyscall_trace.h"
@@ -351,15 +352,15 @@ void __init set_vsyscall_pgtable_user_bits(pgd_t *root)
pmd_t *pmd;

pgd = pgd_offset_pgd(root, VSYSCALL_ADDR);
- pgd->pgd |= _PAGE_USER;
+ set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER));
p4d = p4d_offset(pgd, VSYSCALL_ADDR);
#if CONFIG_PGTABLE_LEVELS >= 5
p4d->p4d |= _PAGE_USER;
#endif
pud = pud_offset(p4d, VSYSCALL_ADDR);
- pud->pud |= _PAGE_USER;
+ set_pud(pud, __pud(pud_val(*pud) | _PAGE_USER));
pmd = pmd_offset(pud, VSYSCALL_ADDR);
- pmd->pmd |= _PAGE_USER;
+ set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_USER));
}

void __init map_vsyscall(void)