In order to unify FIXADDR_TOP for x86 and allow fixmap area to be
moveable, vsyscall page should be mapped individually. However, for
XENPV guest, vsyscall page needs to be mapped into user pagetable too.
So introduce a new PVMMU op to help to map vsyscall page.
Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
Cc: Thomas Garnier <thgarnie@chromium.org>
Cc: Kees Cook <keescook@chromium.org>
---
arch/x86/entry/vsyscall/vsyscall_64.c | 3 +--
arch/x86/include/asm/paravirt.h | 7 +++++++
arch/x86/include/asm/paravirt_types.h | 4 ++++
arch/x86/include/asm/vsyscall.h | 13 +++++++++++++
arch/x86/kernel/paravirt.c | 4 ++++
arch/x86/xen/mmu_pv.c | 20 ++++++++++++++------
6 files changed, 43 insertions(+), 8 deletions(-)
@@ -385,8 +385,7 @@ void __init map_vsyscall(void)
* page.
*/
if (vsyscall_mode == EMULATE) {
- __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
- PAGE_KERNEL_VVAR);
+ __set_vsyscall_page(physaddr_vsyscall, PAGE_KERNEL_VVAR);
set_vsyscall_pgtable_user_bits(swapper_pg_dir);
}
@@ -576,6 +576,13 @@ static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
{
pv_ops.mmu.set_fixmap(idx, phys, flags);
}
+
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
+static inline void __set_vsyscall_page(phys_addr_t phys, pgprot_t flags)
+{
+ pv_ops.mmu.set_vsyscall_page(phys, flags);
+}
+#endif
#endif
#if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS)
@@ -224,6 +224,10 @@ struct pv_mmu_ops {
an mfn. We can tell which is which from the index. */
void (*set_fixmap)(unsigned /* enum fixed_addresses */ idx,
phys_addr_t phys, pgprot_t flags);
+
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
+ void (*set_vsyscall_page)(phys_addr_t phys, pgprot_t flags);
+#endif
#endif
} __no_randomize_layout;
@@ -2,6 +2,7 @@
#ifndef _ASM_X86_VSYSCALL_H
#define _ASM_X86_VSYSCALL_H
+#include <asm/pgtable.h>
#include <linux/seqlock.h>
#include <uapi/asm/vsyscall.h>
@@ -15,6 +16,18 @@ extern void set_vsyscall_pgtable_user_bits(pgd_t *root);
*/
extern bool emulate_vsyscall(unsigned long error_code,
struct pt_regs *regs, unsigned long address);
+static inline void native_set_vsyscall_page(phys_addr_t phys, pgprot_t flags)
+{
+ pgprot_val(flags) &= __default_kernel_pte_mask;
+ set_pte_vaddr(VSYSCALL_ADDR, pfn_pte(phys >> PAGE_SHIFT, flags));
+}
+
+#ifndef CONFIG_PARAVIRT_XXL
+#define __set_vsyscall_page native_set_vsyscall_page
+#else
+#include <asm/paravirt.h>
+#endif
+
#else
static inline void map_vsyscall(void) {}
static inline bool emulate_vsyscall(unsigned long error_code,
@@ -33,6 +33,7 @@
#include <asm/tlb.h>
#include <asm/io_bitmap.h>
#include <asm/gsseg.h>
+#include <asm/vsyscall.h>
/*
* nop stub, which must not clobber anything *including the stack* to
@@ -357,6 +358,9 @@ struct paravirt_patch_template pv_ops = {
},
.mmu.set_fixmap = native_set_fixmap,
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
+ .mmu.set_vsyscall_page = native_set_vsyscall_page,
+#endif
#endif /* CONFIG_PARAVIRT_XXL */
#if defined(CONFIG_PARAVIRT_SPINLOCKS)
@@ -59,6 +59,7 @@
#include <asm/tlbflush.h>
#include <asm/fixmap.h>
+#include <asm/vsyscall.h>
#include <asm/mmu_context.h>
#include <asm/setup.h>
#include <asm/paravirt.h>
@@ -2020,9 +2021,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
switch (idx) {
case FIX_BTMAP_END ... FIX_BTMAP_BEGIN:
-#ifdef CONFIG_X86_VSYSCALL_EMULATION
- case VSYSCALL_PAGE:
-#endif
/* All local page mappings */
pte = pfn_pte(phys, prot);
break;
@@ -2058,14 +2056,21 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
vaddr = __fix_to_virt(idx);
if (HYPERVISOR_update_va_mapping(vaddr, pte, UVMF_INVLPG))
BUG();
+}
#ifdef CONFIG_X86_VSYSCALL_EMULATION
+static void xen_set_vsyscall_page(phys_addr_t phys, pgprot_t prot)
+{
+ pte_t pte = pfn_pte(phys >> PAGE_SHIFT, prot);
+
+ if (HYPERVISOR_update_va_mapping(VSYSCALL_ADDR, pte, UVMF_INVLPG))
+ BUG();
+
/* Replicate changes to map the vsyscall page into the user
pagetable vsyscall mapping. */
- if (idx == VSYSCALL_PAGE)
- set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte);
-#endif
+ set_pte_vaddr_pud(level3_user_vsyscall, VSYSCALL_ADDR, pte);
}
+#endif
static void __init xen_post_allocator_init(void)
{
@@ -2156,6 +2161,9 @@ static const typeof(pv_ops) xen_mmu_ops __initconst = {
},
.set_fixmap = xen_set_fixmap,
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
+ .set_vsyscall_page = xen_set_vsyscall_page,
+#endif
},
};