x86/mm: Adapt MODULES_END based on Fixmap section size
PATCH v3 1/4 x86/mm: Adapt MODULES_END based on Fixmap section size
This patch aligns MODULES_END to the beginning of the Fixmap section. It optimizes the space available for both sections. The address is pre-computed based on the number of pages required by the Fixmap section.
It will allow GDT remapping in the Fixmap section. The current MODULES_END static address does not provide enough space for the kernel to support a large number of processors.
---
Based on next-20170213
--- arch/x86/include/asm/fixmap.h | 8 ++++++++ arch/x86/include/asm/pgtable_64_types.h | 3 --- arch/x86/kernel/module.c | 1 + arch/x86/mm/dump_pagetables.c | 1 + arch/x86/mm/kasan_init_64.c | 1 + 5 files changed, 11 insertions(+), 3 deletions(-)
arch/x86/include/asm/fixmap.h +8 -0
@@ -132,6 +132,14 @@ enum fixed_addresses {extern void reserve_top_address (unsigned long reserve); +/* On 64-bit, the module sections ends with the start of the fixmap */ +#ifdef CONFIG_X86_64 +#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1) +#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#endif /* CONFIG_X86_64 */ + +#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
arch/x86/include/asm/pgtable_64_types.h +0 -3
@@ -66,9 +66,6 @@ typedef struct { pteval_t pte; } pte_t;#define VMEMMAP_START __VMEMMAP_BASE#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) -#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL) -#define MODULES_LEN (MODULES_END - MODULES_VADDR)#define ESPFIX_PGD_ENTRY _AC(-2, UL)#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT)#define EFI_VA_START ( -4 * (_AC(1, UL) << 30))
arch/x86/kernel/module.c +1 -0
@@ -35,6 +35,7 @@#include <asm/page.h> #include <asm/pgtable.h> #include <asm/setup.h> +#include <asm/fixmap.h> #if 0 #define DEBUGP (fmt, ...) \
arch/x86/mm/dump_pagetables.c +1 -0
@@ -19,6 +19,7 @@#include <linux/seq_file.h> #include <asm/pgtable.h> +#include <asm/fixmap.h> /* * The dumper groups pagetable entries of the same type into one, and for
arch/x86/mm/kasan_init_64.c +1 -0
@@ -8,6 +8,7 @@#include <asm/tlbflush.h> #include <asm/sections.h> +#include <asm/fixmap.h> extern pgd_t early_level4_pgt[PTRS_PER_PGD ];extern struct range pfn_mapped[E820_X_MAX ];
Signature · 1 line
2.11.0.483.g087da7b7c-goog
PATCH v3 2/4 x86: Remap GDT tables in the Fixmap section
Each processor holds a GDT in its per-cpu structure. The sgdt instruction gives the base address of the current GDT. This address can be used to bypass KASLR memory randomization. With another bug, an attacker could target other per-cpu structures or deduce the base of the main memory section (PAGE_OFFSET).
This patch relocates the GDT table for each processor inside the Fixmap section. The space is reserved based on number of supported processors.
For consistency, the remapping is done by default on 32 and 64-bit.
Each processor switches to its remapped GDT at the end of initialization. For hibernation, the main processor returns with the original GDT and switches back to the remapping at completion.
This patch was tested on both architectures. Hibernation and KVM were both tested specially for their usage of the GDT.
---
Based on next-20170213
--- arch/x86/entry/vdso/vma.c | 2 +- arch/x86/include/asm/desc.h | 33 +++++++++++++++++++++++++++++---- arch/x86/include/asm/fixmap.h | 4 ++++ arch/x86/include/asm/processor.h | 1 + arch/x86/include/asm/stackprotector.h | 2 +- arch/x86/kernel/acpi/sleep.c | 2 +- arch/x86/kernel/apm_32.c | 6 +++--- arch/x86/kernel/cpu/common.c | 26 ++++++++++++++++++++++++-- arch/x86/kernel/setup_percpu.c | 2 +- arch/x86/kernel/smpboot.c | 2 +- arch/x86/platform/efi/efi_32.c | 4 ++-- arch/x86/power/cpu.c | 7 +++++-- arch/x86/xen/enlighten.c | 2 +- arch/x86/xen/smp.c | 2 +- drivers/lguest/x86/core.c | 6 +++--- drivers/pnp/pnpbios/bioscalls.c | 10 +++++----- 16 files changed, 83 insertions(+), 28 deletions(-)
arch/x86/entry/vdso/vma.c +1 -1
@@ -353,7 +353,7 @@ static void vgetcpu_cpu_init(void *arg) d.p =1 ;/* Present */ d.d =1 ;/* 32-bit */ -write_gdt_entry (get_cpu_gdt_table (cpu),GDT_ENTRY_PER_CPU , &d,DESCTYPE_S ); +write_gdt_entry (get_cpu_gdt_rw (cpu),GDT_ENTRY_PER_CPU , &d,DESCTYPE_S ); }static int vgetcpu_online (unsigned int cpu)
arch/x86/include/asm/desc.h +29 -4
@@ -4,6 +4,7 @@#include <asm/desc_defs.h> #include <asm/ldt.h> #include <asm/mmu.h> +#include <asm/fixmap.h> #include <linux/smp.h> #include <linux/percpu.h>
@@ -45,11 +46,35 @@ struct gdt_page { DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page); -static inline struct desc_struct *get_cpu_gdt_table (unsigned int cpu) +/* Provide the original GDT */ +static inline struct desc_struct *get_cpu_gdt_rw (unsigned int cpu) {return per_cpu (gdt_page, cpu).gdt; } +static inline unsigned long get_cpu_gdt_rw_vaddr (unsigned int cpu) +{ +return (unsigned long )get_cpu_gdt_rw (cpu); +} + +/* Get the fixmap index for a specific processor */ +static inline unsigned int get_cpu_gdt_ro_index (int cpu) +{ +return FIX_GDT_REMAP_BEGIN + cpu; +} + +/* Provide the fixmap address of the remapped GDT */ +static inline struct desc_struct *get_cpu_gdt_ro (int cpu) +{ +unsigned int idx =get_cpu_gdt_ro_index (cpu); +return (struct desc_struct *)__fix_to_virt (idx); +} + +static inline unsigned long get_cpu_gdt_ro_vaddr (int cpu) +{ +return (unsigned long )get_cpu_gdt_ro (cpu); +} +#ifdef CONFIG_X86_64 static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
@@ -174,7 +199,7 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned tstatic inline void __set_tss_desc (unsigned cpu,unsigned int entry,void *addr) { -struct desc_struct *d =get_cpu_gdt_table (cpu); +struct desc_struct *d =get_cpu_gdt_rw (cpu);tss_desc tss;/*
@@ -202,7 +227,7 @@ static inline void native_set_ldt(const void *addr, unsigned int entries)set_tssldt_descriptor (&ldt, (unsigned long )addr,DESC_LDT , entries *LDT_ENTRY_SIZE -1 ); -write_gdt_entry (get_cpu_gdt_table (cpu),GDT_ENTRY_LDT , +write_gdt_entry (get_cpu_gdt_rw (cpu),GDT_ENTRY_LDT , &ldt,DESC_LDT ); asmvolatile ("lldt %w0" ::"q" (GDT_ENTRY_LDT *8 )); }
@@ -244,7 +269,7 @@ static inline unsigned long native_store_tr(void)static inline void native_load_tls (struct thread_struct *t,unsigned int cpu) { -struct desc_struct *gdt =get_cpu_gdt_table (cpu); +struct desc_struct *gdt =get_cpu_gdt_rw (cpu);unsigned int i;for (i =0 ; i <GDT_ENTRY_TLS_ENTRIES ; i++)
arch/x86/include/asm/fixmap.h +4 -0
@@ -100,6 +100,10 @@ enum fixed_addresses {#ifdef CONFIG_X86_INTEL_MID FIX_LNW_VRTC , #endif +/* Fixmap entries to remap the GDTs, one per processor. */ +FIX_GDT_REMAP_BEGIN , +FIX_GDT_REMAP_END =FIX_GDT_REMAP_BEGIN +NR_CPUS -1 , + __end_of_permanent_fixed_addresses,/*
arch/x86/include/asm/processor.h +1 -0
@@ -706,6 +706,7 @@ extern struct desc_ptr early_gdt_descr;extern void cpu_set_gdt (int );extern void switch_to_new_gdt (int ); +extern void load_fixmap_gdt (int );extern void load_percpu_segment (int );extern void cpu_init (void );
arch/x86/include/asm/stackprotector.h +1 -1
@@ -87,7 +87,7 @@ static inline void setup_stack_canary_segment(int cpu) {#ifdef CONFIG_X86_32 unsigned long canary = (unsigned long )&per_cpu (stack_canary, cpu); -struct desc_struct *gdt_table =get_cpu_gdt_table (cpu); +struct desc_struct *gdt_table =get_cpu_gdt_rw (cpu);struct desc_struct desc; desc = gdt_table[GDT_ENTRY_STACK_CANARY ];
arch/x86/kernel/acpi/sleep.c +1 -1
@@ -101,7 +101,7 @@ int x86_acpi_suspend_lowlevel(void)#ifdef CONFIG_SMP initial_stack = (unsigned long )temp_stack +sizeof (temp_stack); early_gdt_descr.address = - (unsigned long )get_cpu_gdt_table (smp_processor_id ()); + (unsigned long )get_cpu_gdt_rw (smp_processor_id ()); initial_gs =per_cpu_offset (smp_processor_id ());#endif initial_code = (unsigned long )wakeup_long64;
arch/x86/kernel/apm_32.c +3 -3
@@ -608,7 +608,7 @@ static long __apm_bios_call(void *_call) cpu =get_cpu ();BUG_ON (cpu !=0 ); - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu); save_desc_40 = gdt[0x40 /8 ]; gdt[0x40 /8 ] = bad_bios_desc;
@@ -684,7 +684,7 @@ static long __apm_bios_call_simple(void *_call) cpu =get_cpu ();BUG_ON (cpu !=0 ); - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu); save_desc_40 = gdt[0x40 /8 ]; gdt[0x40 /8 ] = bad_bios_desc;
@@ -2351,7 +2351,7 @@ static int __init apm_init(void)* Note we only set APM segments on CPU zero, since we pin the APM * code to that CPU. */ - gdt =get_cpu_gdt_table (0 ); + gdt =get_cpu_gdt_rw (0 );set_desc_base (&gdt[APM_CS >>3 ], (unsigned long )__va ((unsigned long )apm_info.bios.cseg <<4 )); set_desc_base(&gdt[APM_CS_16 >> 3],
arch/x86/kernel/cpu/common.c +24 -2
@@ -444,6 +444,23 @@ void load_percpu_segment(int cpu)load_stack_canary_segment (); } +/* Setup the fixmap mapping only once per-processor */ +static inline void setup_fixmap_gdt (int cpu) +{ +__set_fixmap (get_cpu_gdt_ro_index (cpu), +__pa (get_cpu_gdt_rw (cpu)),PAGE_KERNEL ); +} + +/* Load a fixmap remapping of the per-cpu GDT */ +void load_fixmap_gdt (int cpu) +{ +struct desc_ptr gdt_descr; + + gdt_descr.address = (long )get_cpu_gdt_ro (cpu); + gdt_descr.size =GDT_SIZE -1 ; +load_gdt (&gdt_descr); +} +/* * Current gdt points %fs at the "master" per-cpu area: after this, * it's on the real one.
@@ -452,11 +469,10 @@ void switch_to_new_gdt(int cpu) {struct desc_ptr gdt_descr; - gdt_descr.address = (long )get_cpu_gdt_table (cpu); + gdt_descr.address = (long )get_cpu_gdt_rw (cpu); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr);/* Reload the per-cpu base */ -load_percpu_segment (cpu); }
@@ -1524,6 +1540,9 @@ void cpu_init(void)if (is_uv_system ())uv_cpu_init (); + +setup_fixmap_gdt (cpu); + load_fixmap_gdt(cpu); }#else
@@ -1579,6 +1598,9 @@ void cpu_init(void)dbg_restore_debug_regs ();fpu__init_cpu (); + +setup_fixmap_gdt (cpu); + load_fixmap_gdt(cpu); }#endif
arch/x86/kernel/setup_percpu.c +1 -1
@@ -160,7 +160,7 @@ static inline void setup_percpu_segment(int cpu)pack_descriptor (&gdt,per_cpu_offset (cpu),0xFFFFF ,0x2 |DESCTYPE_S ,0x8 ); gdt.s =1 ; -write_gdt_entry (get_cpu_gdt_table (cpu), +write_gdt_entry (get_cpu_gdt_rw (cpu),GDT_ENTRY_PERCPU , &gdt,DESCTYPE_S );#endif }
arch/x86/kernel/smpboot.c +1 -1
@@ -980,7 +980,7 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)unsigned long timeout; idle->thread.sp = (unsigned long )task_pt_regs (idle); - early_gdt_descr.address = (unsigned long )get_cpu_gdt_table (cpu); + early_gdt_descr.address = (unsigned long )get_cpu_gdt_rw (cpu); initial_code = (unsigned long )start_secondary; initial_stack = idle->thread.sp;
arch/x86/platform/efi/efi_32.c +2 -2
@@ -68,7 +68,7 @@ pgd_t * __init efi_call_phys_prolog(void)load_cr3 (initial_page_table);__flush_tlb_all (); - gdt_descr.address =__pa (get_cpu_gdt_table (0 )); + gdt_descr.address =__pa (get_cpu_gdt_rw (0 )); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr);
@@ -79,7 +79,7 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd) {struct desc_ptr gdt_descr; - gdt_descr.address = (unsigned long )get_cpu_gdt_table (0 ); + gdt_descr.address = (unsigned long )get_cpu_gdt_rw (0 ); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr);
arch/x86/power/cpu.c +5 -2
@@ -95,7 +95,7 @@ static void __save_processor_state(struct saved_context *ctxt)* 'pmode_gdt' in wakeup_start. */ ctxt->gdt_desc.size =GDT_SIZE -1 ; - ctxt->gdt_desc.address = (unsigned long )get_cpu_gdt_table (smp_processor_id ()); + ctxt->gdt_desc.address = (unsigned long )get_cpu_gdt_rw (smp_processor_id ());store_tr (ctxt->tr);
@@ -162,7 +162,7 @@ static void fix_processor_context(void)int cpu =smp_processor_id ();struct tss_struct *t = &per_cpu (cpu_tss, cpu);#ifdef CONFIG_X86_64 -struct desc_struct *desc =get_cpu_gdt_table (cpu); +struct desc_struct *desc =get_cpu_gdt_rw (cpu);tss_desc tss;#endif set_tss_desc (cpu, t);/*
@@ -183,6 +183,9 @@ static void fix_processor_context(void)load_mm_ldt (current->active_mm);/* This does lldt */ fpu__resume_cpu (); + +/* The processor is back on the direct GDT, load back the fixmap */ +load_fixmap_gdt (cpu); }/**
arch/x86/xen/enlighten.c +1 -1
@@ -710,7 +710,7 @@ static void load_TLS_descriptor(struct thread_struct *t, *shadow = t->tls_array[i]; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu); maddr =arbitrary_virt_to_machine (&gdt[GDT_ENTRY_TLS_MIN +i]); mc =__xen_mc_entry (0 );
arch/x86/xen/smp.c +1 -1
@@ -391,7 +391,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)if (ctxt ==NULL )return -ENOMEM ; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu);#ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU;
drivers/lguest/x86/core.c +3 -3
@@ -504,7 +504,7 @@ void __init lguest_arch_host_init(void)* byte, not the size, hence the "-1"). */ state->host_gdt_desc.size =GDT_SIZE -1 ; - state->host_gdt_desc.address = (long )get_cpu_gdt_table (i); + state->host_gdt_desc.address = (long )get_cpu_gdt_rw (i);/* * All CPUs on the Host use the same Interrupt Descriptor
@@ -554,8 +554,8 @@ void __init lguest_arch_host_init(void)* The Host needs to be able to use the LGUEST segments on this * CPU, too, so put them in the Host GDT. */ -get_cpu_gdt_table (i)[GDT_ENTRY_LGUEST_CS ] =FULL_EXEC_SEGMENT ; -get_cpu_gdt_table (i)[GDT_ENTRY_LGUEST_DS ] =FULL_SEGMENT ; +get_cpu_gdt_rw (i)[GDT_ENTRY_LGUEST_CS ] =FULL_EXEC_SEGMENT ; +get_cpu_gdt_rw (i)[GDT_ENTRY_LGUEST_DS ] =FULL_SEGMENT ; }/*
drivers/pnp/pnpbios/bioscalls.c +5 -5
@@ -54,7 +54,7 @@ __asm__(".text \n"#define Q2_SET_SEL (cpu, selname, address, size) \ do { \ - struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ + struct desc_struct *gdt = get_cpu_gdt_rw((cpu)); \ set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0)
@@ -95,8 +95,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,return PNP_FUNCTION_NOT_SUPPORTED ; cpu =get_cpu (); - save_desc_40 =get_cpu_gdt_table (cpu)[0x40 /8 ]; -get_cpu_gdt_table (cpu)[0x40 /8 ] = bad_bios_desc; + save_desc_40 =get_cpu_gdt_rw (cpu)[0x40 /8 ]; +get_cpu_gdt_rw (cpu)[0x40 /8 ] = bad_bios_desc;/* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave (&pnp_bios_lock, flags);
@@ -134,7 +134,7 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, :"memory");spin_unlock_irqrestore (&pnp_bios_lock, flags); -get_cpu_gdt_table (cpu)[0x40 /8 ] = save_desc_40; +get_cpu_gdt_rw (cpu)[0x40 /8 ] = save_desc_40;put_cpu ();/* If we get here and this is set then the PnP BIOS faulted on us. */
@@ -477,7 +477,7 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.segment =PNP_CS16 ;for_each_possible_cpu (i) { -struct desc_struct *gdt =get_cpu_gdt_table (i); +struct desc_struct *gdt =get_cpu_gdt_rw (i);if (!gdt)continue ; set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32],
Signature · 1 line
2.11.0.483.g087da7b7c-goog
Boris Ostrovsky
reviewerRe: [PATCH v3 2/4] x86: Remap GDT tables in the Fixmap section
arch/x86/xen/smp.c cpu_initialize_context(unsigned int cpu, struct task_struct *idle) · line 397
Quoted 13 lines · Thomas Garnier
arch/x86/xen/smp.c +1
-1@@ -391,7 +391,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)if (ctxt ==NULL )return -ENOMEM ; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu);#ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU;
Which tree are these patches against? The chunk above cannot be applied to current Linus tree but it can be applied against Xen staging tree that has not been pulled yet.
I can apply this manually but the series crashes PV guests so I want to make sure I am using right bits.
-boris
[kernel-hardening] Re: [PATCH v3 2/4] x86: Remap GDT tables in the Fixmap section
Quoted 20 lines · Boris Ostrovsky
arch/x86/xen/smp.c cpu_initialize_context(unsigned int cpu, struct task_struct *idle) · line 397
Quoted 13 lines · Thomas Garnier
arch/x86/xen/smp.c +1
-1@@ -391,7 +391,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)if (ctxt ==NULL )return -ENOMEM ; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu);#ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU;Which tree are these patches against? The chunk above cannot be applied to current Linus tree but it can be applied against Xen staging tree that has not been pulled yet.
Quoted 3 lines
I can apply this manually but the series crashes PV guests so I want to make sure I am using right bits.
That was against linux-next (next-20170213 tag).
Quoted 3 lines
-boris
Signature · 1 line
Thomas
Re: [PATCH v3 2/4] x86: Remap GDT tables in the Fixmap section
In reply to Boris OstrovskyQuoted 20 lines · Boris Ostrovsky
arch/x86/xen/smp.c cpu_initialize_context(unsigned int cpu, struct task_struct *idle) · line 397
Quoted 13 lines · Thomas Garnier
arch/x86/xen/smp.c +1
-1@@ -391,7 +391,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)if (ctxt ==NULL )return -ENOMEM ; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu);#ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU;Which tree are these patches against? The chunk above cannot be applied to current Linus tree but it can be applied against Xen staging tree that has not been pulled yet.
Quoted 3 lines
I can apply this manually but the series crashes PV guests so I want to make sure I am using right bits.
That was against linux-next (next-20170213 tag).
Quoted 3 lines
-boris
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Boris Ostrovsky
reviewerRe: [PATCH v3 2/4] x86: Remap GDT tables in the Fixmap section
In reply to Thomas Garnierarch/x86/xen/smp.c cpu_initialize_context(unsigned int cpu, struct task_struct *idle) · line 397
Quoted 13 lines · Thomas Garnier
arch/x86/xen/smp.c +1
-1@@ -391,7 +391,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)if (ctxt ==NULL )return -ENOMEM ; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu);#ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU;
Which tree are these patches against? The chunk above cannot be applied to current Linus tree but it can be applied against Xen staging tree that has not been pulled yet.
I can apply this manually but the series crashes PV guests so I want to make sure I am using right bits.
-boris
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
PATCH v3 2/4 x86: Remap GDT tables in the Fixmap section
In reply to Thomas GarnierEach processor holds a GDT in its per-cpu structure. The sgdt instruction gives the base address of the current GDT. This address can be used to bypass KASLR memory randomization. With another bug, an attacker could target other per-cpu structures or deduce the base of the main memory section (PAGE_OFFSET).
This patch relocates the GDT table for each processor inside the Fixmap section. The space is reserved based on number of supported processors.
For consistency, the remapping is done by default on 32 and 64-bit.
Each processor switches to its remapped GDT at the end of initialization. For hibernation, the main processor returns with the original GDT and switches back to the remapping at completion.
This patch was tested on both architectures. Hibernation and KVM were both tested specially for their usage of the GDT.
---
Based on next-20170213
--- arch/x86/entry/vdso/vma.c | 2 +- arch/x86/include/asm/desc.h | 33 +++++++++++++++++++++++++++++---- arch/x86/include/asm/fixmap.h | 4 ++++ arch/x86/include/asm/processor.h | 1 + arch/x86/include/asm/stackprotector.h | 2 +- arch/x86/kernel/acpi/sleep.c | 2 +- arch/x86/kernel/apm_32.c | 6 +++--- arch/x86/kernel/cpu/common.c | 26 ++++++++++++++++++++++++-- arch/x86/kernel/setup_percpu.c | 2 +- arch/x86/kernel/smpboot.c | 2 +- arch/x86/platform/efi/efi_32.c | 4 ++-- arch/x86/power/cpu.c | 7 +++++-- arch/x86/xen/enlighten.c | 2 +- arch/x86/xen/smp.c | 2 +- drivers/lguest/x86/core.c | 6 +++--- drivers/pnp/pnpbios/bioscalls.c | 10 +++++----- 16 files changed, 83 insertions(+), 28 deletions(-)
arch/x86/entry/vdso/vma.c +1 -1
@@ -353,7 +353,7 @@ static void vgetcpu_cpu_init(void *arg) d.p =1 ;/* Present */ d.d =1 ;/* 32-bit */ -write_gdt_entry (get_cpu_gdt_table (cpu),GDT_ENTRY_PER_CPU , &d,DESCTYPE_S ); +write_gdt_entry (get_cpu_gdt_rw (cpu),GDT_ENTRY_PER_CPU , &d,DESCTYPE_S ); }static int vgetcpu_online (unsigned int cpu)
arch/x86/include/asm/desc.h +29 -4
@@ -4,6 +4,7 @@#include <asm/desc_defs.h> #include <asm/ldt.h> #include <asm/mmu.h> +#include <asm/fixmap.h> #include <linux/smp.h> #include <linux/percpu.h>
@@ -45,11 +46,35 @@ struct gdt_page { DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page); -static inline struct desc_struct *get_cpu_gdt_table (unsigned int cpu) +/* Provide the original GDT */ +static inline struct desc_struct *get_cpu_gdt_rw (unsigned int cpu) {return per_cpu (gdt_page, cpu).gdt; } +static inline unsigned long get_cpu_gdt_rw_vaddr (unsigned int cpu) +{ +return (unsigned long )get_cpu_gdt_rw (cpu); +} + +/* Get the fixmap index for a specific processor */ +static inline unsigned int get_cpu_gdt_ro_index (int cpu) +{ +return FIX_GDT_REMAP_BEGIN + cpu; +} + +/* Provide the fixmap address of the remapped GDT */ +static inline struct desc_struct *get_cpu_gdt_ro (int cpu) +{ +unsigned int idx =get_cpu_gdt_ro_index (cpu); +return (struct desc_struct *)__fix_to_virt (idx); +} + +static inline unsigned long get_cpu_gdt_ro_vaddr (int cpu) +{ +return (unsigned long )get_cpu_gdt_ro (cpu); +} +#ifdef CONFIG_X86_64 static inline void pack_gate(gate_desc *gate, unsigned type, unsigned long func,
@@ -174,7 +199,7 @@ static inline void set_tssldt_descriptor(void *d, unsigned long addr, unsigned tstatic inline void __set_tss_desc (unsigned cpu,unsigned int entry,void *addr) { -struct desc_struct *d =get_cpu_gdt_table (cpu); +struct desc_struct *d =get_cpu_gdt_rw (cpu);tss_desc tss;/*
@@ -202,7 +227,7 @@ static inline void native_set_ldt(const void *addr, unsigned int entries)set_tssldt_descriptor (&ldt, (unsigned long )addr,DESC_LDT , entries *LDT_ENTRY_SIZE -1 ); -write_gdt_entry (get_cpu_gdt_table (cpu),GDT_ENTRY_LDT , +write_gdt_entry (get_cpu_gdt_rw (cpu),GDT_ENTRY_LDT , &ldt,DESC_LDT ); asmvolatile ("lldt %w0" ::"q" (GDT_ENTRY_LDT *8 )); }
@@ -244,7 +269,7 @@ static inline unsigned long native_store_tr(void)static inline void native_load_tls (struct thread_struct *t,unsigned int cpu) { -struct desc_struct *gdt =get_cpu_gdt_table (cpu); +struct desc_struct *gdt =get_cpu_gdt_rw (cpu);unsigned int i;for (i =0 ; i <GDT_ENTRY_TLS_ENTRIES ; i++)
arch/x86/include/asm/fixmap.h +4 -0
@@ -100,6 +100,10 @@ enum fixed_addresses {#ifdef CONFIG_X86_INTEL_MID FIX_LNW_VRTC , #endif +/* Fixmap entries to remap the GDTs, one per processor. */ +FIX_GDT_REMAP_BEGIN , +FIX_GDT_REMAP_END =FIX_GDT_REMAP_BEGIN +NR_CPUS -1 , + __end_of_permanent_fixed_addresses,/*
arch/x86/include/asm/processor.h +1 -0
@@ -706,6 +706,7 @@ extern struct desc_ptr early_gdt_descr;extern void cpu_set_gdt (int );extern void switch_to_new_gdt (int ); +extern void load_fixmap_gdt (int );extern void load_percpu_segment (int );extern void cpu_init (void );
arch/x86/include/asm/stackprotector.h +1 -1
@@ -87,7 +87,7 @@ static inline void setup_stack_canary_segment(int cpu) {#ifdef CONFIG_X86_32 unsigned long canary = (unsigned long )&per_cpu (stack_canary, cpu); -struct desc_struct *gdt_table =get_cpu_gdt_table (cpu); +struct desc_struct *gdt_table =get_cpu_gdt_rw (cpu);struct desc_struct desc; desc = gdt_table[GDT_ENTRY_STACK_CANARY ];
arch/x86/kernel/acpi/sleep.c +1 -1
@@ -101,7 +101,7 @@ int x86_acpi_suspend_lowlevel(void)#ifdef CONFIG_SMP initial_stack = (unsigned long )temp_stack +sizeof (temp_stack); early_gdt_descr.address = - (unsigned long )get_cpu_gdt_table (smp_processor_id ()); + (unsigned long )get_cpu_gdt_rw (smp_processor_id ()); initial_gs =per_cpu_offset (smp_processor_id ());#endif initial_code = (unsigned long )wakeup_long64;
arch/x86/kernel/apm_32.c +3 -3
@@ -608,7 +608,7 @@ static long __apm_bios_call(void *_call) cpu =get_cpu ();BUG_ON (cpu !=0 ); - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu); save_desc_40 = gdt[0x40 /8 ]; gdt[0x40 /8 ] = bad_bios_desc;
@@ -684,7 +684,7 @@ static long __apm_bios_call_simple(void *_call) cpu =get_cpu ();BUG_ON (cpu !=0 ); - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu); save_desc_40 = gdt[0x40 /8 ]; gdt[0x40 /8 ] = bad_bios_desc;
@@ -2351,7 +2351,7 @@ static int __init apm_init(void)* Note we only set APM segments on CPU zero, since we pin the APM * code to that CPU. */ - gdt =get_cpu_gdt_table (0 ); + gdt =get_cpu_gdt_rw (0 );set_desc_base (&gdt[APM_CS >>3 ], (unsigned long )__va ((unsigned long )apm_info.bios.cseg <<4 )); set_desc_base(&gdt[APM_CS_16 >> 3],
arch/x86/kernel/cpu/common.c +24 -2
@@ -444,6 +444,23 @@ void load_percpu_segment(int cpu)load_stack_canary_segment (); } +/* Setup the fixmap mapping only once per-processor */ +static inline void setup_fixmap_gdt (int cpu) +{ +__set_fixmap (get_cpu_gdt_ro_index (cpu), +__pa (get_cpu_gdt_rw (cpu)),PAGE_KERNEL ); +} + +/* Load a fixmap remapping of the per-cpu GDT */ +void load_fixmap_gdt (int cpu) +{ +struct desc_ptr gdt_descr; + + gdt_descr.address = (long )get_cpu_gdt_ro (cpu); + gdt_descr.size =GDT_SIZE -1 ; +load_gdt (&gdt_descr); +} +/* * Current gdt points %fs at the "master" per-cpu area: after this, * it's on the real one.
@@ -452,11 +469,10 @@ void switch_to_new_gdt(int cpu) {struct desc_ptr gdt_descr; - gdt_descr.address = (long )get_cpu_gdt_table (cpu); + gdt_descr.address = (long )get_cpu_gdt_rw (cpu); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr);/* Reload the per-cpu base */ -load_percpu_segment (cpu); }
@@ -1524,6 +1540,9 @@ void cpu_init(void)if (is_uv_system ())uv_cpu_init (); + +setup_fixmap_gdt (cpu); + load_fixmap_gdt(cpu); }#else
@@ -1579,6 +1598,9 @@ void cpu_init(void)dbg_restore_debug_regs ();fpu__init_cpu (); + +setup_fixmap_gdt (cpu); + load_fixmap_gdt(cpu); }#endif
arch/x86/kernel/setup_percpu.c +1 -1
@@ -160,7 +160,7 @@ static inline void setup_percpu_segment(int cpu)pack_descriptor (&gdt,per_cpu_offset (cpu),0xFFFFF ,0x2 |DESCTYPE_S ,0x8 ); gdt.s =1 ; -write_gdt_entry (get_cpu_gdt_table (cpu), +write_gdt_entry (get_cpu_gdt_rw (cpu),GDT_ENTRY_PERCPU , &gdt,DESCTYPE_S );#endif }
arch/x86/kernel/smpboot.c +1 -1
@@ -980,7 +980,7 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)unsigned long timeout; idle->thread.sp = (unsigned long )task_pt_regs (idle); - early_gdt_descr.address = (unsigned long )get_cpu_gdt_table (cpu); + early_gdt_descr.address = (unsigned long )get_cpu_gdt_rw (cpu); initial_code = (unsigned long )start_secondary; initial_stack = idle->thread.sp;
arch/x86/platform/efi/efi_32.c +2 -2
@@ -68,7 +68,7 @@ pgd_t * __init efi_call_phys_prolog(void)load_cr3 (initial_page_table);__flush_tlb_all (); - gdt_descr.address =__pa (get_cpu_gdt_table (0 )); + gdt_descr.address =__pa (get_cpu_gdt_rw (0 )); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr);
@@ -79,7 +79,7 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd) {struct desc_ptr gdt_descr; - gdt_descr.address = (unsigned long )get_cpu_gdt_table (0 ); + gdt_descr.address = (unsigned long )get_cpu_gdt_rw (0 ); gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr);
arch/x86/power/cpu.c +5 -2
@@ -95,7 +95,7 @@ static void __save_processor_state(struct saved_context *ctxt)* 'pmode_gdt' in wakeup_start. */ ctxt->gdt_desc.size =GDT_SIZE -1 ; - ctxt->gdt_desc.address = (unsigned long )get_cpu_gdt_table (smp_processor_id ()); + ctxt->gdt_desc.address = (unsigned long )get_cpu_gdt_rw (smp_processor_id ());store_tr (ctxt->tr);
@@ -162,7 +162,7 @@ static void fix_processor_context(void)int cpu =smp_processor_id ();struct tss_struct *t = &per_cpu (cpu_tss, cpu);#ifdef CONFIG_X86_64 -struct desc_struct *desc =get_cpu_gdt_table (cpu); +struct desc_struct *desc =get_cpu_gdt_rw (cpu);tss_desc tss;#endif set_tss_desc (cpu, t);/*
@@ -183,6 +183,9 @@ static void fix_processor_context(void)load_mm_ldt (current->active_mm);/* This does lldt */ fpu__resume_cpu (); + +/* The processor is back on the direct GDT, load back the fixmap */ +load_fixmap_gdt (cpu); }/**
arch/x86/xen/enlighten.c +1 -1
@@ -710,7 +710,7 @@ static void load_TLS_descriptor(struct thread_struct *t, *shadow = t->tls_array[i]; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu); maddr =arbitrary_virt_to_machine (&gdt[GDT_ENTRY_TLS_MIN +i]); mc =__xen_mc_entry (0 );
arch/x86/xen/smp.c +1 -1
@@ -391,7 +391,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)if (ctxt ==NULL )return -ENOMEM ; - gdt =get_cpu_gdt_table (cpu); + gdt =get_cpu_gdt_rw (cpu);#ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU;
drivers/lguest/x86/core.c +3 -3
@@ -504,7 +504,7 @@ void __init lguest_arch_host_init(void)* byte, not the size, hence the "-1"). */ state->host_gdt_desc.size =GDT_SIZE -1 ; - state->host_gdt_desc.address = (long )get_cpu_gdt_table (i); + state->host_gdt_desc.address = (long )get_cpu_gdt_rw (i);/* * All CPUs on the Host use the same Interrupt Descriptor
@@ -554,8 +554,8 @@ void __init lguest_arch_host_init(void)* The Host needs to be able to use the LGUEST segments on this * CPU, too, so put them in the Host GDT. */ -get_cpu_gdt_table (i)[GDT_ENTRY_LGUEST_CS ] =FULL_EXEC_SEGMENT ; -get_cpu_gdt_table (i)[GDT_ENTRY_LGUEST_DS ] =FULL_SEGMENT ; +get_cpu_gdt_rw (i)[GDT_ENTRY_LGUEST_CS ] =FULL_EXEC_SEGMENT ; +get_cpu_gdt_rw (i)[GDT_ENTRY_LGUEST_DS ] =FULL_SEGMENT ; }/*
drivers/pnp/pnpbios/bioscalls.c +5 -5
@@ -54,7 +54,7 @@ __asm__(".text \n"#define Q2_SET_SEL (cpu, selname, address, size) \ do { \ - struct desc_struct *gdt = get_cpu_gdt_table((cpu)); \ + struct desc_struct *gdt = get_cpu_gdt_rw((cpu)); \ set_desc_base(&gdt[(selname) >> 3], (u32)(address)); \ set_desc_limit(&gdt[(selname) >> 3], (size) - 1); \ } while(0)
@@ -95,8 +95,8 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,return PNP_FUNCTION_NOT_SUPPORTED ; cpu =get_cpu (); - save_desc_40 =get_cpu_gdt_table (cpu)[0x40 /8 ]; -get_cpu_gdt_table (cpu)[0x40 /8 ] = bad_bios_desc; + save_desc_40 =get_cpu_gdt_rw (cpu)[0x40 /8 ]; +get_cpu_gdt_rw (cpu)[0x40 /8 ] = bad_bios_desc;/* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave (&pnp_bios_lock, flags);
@@ -134,7 +134,7 @@ static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3, :"memory");spin_unlock_irqrestore (&pnp_bios_lock, flags); -get_cpu_gdt_table (cpu)[0x40 /8 ] = save_desc_40; +get_cpu_gdt_rw (cpu)[0x40 /8 ] = save_desc_40;put_cpu ();/* If we get here and this is set then the PnP BIOS faulted on us. */
@@ -477,7 +477,7 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.segment =PNP_CS16 ;for_each_possible_cpu (i) { -struct desc_struct *gdt =get_cpu_gdt_table (i); +struct desc_struct *gdt =get_cpu_gdt_rw (i);if (!gdt)continue ; set_desc_base(&gdt[GDT_ENTRY_PNPBIOS_CS32],
Signature · 7 lines
2.11.0.483.g087da7b7c-goog _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
PATCH v3 3/4 x86: Make the GDT remapping read-only on 64-bit
In reply to Thomas GarnierThis patch makes the GDT remapped pages read-only to prevent corruption. This change is done only on 64-bit.
The native_load_tr_desc function was adapted to correctly handle a read-only GDT. The LTR instruction always writes to the GDT TSS entry. This generates a page fault if the GDT is read-only. This change checks if the current GDT is a remap and swap GDTs as needed. This function was tested by booting multiple machines and checking hibernation works properly.
KVM SVM and VMX were adapted to use the writeable GDT. On VMX, the per-cpu variable was removed for functions to fetch the original GDT. Instead of reloading the previous GDT, VMX will reload the fixmap GDT as expected. For testing, VMs were started and restored on multiple configurations.
---
Based on next-20170213
--- arch/x86/include/asm/desc.h | 51 ++++++++++++++++++++++++++++++++++++---- arch/x86/include/asm/processor.h | 1 + arch/x86/kernel/cpu/common.c | 28 +++++++++++++++++----- arch/x86/kvm/svm.c | 4 +--- arch/x86/kvm/vmx.c | 15 ++++-------- 5 files changed, 75 insertions(+), 24 deletions(-)
arch/x86/include/asm/desc.h +46 -5
@@ -57,6 +57,17 @@ static inline unsigned long get_cpu_gdt_rw_vaddr(unsigned int cpu)return (unsigned long )get_cpu_gdt_rw (cpu); } +/* Provide the current original GDT */ +static inline struct desc_struct *get_current_gdt_rw (void ) +{ +return this_cpu_ptr (&gdt_page)->gdt; +} + +static inline unsigned long get_current_gdt_rw_vaddr (void ) +{ +return (unsigned long )get_current_gdt_rw (); +} +/* Get the fixmap index for a specific processor */ static inline unsigned int get_cpu_gdt_ro_index (int cpu) {
@@ -233,11 +244,6 @@ static inline void native_set_ldt(const void *addr, unsigned int entries) } } -static inline void native_load_tr_desc (void ) -{ - asmvolatile ("ltr %w0" ::"q" (GDT_ENTRY_TSS *8 )); -} -static inline void native_load_gdt (const struct desc_ptr *dtr) { asmvolatile ("lgdt %0" ::"m" (*dtr));
@@ -258,6 +264,41 @@ static inline void native_store_idt(struct desc_ptr *dtr) asmvolatile ("sidt %0" :"=m" (*dtr)); } +/* +* The LTR instruction marks the TSS GDT entry as busy. On 64-bit, the GDT is +* a read-only remapping. To prevent a page fault, the GDT is switched to the +* original writeable version when needed. +*/ +#ifdef CONFIG_X86_64 +static inline void native_load_tr_desc (void ) +{ +struct desc_ptr gdt; +int cpu =raw_smp_processor_id (); +bool restore =0 ; +struct desc_struct *fixmap_gdt; + +native_store_gdt (&gdt); + fixmap_gdt =get_cpu_gdt_ro (cpu); + +/* +* If the current GDT is the read-only fixmap, swap to the original +* writeable version. Swap back at the end. +*/ +if (gdt.address == (unsigned long )fixmap_gdt) { +load_direct_gdt (cpu); + restore =1 ; + } + asmvolatile ("ltr %w0" ::"q" (GDT_ENTRY_TSS *8 )); +if (restore) +load_fixmap_gdt (cpu); +} +#else +static inline void native_load_tr_desc (void ) +{ + asmvolatile ("ltr %w0" ::"q" (GDT_ENTRY_TSS *8 )); +} +#endif +static inline unsigned long native_store_tr (void ) {unsigned long tr;
arch/x86/include/asm/processor.h +1 -0
@@ -706,6 +706,7 @@ extern struct desc_ptr early_gdt_descr;extern void cpu_set_gdt (int );extern void switch_to_new_gdt (int ); +extern void load_direct_gdt (int );extern void load_fixmap_gdt (int );extern void load_percpu_segment (int );extern void cpu_init (void );
arch/x86/kernel/cpu/common.c +22 -6
@@ -444,13 +444,31 @@ void load_percpu_segment(int cpu)load_stack_canary_segment (); } +/* On 64-bit the GDT remapping is read-only */ +#ifdef CONFIG_X86_64 +#define PAGE_FIXMAP_GDT PAGE_KERNEL_RO +#else +#define PAGE_FIXMAP_GDT PAGE_KERNEL +#endif +/* Setup the fixmap mapping only once per-processor */ static inline void setup_fixmap_gdt (int cpu) {__set_fixmap (get_cpu_gdt_ro_index (cpu), -__pa (get_cpu_gdt_rw (cpu)),PAGE_KERNEL ); +__pa (get_cpu_gdt_rw (cpu)),PAGE_FIXMAP_GDT ); } +/* Load the original GDT from the per-cpu structure */ +void load_direct_gdt (int cpu) +{ +struct desc_ptr gdt_descr; + + gdt_descr.address = (long )get_cpu_gdt_rw (cpu); + gdt_descr.size =GDT_SIZE -1 ; +load_gdt (&gdt_descr); +} +EXPORT_SYMBOL_GPL (load_direct_gdt); +/* Load a fixmap remapping of the per-cpu GDT */ void load_fixmap_gdt (int cpu) {
@@ -460,6 +478,7 @@ void load_fixmap_gdt(int cpu) gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr); } +EXPORT_SYMBOL_GPL (load_fixmap_gdt);/* * Current gdt points %fs at the "master" per-cpu area: after this,
@@ -467,11 +486,8 @@ void load_fixmap_gdt(int cpu)*/ void switch_to_new_gdt (int cpu) { -struct desc_ptr gdt_descr; - - gdt_descr.address = (long )get_cpu_gdt_rw (cpu); - gdt_descr.size =GDT_SIZE -1 ; -load_gdt (&gdt_descr); +/* Load the original GDT */ +load_direct_gdt (cpu);/* Reload the per-cpu base */ load_percpu_segment (cpu); }
arch/x86/kvm/svm.c +1 -3
@@ -741,7 +741,6 @@ static int svm_hardware_enable(void)struct svm_cpu_data *sd;uint64_t efer; -struct desc_ptr gdt_descr;struct desc_struct *gdt;int me =raw_smp_processor_id ();
@@ -763,8 +762,7 @@ static int svm_hardware_enable(void) sd->max_asid =cpuid_ebx (SVM_CPUID_FUNC ) -1 ; sd->next_asid = sd->max_asid +1 ; -native_store_gdt (&gdt_descr); - gdt = (struct desc_struct *)gdt_descr.address; + gdt =get_current_gdt_rw (); sd->tss_desc = (struct kvm_ldttss_desc *)(gdt +GDT_ENTRY_TSS );wrmsrl (MSR_EFER , efer |EFER_SVME );
arch/x86/kvm/vmx.c +5 -10
@@ -935,7 +935,6 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);* when a CPU is brought down, and we need to VMCLEAR all VMCSs loaded on it. */ static DEFINE_PER_CPU(struct list_head, loaded_vmcss_on_cpu); -static DEFINE_PER_CPU(struct desc_ptr, host_gdt);/* * We maintian a per-CPU linked-list of vCPU, so in wakeup_handler() we
@@ -1997,10 +1996,9 @@ static void reload_tss(void)/* * VT restores TR but not its size. Useless. */ -struct desc_ptr *gdt =this_cpu_ptr (&host_gdt);struct desc_struct *descs; - descs = (void *)gdt->address; + descs =get_current_gdt_rw (); descs[GDT_ENTRY_TSS ].type =9 ;/* available TSS */ load_TR_desc (); }
@@ -2061,7 +2059,6 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)static unsigned long segment_base (u16 selector) { -struct desc_ptr *gdt =this_cpu_ptr (&host_gdt);struct desc_struct *d;unsigned long table_base;unsigned long v;
@@ -2069,7 +2066,7 @@ static unsigned long segment_base(u16 selector)if (!(selector & ~3 ))return 0 ; - table_base = gdt->address; + table_base =get_current_gdt_rw_vaddr ();if (selector &4 ) {/* from ldt */ u16 ldt_selector =kvm_read_ldt ();
@@ -2185,7 +2182,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)#endif if (vmx->host_state.msr_host_bndcfgs)wrmsrl (MSR_IA32_BNDCFGS , vmx->host_state.msr_host_bndcfgs); -load_gdt (this_cpu_ptr (&host_gdt)); +load_fixmap_gdt (raw_smp_processor_id ()); }static void vmx_load_host_state (struct vcpu_vmx *vmx)
@@ -2287,7 +2284,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) }if (!already_loaded) { -struct desc_ptr *gdt =this_cpu_ptr (&host_gdt); +unsigned long gdt =get_current_gdt_rw_vaddr ();unsigned long sysenter_esp;kvm_make_request (KVM_REQ_TLB_FLUSH , vcpu);
@@ -2297,7 +2294,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)* processors. */ vmcs_writel (HOST_TR_BASE ,kvm_read_tr_base ());/* 22.2.4 */ -vmcs_writel (HOST_GDTR_BASE , gdt->address);/* 22.2.4 */ +vmcs_writel (HOST_GDTR_BASE , gdt);/* 22.2.4 */ rdmsrl (MSR_IA32_SYSENTER_ESP , sysenter_esp);vmcs_writel (HOST_IA32_SYSENTER_ESP , sysenter_esp);/* 22.2.3 */
@@ -3523,8 +3520,6 @@ static int hardware_enable(void)ept_sync_global (); } -native_store_gdt (this_cpu_ptr (&host_gdt)); -return 0 ; }
Signature · 1 line
2.11.0.483.g087da7b7c-goog
PATCH v3 3/4 x86: Make the GDT remapping read-only on 64-bit
In reply to Thomas GarnierThis patch makes the GDT remapped pages read-only to prevent corruption. This change is done only on 64-bit.
The native_load_tr_desc function was adapted to correctly handle a read-only GDT. The LTR instruction always writes to the GDT TSS entry. This generates a page fault if the GDT is read-only. This change checks if the current GDT is a remap and swap GDTs as needed. This function was tested by booting multiple machines and checking hibernation works properly.
KVM SVM and VMX were adapted to use the writeable GDT. On VMX, the per-cpu variable was removed for functions to fetch the original GDT. Instead of reloading the previous GDT, VMX will reload the fixmap GDT as expected. For testing, VMs were started and restored on multiple configurations.
---
Based on next-20170213
--- arch/x86/include/asm/desc.h | 51 ++++++++++++++++++++++++++++++++++++---- arch/x86/include/asm/processor.h | 1 + arch/x86/kernel/cpu/common.c | 28 +++++++++++++++++----- arch/x86/kvm/svm.c | 4 +--- arch/x86/kvm/vmx.c | 15 ++++-------- 5 files changed, 75 insertions(+), 24 deletions(-)
arch/x86/include/asm/desc.h +46 -5
@@ -57,6 +57,17 @@ static inline unsigned long get_cpu_gdt_rw_vaddr(unsigned int cpu)return (unsigned long )get_cpu_gdt_rw (cpu); } +/* Provide the current original GDT */ +static inline struct desc_struct *get_current_gdt_rw (void ) +{ +return this_cpu_ptr (&gdt_page)->gdt; +} + +static inline unsigned long get_current_gdt_rw_vaddr (void ) +{ +return (unsigned long )get_current_gdt_rw (); +} +/* Get the fixmap index for a specific processor */ static inline unsigned int get_cpu_gdt_ro_index (int cpu) {
@@ -233,11 +244,6 @@ static inline void native_set_ldt(const void *addr, unsigned int entries) } } -static inline void native_load_tr_desc (void ) -{ - asmvolatile ("ltr %w0" ::"q" (GDT_ENTRY_TSS *8 )); -} -static inline void native_load_gdt (const struct desc_ptr *dtr) { asmvolatile ("lgdt %0" ::"m" (*dtr));
@@ -258,6 +264,41 @@ static inline void native_store_idt(struct desc_ptr *dtr) asmvolatile ("sidt %0" :"=m" (*dtr)); } +/* +* The LTR instruction marks the TSS GDT entry as busy. On 64-bit, the GDT is +* a read-only remapping. To prevent a page fault, the GDT is switched to the +* original writeable version when needed. +*/ +#ifdef CONFIG_X86_64 +static inline void native_load_tr_desc (void ) +{ +struct desc_ptr gdt; +int cpu =raw_smp_processor_id (); +bool restore =0 ; +struct desc_struct *fixmap_gdt; + +native_store_gdt (&gdt); + fixmap_gdt =get_cpu_gdt_ro (cpu); + +/* +* If the current GDT is the read-only fixmap, swap to the original +* writeable version. Swap back at the end. +*/ +if (gdt.address == (unsigned long )fixmap_gdt) { +load_direct_gdt (cpu); + restore =1 ; + } + asmvolatile ("ltr %w0" ::"q" (GDT_ENTRY_TSS *8 )); +if (restore) +load_fixmap_gdt (cpu); +} +#else +static inline void native_load_tr_desc (void ) +{ + asmvolatile ("ltr %w0" ::"q" (GDT_ENTRY_TSS *8 )); +} +#endif +static inline unsigned long native_store_tr (void ) {unsigned long tr;
arch/x86/include/asm/processor.h +1 -0
@@ -706,6 +706,7 @@ extern struct desc_ptr early_gdt_descr;extern void cpu_set_gdt (int );extern void switch_to_new_gdt (int ); +extern void load_direct_gdt (int );extern void load_fixmap_gdt (int );extern void load_percpu_segment (int );extern void cpu_init (void );
arch/x86/kernel/cpu/common.c +22 -6
@@ -444,13 +444,31 @@ void load_percpu_segment(int cpu)load_stack_canary_segment (); } +/* On 64-bit the GDT remapping is read-only */ +#ifdef CONFIG_X86_64 +#define PAGE_FIXMAP_GDT PAGE_KERNEL_RO +#else +#define PAGE_FIXMAP_GDT PAGE_KERNEL +#endif +/* Setup the fixmap mapping only once per-processor */ static inline void setup_fixmap_gdt (int cpu) {__set_fixmap (get_cpu_gdt_ro_index (cpu), -__pa (get_cpu_gdt_rw (cpu)),PAGE_KERNEL ); +__pa (get_cpu_gdt_rw (cpu)),PAGE_FIXMAP_GDT ); } +/* Load the original GDT from the per-cpu structure */ +void load_direct_gdt (int cpu) +{ +struct desc_ptr gdt_descr; + + gdt_descr.address = (long )get_cpu_gdt_rw (cpu); + gdt_descr.size =GDT_SIZE -1 ; +load_gdt (&gdt_descr); +} +EXPORT_SYMBOL_GPL (load_direct_gdt); +/* Load a fixmap remapping of the per-cpu GDT */ void load_fixmap_gdt (int cpu) {
@@ -460,6 +478,7 @@ void load_fixmap_gdt(int cpu) gdt_descr.size =GDT_SIZE -1 ;load_gdt (&gdt_descr); } +EXPORT_SYMBOL_GPL (load_fixmap_gdt);/* * Current gdt points %fs at the "master" per-cpu area: after this,
@@ -467,11 +486,8 @@ void load_fixmap_gdt(int cpu)*/ void switch_to_new_gdt (int cpu) { -struct desc_ptr gdt_descr; - - gdt_descr.address = (long )get_cpu_gdt_rw (cpu); - gdt_descr.size =GDT_SIZE -1 ; -load_gdt (&gdt_descr); +/* Load the original GDT */ +load_direct_gdt (cpu);/* Reload the per-cpu base */ load_percpu_segment (cpu); }
arch/x86/kvm/svm.c +1 -3
@@ -741,7 +741,6 @@ static int svm_hardware_enable(void)struct svm_cpu_data *sd;uint64_t efer; -struct desc_ptr gdt_descr;struct desc_struct *gdt;int me =raw_smp_processor_id ();
@@ -763,8 +762,7 @@ static int svm_hardware_enable(void) sd->max_asid =cpuid_ebx (SVM_CPUID_FUNC ) -1 ; sd->next_asid = sd->max_asid +1 ; -native_store_gdt (&gdt_descr); - gdt = (struct desc_struct *)gdt_descr.address; + gdt =get_current_gdt_rw (); sd->tss_desc = (struct kvm_ldttss_desc *)(gdt +GDT_ENTRY_TSS );wrmsrl (MSR_EFER , efer |EFER_SVME );
arch/x86/kvm/vmx.c +5 -10
@@ -935,7 +935,6 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);* when a CPU is brought down, and we need to VMCLEAR all VMCSs loaded on it. */ static DEFINE_PER_CPU(struct list_head, loaded_vmcss_on_cpu); -static DEFINE_PER_CPU(struct desc_ptr, host_gdt);/* * We maintian a per-CPU linked-list of vCPU, so in wakeup_handler() we
@@ -1997,10 +1996,9 @@ static void reload_tss(void)/* * VT restores TR but not its size. Useless. */ -struct desc_ptr *gdt =this_cpu_ptr (&host_gdt);struct desc_struct *descs; - descs = (void *)gdt->address; + descs =get_current_gdt_rw (); descs[GDT_ENTRY_TSS ].type =9 ;/* available TSS */ load_TR_desc (); }
@@ -2061,7 +2059,6 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)static unsigned long segment_base (u16 selector) { -struct desc_ptr *gdt =this_cpu_ptr (&host_gdt);struct desc_struct *d;unsigned long table_base;unsigned long v;
@@ -2069,7 +2066,7 @@ static unsigned long segment_base(u16 selector)if (!(selector & ~3 ))return 0 ; - table_base = gdt->address; + table_base =get_current_gdt_rw_vaddr ();if (selector &4 ) {/* from ldt */ u16 ldt_selector =kvm_read_ldt ();
@@ -2185,7 +2182,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)#endif if (vmx->host_state.msr_host_bndcfgs)wrmsrl (MSR_IA32_BNDCFGS , vmx->host_state.msr_host_bndcfgs); -load_gdt (this_cpu_ptr (&host_gdt)); +load_fixmap_gdt (raw_smp_processor_id ()); }static void vmx_load_host_state (struct vcpu_vmx *vmx)
@@ -2287,7 +2284,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) }if (!already_loaded) { -struct desc_ptr *gdt =this_cpu_ptr (&host_gdt); +unsigned long gdt =get_current_gdt_rw_vaddr ();unsigned long sysenter_esp;kvm_make_request (KVM_REQ_TLB_FLUSH , vcpu);
@@ -2297,7 +2294,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)* processors. */ vmcs_writel (HOST_TR_BASE ,kvm_read_tr_base ());/* 22.2.4 */ -vmcs_writel (HOST_GDTR_BASE , gdt->address);/* 22.2.4 */ +vmcs_writel (HOST_GDTR_BASE , gdt);/* 22.2.4 */ rdmsrl (MSR_IA32_SYSENTER_ESP , sysenter_esp);vmcs_writel (HOST_IA32_SYSENTER_ESP , sysenter_esp);/* 22.2.3 */
@@ -3523,8 +3520,6 @@ static int hardware_enable(void)ept_sync_global (); } -native_store_gdt (this_cpu_ptr (&host_gdt)); -return 0 ; }
Signature · 7 lines
2.11.0.483.g087da7b7c-goog _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
PATCH v3 4/4 KVM: VMX: Simplify segment_base
In reply to Thomas GarnierThe KVM segment_base function is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.
---
Based on next-20170213
--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
arch/x86/kvm/vmx.c +18 -8
@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; }
Signature · 1 line
2.11.0.483.g087da7b7c-goog
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 2 lines · Thomas Garnier
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.
It could pay to put this first in the series, but last is probably fine, too.
Quoted 13 lines
Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +0
-0
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2063
Quoted 2 lines
arch/x86/kvm/vmx.c +0
-0@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;
This should go away IMO. It should be struct desc_struct *table;
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2079
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ table_base =get_current_gdt_rw_vaddr ();
Then this can go away, too, and you can stop having the silly get_current_gdt_rw_vaddr() function at all.
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2082
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ d = (struct desc_struct *)table_base + (selector >>3 );
And this cast goes away too.
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 6 lines · Andy Lutomirski
Quoted 2 lines · Thomas Garnier
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.It could pay to put this first in the series, but last is probably fine, too.
:)
Quoted 18 lines
Quoted 13 lines
Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +0
-0arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2063
Quoted 2 lines
arch/x86/kvm/vmx.c +0
-0@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;This should go away IMO. It should be struct
desc_struct*table;
Quoted 8 lines
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2079
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ table_base =get_current_gdt_rw_vaddr ();Then this can go away, too, and you can stop having the silly
get_current_gdt_rw_vaddr()function at all.arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2082
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ d = (struct desc_struct *)table_base + (selector >>3 );And this cast goes away too.
No problem.
Signature · 1 line
Thomas
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Andy LutomirskiQuoted 6 lines · Andy Lutomirski
Quoted 2 lines · Thomas Garnier
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.It could pay to put this first in the series, but last is probably fine, too.
:)
Quoted 18 lines
Quoted 13 lines
Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +0
-0arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2063
Quoted 2 lines
arch/x86/kvm/vmx.c +0
-0@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;This should go away IMO. It should be struct
desc_struct*table;
Quoted 8 lines
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2079
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ table_base =get_current_gdt_rw_vaddr ();Then this can go away, too, and you can stop having the silly
get_current_gdt_rw_vaddr()function at all.arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2082
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ d = (struct desc_struct *)table_base + (selector >>3 );And this cast goes away too.
No problem.
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierQuoted 2 lines · Thomas Garnier
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.
It could pay to put this first in the series, but last is probably fine, too.
Quoted 13 lines
Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +0
-0
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2063
Quoted 2 lines
arch/x86/kvm/vmx.c +0
-0@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;
This should go away IMO. It should be struct desc_struct *table;
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2079
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ table_base =get_current_gdt_rw_vaddr ();
Then this can go away, too, and you can stop having the silly get_current_gdt_rw_vaddr() function at all.
arch/x86/kvm/vmx.c static unsigned long segment_base(u16 selector) · line 2082
Quoted 1 line
arch/x86/kvm/vmx.c +1
-0+ d = (struct desc_struct *)table_base + (selector >>3 );
And this cast goes away too.
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierCan we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (d->s == 0 && d->type != 0)?
Quoted 61 lines · Thomas Garnier
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +18
-9@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; } --2.11.0.483.g087da7b7c-goog
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?
We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
Quoted 64 lines · Thomas Garnier
Quoted 61 lines
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +18
-9@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; } --2.11.0.483.g087da7b7c-goog
Signature · 1 line
Thomas
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).
All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Quoted 71 lines
Quoted 57 lines · Thomas Garnier
Quoted 53 lines
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +16
-8@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3;Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/vmx.c +2
-1+ v |= (u64)high32 << 32; + }#endif return v; } --2.11.0.483.g087da7b7c-goog
--
Thomas
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 14 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
Quoted 9 lines
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Ok, then I will test an updated version next week.
Quoted 71 lines
Quoted 71 lines
Quoted 57 lines · Thomas Garnier
Quoted 53 lines
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +16
-8@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3;Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/vmx.c +2
-1+ v |= (u64)high32 << 32; + }#endif return v; } --2.11.0.483.g087da7b7c-goog
--
Thomas
Signature · 1 line
Thomas
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 20 lines · Thomas Garnier
Quoted 19 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).
Quoted 7 lines
Quoted 4 lines
All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Ok, then I will test an updated version next week.
I'm going to send out some preliminary patches that just get rid of this problem entirely.
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 26 lines · Andy Lutomirski
Quoted 25 lines · Thomas Garnier
Quoted 23 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Quoted 5 lines
Quoted 2 lines
Ok, then I will test an updated version next week.
I'm going to send out some preliminary patches that just get rid of this problem entirely.
Okay, I guess I will have to wait for it to be integrated to linux-next then. Or would you rather to it after this patch set is added?
Signature · 1 line
Thomas
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 30 lines · Thomas Garnier
Quoted 29 lines · Andy Lutomirski
Quoted 27 lines · Thomas Garnier
Quoted 14 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
Quoted 9 lines
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Ok, then I will test an updated version next week.
Quoted 7 lines
Quoted 2 lines
I'm going to send out some preliminary patches that just get rid of this problem entirely.
Okay, I guess I will have to wait for it to be integrated to linux-next then. Or would you rather to it after this patch set is added?
Read your summary for the patchset of KVM cleanup, I will wait for it to reach linux-next to rebase and send the new iteration.
Thanks for working on the clean-up.
Quoted 2 lines
--
Thomas
Signature · 1 line
Thomas
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 6 lines · Thomas Garnier
Quoted 3 lines
Okay, I guess I will have to wait for it to be integrated to linux-next then. Or would you rather to it after this patch set is added?
Read your summary for the patchset of KVM cleanup, I will wait for it to reach linux-next to rebase and send the new iteration.
Note that to be able to apply your readonly-GDT series to the x86 tree I'll need a stable SHA1 to base it on.
Paolo, how stable, non-rebasing are the KVM tree commits? Once Andy's patches hit the KVM tree I could pull from you and order it so that I'd send it to Linus only after you sent your bits upstream. That would save us 3 months of patch propagation latency.
Or should we keep Andy's KVM patches together with the GDT patches? Either workflow works for me - it's your call as these are predominantly KVM changes.
Thanks,
Ingo
Paolo Bonzini
maintainer[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 2 lines
Paolo, how stable, non-rebasing are the KVM tree commits?
Whatever ends in linux-next is stable. I have a separate rebasing branch, but it's not part of linux-next by design.
Quoted 3 lines
Or should we keep Andy's KVM patches together with the GDT patches? Either workflow works for me - it's your call as these are predominantly KVM changes.
I'll delay my pull request to Linus a couple days so that I can test Andy's 6 patches. Then you can just base your branch on Linus's tree.
Paolo
[kernel-hardening] Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
Quoted 4 lines · Paolo Bonzini
Quoted 1 line
Paolo, how stable, non-rebasing are the KVM tree commits?
Whatever ends in linux-next is stable. I have a separate rebasing branch, but it's not part of linux-next by design.
Ok, that's nice!
Quoted 5 lines
Quoted 2 lines
Or should we keep Andy's KVM patches together with the GDT patches? Either workflow works for me - it's your call as these are predominantly KVM changes.
I'll delay my pull request to Linus a couple days so that I can test Andy's 6 patches. Then you can just base your branch on Linus's tree.
Fantastic, thank you!
Ingo
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Paolo BonziniQuoted 4 lines · Paolo Bonzini
Quoted 1 line
Paolo, how stable, non-rebasing are the KVM tree commits?
Whatever ends in linux-next is stable. I have a separate rebasing branch, but it's not part of linux-next by design.
Ok, that's nice!
Quoted 5 lines
Quoted 2 lines
Or should we keep Andy's KVM patches together with the GDT patches? Either workflow works for me - it's your call as these are predominantly KVM changes.
I'll delay my pull request to Linus a couple days so that I can test Andy's 6 patches. Then you can just base your branch on Linus's tree.
Fantastic, thank you!
Ingo
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Paolo Bonzini
maintainerRe: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Ingo MolnarQuoted 2 lines
Paolo, how stable, non-rebasing are the KVM tree commits?
Whatever ends in linux-next is stable. I have a separate rebasing branch, but it's not part of linux-next by design.
Quoted 3 lines
Or should we keep Andy's KVM patches together with the GDT patches? Either workflow works for me - it's your call as these are predominantly KVM changes.
I'll delay my pull request to Linus a couple days so that I can test Andy's 6 patches. Then you can just base your branch on Linus's tree.
Paolo
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierQuoted 6 lines · Thomas Garnier
Quoted 3 lines
Okay, I guess I will have to wait for it to be integrated to linux-next then. Or would you rather to it after this patch set is added?
Read your summary for the patchset of KVM cleanup, I will wait for it to reach linux-next to rebase and send the new iteration.
Note that to be able to apply your readonly-GDT series to the x86 tree I'll need a stable SHA1 to base it on.
Paolo, how stable, non-rebasing are the KVM tree commits? Once Andy's patches hit the KVM tree I could pull from you and order it so that I'd send it to Linus only after you sent your bits upstream. That would save us 3 months of patch propagation latency.
Or should we keep Andy's KVM patches together with the GDT patches? Either workflow works for me - it's your call as these are predominantly KVM changes.
Thanks,
Ingo
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierQuoted 30 lines · Thomas Garnier
Quoted 29 lines · Andy Lutomirski
Quoted 27 lines · Thomas Garnier
Quoted 14 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
Quoted 9 lines
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Ok, then I will test an updated version next week.
Quoted 7 lines
Quoted 2 lines
I'm going to send out some preliminary patches that just get rid of this problem entirely.
Okay, I guess I will have to wait for it to be integrated to linux-next then. Or would you rather to it after this patch set is added?
Read your summary for the patchset of KVM cleanup, I will wait for it to reach linux-next to rebase and send the new iteration.
Thanks for working on the clean-up.
Quoted 2 lines
--
Thomas
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Andy LutomirskiQuoted 26 lines · Andy Lutomirski
Quoted 25 lines · Thomas Garnier
Quoted 23 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Quoted 5 lines
Quoted 2 lines
Ok, then I will test an updated version next week.
I'm going to send out some preliminary patches that just get rid of this problem entirely.
Okay, I guess I will have to wait for it to be integrated to linux-next then. Or would you rather to it after this patch set is added?
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierQuoted 20 lines · Thomas Garnier
Quoted 19 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).
Quoted 7 lines
Quoted 4 lines
All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Ok, then I will test an updated version next week.
I'm going to send out some preliminary patches that just get rid of this problem entirely.
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Jim MattsonQuoted 14 lines · Jim Mattson
Quoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
Quoted 9 lines
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Ok, then I will test an updated version next week.
Quoted 71 lines
Quoted 71 lines
Quoted 57 lines · Thomas Garnier
Quoted 53 lines
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +16
-8@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3;Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/vmx.c +2
-1+ v |= (u64)high32 << 32; + }#endif return v; } --2.11.0.483.g087da7b7c-goog
--
Thomas
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierQuoted 10 lines · Thomas Garnier
Quoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
According to volume 3 of the SDM, section 3.5.2:
The following system descriptors expand to 16 bytes:
— Call gate descriptors (see Section 5.8.3.1, “IA-32e Mode Call Gates”) — IDT gate descriptors (see Section 6.14.1, “64-Bit Mode IDT”)
— LDT and TSS descriptors (see Section 7.2.3, “TSS Descriptor in 64-bit mode”).
All legal system descriptor types (except for 0: Upper 8 bytes of an 16-byte descriptor) should get the high 32 bits of the base address from the next 8-byte descriptor.
Quoted 63 lines
Quoted 63 lines · Thomas Garnier
Quoted 59 lines
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +18
-9@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; } --
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
2.11.0.483.g087da7b7c-goog
--
Thomas
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Jim MattsonQuoted 4 lines · Jim Mattson
Can we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (
d->s== 0 &&d->type!= 0)?
We can use the readonly GDT but I think doesn't matter one or the other here. We have to check specific types for LDT or TSS, other values describe other entries (cf Intel volume 3, 3.5) (for example 14 & 15 on 64-bits are for trap & interrupt gates).
Quoted 64 lines · Thomas Garnier
Quoted 61 lines
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +18
-9@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; } --2.11.0.483.g087da7b7c-goog
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v3 4/4] KVM: VMX: Simplify segment_base
In reply to Thomas GarnierCan we use the read-only GDT here? When expanding the virtual address for 64-bit system descriptors, isn't it sufficient to check (d->s == 0 && d->type != 0)?
Quoted 59 lines · Thomas Garnier
The KVM
segment_basefunction is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)arch/x86/kvm/vmx.c +18
-9@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; } --
Quoted 2 lines
2.11.0.483.g087da7b7c-goog
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
PATCH v3 4/4 KVM: VMX: Simplify segment_base
In reply to Thomas GarnierThe KVM segment_base function is confusing. This patch replaces integers with appropriate flags, simplify constructs and add comments.
---
Based on next-20170213
--- arch/x86/kvm/vmx.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
arch/x86/kvm/vmx.c +18 -8
@@ -2062,25 +2062,35 @@ static unsigned long segment_base(u16 selector)struct desc_struct *d;unsigned long table_base;unsigned long v; +u32 high32; -if (!(selector & ~3 )) +if (!(selector & ~SEGMENT_RPL_MASK ))return 0 ; - table_base =get_current_gdt_rw_vaddr (); - -if (selector &4 ) {/* from ldt */ +/* LDT selector */ +if ((selector &SEGMENT_TI_MASK ) ==SEGMENT_LDT ) {u16 ldt_selector =kvm_read_ldt (); -if (!(ldt_selector & ~3 )) +if (!(ldt_selector & ~SEGMENT_RPL_MASK ))return 0 ; table_base =segment_base (ldt_selector); + }else { + table_base =get_current_gdt_rw_vaddr (); } - d = (struct desc_struct *)(table_base + (selector & ~7 )); + + d = (struct desc_struct *)table_base + (selector >>3 ); v =get_desc_base (d);#ifdef CONFIG_X86_64 -if (d->s ==0 && (d->type ==2 || d->type ==9 || d->type ==11 )) - v |= ((unsigned long )((struct ldttss_desc64 *)d)->base3) <<32 ; +/* +* Extend the virtual address if we have a system descriptor entry for +* LDT or TSS (available or busy). +*/ +if (d->s ==0 && (d->type ==DESC_LDT || d->type ==DESC_TSS || + d->type ==11 /*Busy TSS */ )) { + high32 = ((struct ldttss_desc64 *)d)->base3; + v |= (u64 )high32 <<32 ; + }#endif return v; }
Signature · 7 lines
2.11.0.483.g087da7b7c-goog _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Quoted 25 lines · Thomas Garnier
This patch aligns
MODULES_ENDto the beginning of the Fixmap section. It optimizes the space available for both sections. The address is pre-computed based on the number of pages required by the Fixmap section.It will allow GDT remapping in the Fixmap section. The current
MODULES_ENDstatic address does not provide enough space for the kernel to support a large number of processors.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/include/asm/fixmap.h | 8 ++++++++ arch/x86/include/asm/pgtable_64_types.h | 3 --- arch/x86/kernel/module.c | 1 + arch/x86/mm/dump_pagetables.c | 1 + arch/x86/mm/kasan_init_64.c | 1 + 5 files changed, 11 insertions(+), 3 deletions(-)arch/x86/include/asm/fixmap.h +0
-0
arch/x86/include/asm/fixmap.h enum fixed_addresses { · line 140
Quoted 9 lines
arch/x86/include/asm/fixmap.h +6
-0@@ -132,6 +132,14 @@ enum fixed_addresses {extern void reserve_top_address (unsigned long reserve); +/* On 64-bit, the module sections ends with the start of the fixmap */ +#ifdef CONFIG_X86_64 +#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1) +#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#endif /* CONFIG_X86_64 */
JFYI: so there's another patchset which adds KERNEL_MAPPING_SIZE:
https://lkml.kernel.org/r/[email protected]
and makes it a 1G, i.e., the KASLR default. I guess the above will have to be KERNEL_MAPPING_SIZE then.
And why are you moving those to fixmap.h? What's wrong with including fixmap.h into pgtable_64_types.h so that you can get __end_of_fixed_addresses?
FWIW, I didn't even have to add any includes with my .config, i.e., that builds:
---
arch/x86/include/asm/pgtable_64_types.h +1 -1
@@ -67,7 +67,7 @@ typedef struct { pteval_t pte; } pte_t;#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1)#define MODULES_LEN (MODULES_END - MODULES_VADDR)#define ESPFIX_PGD_ENTRY _AC(-2, UL)#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT)
---
but I wouldn't be surprised if some strange configuration would need it.
arch/x86/include/asm/pgtable_64_types.h typedef struct { pteval_t pte; } pte_t; · line 70
Quoted 13 lines
arch/x86/include/asm/fixmap.h +0
-0#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)arch/x86/include/asm/pgtable_64_types.h +0
-2@@ -66,9 +66,6 @@ typedef struct { pteval_t pte; } pte_t;#define VMEMMAP_START __VMEMMAP_BASE#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) -#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL)
How much of an ABI breakage would that be? SeeDocumentation/x86/x86_64/mm.txt.
With my .config MODULES_END becomes 0xffffffffff1fe000 and it'll remain dynamic depending on .config. No idea how much in userspace relies on MODULES_END being static 0xffffffffff000000...
Hmm.
Signature · 5 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- Quoted 41 lines · Borislav Petkov
Quoted 25 lines · Thomas Garnier
This patch aligns
MODULES_ENDto the beginning of the Fixmap section. It optimizes the space available for both sections. The address is pre-computed based on the number of pages required by the Fixmap section.It will allow GDT remapping in the Fixmap section. The current
MODULES_ENDstatic address does not provide enough space for the kernel to support a large number of processors.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/include/asm/fixmap.h | 8 ++++++++ arch/x86/include/asm/pgtable_64_types.h | 3 --- arch/x86/kernel/module.c | 1 + arch/x86/mm/dump_pagetables.c | 1 + arch/x86/mm/kasan_init_64.c | 1 + 5 files changed, 11 insertions(+), 3 deletions(-)arch/x86/include/asm/fixmap.h +0
-0arch/x86/include/asm/fixmap.h enum fixed_addresses { · line 140
Quoted 9 lines
arch/x86/include/asm/fixmap.h +6
-0@@ -132,6 +132,14 @@ enum fixed_addresses {extern void reserve_top_address (unsigned long reserve); +/* On 64-bit, the module sections ends with the start of the fixmap */ +#ifdef CONFIG_X86_64 +#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1) +#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#endif /* CONFIG_X86_64 */ JFYI: so there's another patchset which adds
KERNEL_MAPPING_SIZE:
Quoted 9 lines
and makes it a 1G, i.e., the KASLR default. I guess the above will have to be
KERNEL_MAPPING_SIZEthen.And why are you moving those to
fixmap.h? What's wrong with includingfixmap.hintopgtable_64_types.hso that you can get__end_of_fixed_addresses?FWIW, I didn't even have to add any includes with my .config, i.e., that builds:
I tried to add fixmap.h and I thought I tried without too but maybe not, I will try to adapt it on v4.
Quoted 35 lines
---
arch/x86/include/asm/pgtable_64_types.h +1
-2@@ -67,7 +67,7 @@ typedef struct { pteval_t pte; } pte_t;#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1)#define MODULES_LEN (MODULES_END - MODULES_VADDR)#define ESPFIX_PGD_ENTRY _AC(-2, UL)#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT) ---but I wouldn't be surprised if some strange configuration would need it.
arch/x86/include/asm/pgtable_64_types.h typedef struct { pteval_t pte; } pte_t; · line 70
Quoted 13 lines
arch/x86/include/asm/fixmap.h +0
-0#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)arch/x86/include/asm/pgtable_64_types.h +0
-2@@ -66,9 +66,6 @@ typedef struct { pteval_t pte; } pte_t;#define VMEMMAP_START __VMEMMAP_BASE#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) -#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL)How much of an ABI breakage would that be? See
Documentation/x86/x86_64/mm.txt.
Quoted 6 lines
With my .config
MODULES_ENDbecomes0xffffffffff1fe000and it'll remain dynamic depending on .config. No idea how much in userspace relies onMODULES_ENDbeing static0xffffffffff000000...Hmm.
Why do you think they rely on it being static? The VSYSCALL address is not changed for example.
Quoted 6 lines
--
Regards/Gruss,
Boris.SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg) --
Thanks for the feedback.
Signature · 1 line
Thomas
Quoted 2 lines · Thomas Garnier
Why do you think they rely on it being static? The VSYSCALL address is not changed for example.
I don't know, that's why I'm asking first. Userspace is known to pick different aspects of the kernel and deciding to use them for whatever. And once it relies on that, there's no changing it.
Signature · 5 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- Quoted 7 lines · Borislav Petkov
Quoted 2 lines · Thomas Garnier
Why do you think they rely on it being static? The VSYSCALL address is not changed for example.
I don't know, that's why I'm asking first. Userspace is known to pick different aspects of the kernel and deciding to use them for whatever. And once it relies on that, there's no changing it.
Ok, so we should be fine here because those addresses are internal to the kernel, I'm being told, so anything using them will break and gets to keep the pieces even.
Signature · 5 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- Quoted 7 lines · Borislav Petkov
Quoted 2 lines · Thomas Garnier
Why do you think they rely on it being static? The VSYSCALL address is not changed for example.
I don't know, that's why I'm asking first. Userspace is known to pick different aspects of the kernel and deciding to use them for whatever. And once it relies on that, there's no changing it.
Ok, so we should be fine here because those addresses are internal to the kernel, I'm being told, so anything using them will break and gets to keep the pieces even.
Signature · 10 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-develQuoted 2 lines · Thomas Garnier
Why do you think they rely on it being static? The VSYSCALL address is not changed for example.
I don't know, that's why I'm asking first. Userspace is known to pick different aspects of the kernel and deciding to use them for whatever. And once it relies on that, there's no changing it.
Signature · 10 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-develQuoted 41 lines · Borislav Petkov
Quoted 25 lines · Thomas Garnier
This patch aligns
MODULES_ENDto the beginning of the Fixmap section. It optimizes the space available for both sections. The address is pre-computed based on the number of pages required by the Fixmap section.It will allow GDT remapping in the Fixmap section. The current
MODULES_ENDstatic address does not provide enough space for the kernel to support a large number of processors.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/include/asm/fixmap.h | 8 ++++++++ arch/x86/include/asm/pgtable_64_types.h | 3 --- arch/x86/kernel/module.c | 1 + arch/x86/mm/dump_pagetables.c | 1 + arch/x86/mm/kasan_init_64.c | 1 + 5 files changed, 11 insertions(+), 3 deletions(-)arch/x86/include/asm/fixmap.h +0
-0arch/x86/include/asm/fixmap.h enum fixed_addresses { · line 140
Quoted 9 lines
arch/x86/include/asm/fixmap.h +6
-0@@ -132,6 +132,14 @@ enum fixed_addresses {extern void reserve_top_address (unsigned long reserve); +/* On 64-bit, the module sections ends with the start of the fixmap */ +#ifdef CONFIG_X86_64 +#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1) +#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#endif /* CONFIG_X86_64 */ JFYI: so there's another patchset which adds
KERNEL_MAPPING_SIZE:
Quoted 9 lines
and makes it a 1G, i.e., the KASLR default. I guess the above will have to be
KERNEL_MAPPING_SIZEthen.And why are you moving those to
fixmap.h? What's wrong with includingfixmap.hintopgtable_64_types.hso that you can get__end_of_fixed_addresses?FWIW, I didn't even have to add any includes with my .config, i.e., that builds:
I tried to add fixmap.h and I thought I tried without too but maybe not, I will try to adapt it on v4.
Quoted 35 lines
---
arch/x86/include/asm/pgtable_64_types.h +1
-2@@ -67,7 +67,7 @@ typedef struct { pteval_t pte; } pte_t;#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1)#define MODULES_LEN (MODULES_END - MODULES_VADDR)#define ESPFIX_PGD_ENTRY _AC(-2, UL)#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT) ---but I wouldn't be surprised if some strange configuration would need it.
arch/x86/include/asm/pgtable_64_types.h typedef struct { pteval_t pte; } pte_t; · line 70
Quoted 13 lines
arch/x86/include/asm/fixmap.h +0
-0#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)arch/x86/include/asm/pgtable_64_types.h +0
-2@@ -66,9 +66,6 @@ typedef struct { pteval_t pte; } pte_t;#define VMEMMAP_START __VMEMMAP_BASE#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) -#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL)How much of an ABI breakage would that be? See
Documentation/x86/x86_64/mm.txt.
Quoted 6 lines
With my .config
MODULES_ENDbecomes0xffffffffff1fe000and it'll remain dynamic depending on .config. No idea how much in userspace relies onMODULES_ENDbeing static0xffffffffff000000...Hmm.
Why do you think they rely on it being static? The VSYSCALL address is not changed for example.
Quoted 6 lines
--
Regards/Gruss,
Boris.SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg) --
Thanks for the feedback.
Signature · 6 lines
Thomas _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Quoted 25 lines · Thomas Garnier
This patch aligns
MODULES_ENDto the beginning of the Fixmap section. It optimizes the space available for both sections. The address is pre-computed based on the number of pages required by the Fixmap section.It will allow GDT remapping in the Fixmap section. The current
MODULES_ENDstatic address does not provide enough space for the kernel to support a large number of processors.Signed-off-by Thomas Garnier <[email protected]>---
Based on next-20170213--- arch/x86/include/asm/fixmap.h | 8 ++++++++ arch/x86/include/asm/pgtable_64_types.h | 3 --- arch/x86/kernel/module.c | 1 + arch/x86/mm/dump_pagetables.c | 1 + arch/x86/mm/kasan_init_64.c | 1 + 5 files changed, 11 insertions(+), 3 deletions(-)arch/x86/include/asm/fixmap.h +0
-0
arch/x86/include/asm/fixmap.h enum fixed_addresses { · line 140
Quoted 9 lines
arch/x86/include/asm/fixmap.h +6
-0@@ -132,6 +132,14 @@ enum fixed_addresses {extern void reserve_top_address (unsigned long reserve); +/* On 64-bit, the module sections ends with the start of the fixmap */ +#ifdef CONFIG_X86_64 +#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1) +#define MODULES_LEN (MODULES_END - MODULES_VADDR) +#endif /* CONFIG_X86_64 */
JFYI: so there's another patchset which adds KERNEL_MAPPING_SIZE:
https://lkml.kernel.org/r/[email protected]
and makes it a 1G, i.e., the KASLR default. I guess the above will have to be KERNEL_MAPPING_SIZE then.
And why are you moving those to fixmap.h? What's wrong with including fixmap.h into pgtable_64_types.h so that you can get __end_of_fixed_addresses?
FWIW, I didn't even have to add any includes with my .config, i.e., that builds:
---
arch/x86/include/asm/pgtable_64_types.h +1 -1
@@ -67,7 +67,7 @@ typedef struct { pteval_t pte; } pte_t;#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL) +#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1)#define MODULES_LEN (MODULES_END - MODULES_VADDR)#define ESPFIX_PGD_ENTRY _AC(-2, UL)#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT)
---
but I wouldn't be surprised if some strange configuration would need it.
arch/x86/include/asm/pgtable_64_types.h typedef struct { pteval_t pte; } pte_t; · line 70
Quoted 13 lines
arch/x86/include/asm/fixmap.h +0
-0#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)arch/x86/include/asm/pgtable_64_types.h +0
-2@@ -66,9 +66,6 @@ typedef struct { pteval_t pte; } pte_t;#define VMEMMAP_START __VMEMMAP_BASE#endif /* CONFIG_RANDOMIZE_MEMORY */ #define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL)) -#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) -#define MODULES_END _AC(0xffffffffff000000, UL)
How much of an ABI breakage would that be? SeeDocumentation/x86/x86_64/mm.txt.
With my .config MODULES_END becomes 0xffffffffff1fe000 and it'll remain dynamic depending on .config. No idea how much in userspace relies on MODULES_END being static 0xffffffffff000000...
Hmm.
Signature · 10 lines
Regards/Gruss,
Boris.
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel