From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752223AbdKZNsu (ORCPT ); Sun, 26 Nov 2017 08:48:50 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:40413 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752145AbdKZNss (ORCPT ); Sun, 26 Nov 2017 08:48:48 -0500 X-Google-Smtp-Source: AGs4zMYmlP0PtuFvh17Es6tsHQTG51me8kOCaZaLU3UZXYW2vjMJR5HY8VdM2GWJR8HgBJxLswHiZw== Date: Sun, 26 Nov 2017 14:48:44 +0100 From: Ingo Molnar To: Dave Hansen Cc: Andy Lutomirski , X86 ML , Borislav Petkov , "linux-kernel@vger.kernel.org" , Brian Gerst , Linus Torvalds Subject: [PATCH v2] x86/entry: Fix assumptions that the HW TSS is at the beginning of cpu_tss Message-ID: <20171126134844.o4nz6kuuzsflxrw6@gmail.com> References: <03fb20a8639aeecfeda3ba18a520ce646267eb9a.1510371795.git.luto@kernel.org> <2fdf9cf9-ec48-e63f-2ec8-44160c206c9a@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <2fdf9cf9-ec48-e63f-2ec8-44160c206c9a@intel.com> User-Agent: NeoMutt/20170609 (1.8.3) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org * Dave Hansen wrote: > On 11/10/2017 08:05 PM, Andy Lutomirski wrote: > > -struct tss_struct doublefault_tss __cacheline_aligned = { > > - .x86_tss = { > > - .sp0 = STACK_START, > > - .ss0 = __KERNEL_DS, > > - .ldt = 0, > ... > > +struct x86_hw_tss doublefault_tss __cacheline_aligned = { > > + .sp0 = STACK_START, > > + .ss0 = __KERNEL_DS, > > + .ldt = 0, > > + .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, > > FWIW, I really like the trend of renaming the hardware structures in > such a way that it's clear that they *are* hardware structures. > > It might also be nice to reference the relevant SDM sections on the > topic, or even to include a comment along the lines of how it get used. > This chunk from the SDM is particularly relevant: > > "The TSS holds information important to 64-bit mode and that is not > directly related to the task-switch mechanism." That makes sense - I've updated this patch with the following description added to struct x86_hw_tss: +/* + * Note that while the legacy 'TSS' name comes from 'Task State Segment', + * on modern x86 CPUs the TSS holds information important to 64-bit mode + * unrelated to the task-switch mechanism: + */ I have also added your Reviewed-by tag. Updated patch below. Thanks, Ingo =====================> Subject: x86/entry: Fix assumptions that the HW TSS is at the beginning of cpu_tss From: Andy Lutomirski Date: Thu, 23 Nov 2017 20:32:52 -0800 A future patch will move SYSENTER_stack to the beginning of cpu_tss to help detect overflow. Before this can happen, fix several code paths that hardcode assumptions about the old layout. Signed-off-by: Andy Lutomirski Signed-off-by: Thomas Gleixner [ Updated the 'struct tss_struct' comments, as suggested by Dave Hansen. ] Reviewed-by: Borislav Petkov Reviewed-by: Dave Hansen Reviewed-by: Thomas Gleixner Cc: Borislav Petkov Cc: Brian Gerst Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Link: https://lkml.kernel.org/r/d40a2c5ae4539d64090849a374f3169ec492f4e2.1511497875.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/include/asm/desc.h | 2 +- arch/x86/include/asm/processor.h | 9 +++++++-- arch/x86/kernel/cpu/common.c | 8 ++++---- arch/x86/kernel/doublefault.c | 32 +++++++++++++++----------------- arch/x86/power/cpu.c | 13 +++++++------ 5 files changed, 34 insertions(+), 30 deletions(-) Index: tip/arch/x86/include/asm/desc.h =================================================================== --- tip.orig/arch/x86/include/asm/desc.h +++ tip/arch/x86/include/asm/desc.h @@ -178,7 +178,7 @@ static inline void set_tssldt_descriptor #endif } -static inline void __set_tss_desc(unsigned cpu, unsigned int entry, void *addr) +static inline void __set_tss_desc(unsigned cpu, unsigned int entry, struct x86_hw_tss *addr) { struct desc_struct *d = get_cpu_gdt_rw(cpu); tss_desc tss; Index: tip/arch/x86/include/asm/processor.h =================================================================== --- tip.orig/arch/x86/include/asm/processor.h +++ tip/arch/x86/include/asm/processor.h @@ -163,7 +163,7 @@ enum cpuid_regs_idx { extern struct cpuinfo_x86 boot_cpu_data; extern struct cpuinfo_x86 new_cpu_data; -extern struct tss_struct doublefault_tss; +extern struct x86_hw_tss doublefault_tss; extern __u32 cpu_caps_cleared[NCAPINTS]; extern __u32 cpu_caps_set[NCAPINTS]; @@ -253,6 +253,11 @@ static inline void load_cr3(pgd_t *pgdir write_cr3(__sme_pa(pgdir)); } +/* + * Note that while the legacy 'TSS' name comes from 'Task State Segment', + * on modern x86 CPUs the TSS also holds information important to 64-bit mode, + * unrelated to the task-switch mechanism: + */ #ifdef CONFIG_X86_32 /* This is the TSS defined by the hardware. */ struct x86_hw_tss { @@ -323,7 +328,7 @@ struct x86_hw_tss { #define IO_BITMAP_BITS 65536 #define IO_BITMAP_BYTES (IO_BITMAP_BITS/8) #define IO_BITMAP_LONGS (IO_BITMAP_BYTES/sizeof(long)) -#define IO_BITMAP_OFFSET offsetof(struct tss_struct, io_bitmap) +#define IO_BITMAP_OFFSET (offsetof(struct tss_struct, io_bitmap) - offsetof(struct tss_struct, x86_tss)) #define INVALID_IO_BITMAP_OFFSET 0x8000 struct tss_struct { Index: tip/arch/x86/kernel/cpu/common.c =================================================================== --- tip.orig/arch/x86/kernel/cpu/common.c +++ tip/arch/x86/kernel/cpu/common.c @@ -1582,7 +1582,7 @@ void cpu_init(void) } } - t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); + t->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; /* * <= is required because the CPU will access up to @@ -1601,7 +1601,7 @@ void cpu_init(void) * Initialize the TSS. Don't bother initializing sp0, as the initial * task never enters user mode. */ - set_tss_desc(cpu, t); + set_tss_desc(cpu, &t->x86_tss); load_TR_desc(); load_mm_ldt(&init_mm); @@ -1659,12 +1659,12 @@ void cpu_init(void) * Initialize the TSS. Don't bother initializing sp0, as the initial * task never enters user mode. */ - set_tss_desc(cpu, t); + set_tss_desc(cpu, &t->x86_tss); load_TR_desc(); load_mm_ldt(&init_mm); - t->x86_tss.io_bitmap_base = offsetof(struct tss_struct, io_bitmap); + t->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; #ifdef CONFIG_DOUBLEFAULT /* Set up doublefault TSS pointer in the GDT */ Index: tip/arch/x86/kernel/doublefault.c =================================================================== --- tip.orig/arch/x86/kernel/doublefault.c +++ tip/arch/x86/kernel/doublefault.c @@ -50,25 +50,23 @@ static void doublefault_fn(void) cpu_relax(); } -struct tss_struct doublefault_tss __cacheline_aligned = { - .x86_tss = { - .sp0 = STACK_START, - .ss0 = __KERNEL_DS, - .ldt = 0, - .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, +struct x86_hw_tss doublefault_tss __cacheline_aligned = { + .sp0 = STACK_START, + .ss0 = __KERNEL_DS, + .ldt = 0, + .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, - .ip = (unsigned long) doublefault_fn, - /* 0x2 bit is always set */ - .flags = X86_EFLAGS_SF | 0x2, - .sp = STACK_START, - .es = __USER_DS, - .cs = __KERNEL_CS, - .ss = __KERNEL_DS, - .ds = __USER_DS, - .fs = __KERNEL_PERCPU, + .ip = (unsigned long) doublefault_fn, + /* 0x2 bit is always set */ + .flags = X86_EFLAGS_SF | 0x2, + .sp = STACK_START, + .es = __USER_DS, + .cs = __KERNEL_CS, + .ss = __KERNEL_DS, + .ds = __USER_DS, + .fs = __KERNEL_PERCPU, - .__cr3 = __pa_nodebug(swapper_pg_dir), - } + .__cr3 = __pa_nodebug(swapper_pg_dir), }; /* dummy for do_double_fault() call */ Index: tip/arch/x86/power/cpu.c =================================================================== --- tip.orig/arch/x86/power/cpu.c +++ tip/arch/x86/power/cpu.c @@ -165,12 +165,13 @@ static void fix_processor_context(void) struct desc_struct *desc = get_cpu_gdt_rw(cpu); tss_desc tss; #endif - set_tss_desc(cpu, t); /* - * This just modifies memory; should not be - * necessary. But... This is necessary, because - * 386 hardware has concept of busy TSS or some - * similar stupidity. - */ + + /* + * This just modifies memory; should not be necessary. But... This is + * necessary, because 386 hardware has concept of busy TSS or some + * similar stupidity. + */ + set_tss_desc(cpu, &t->x86_tss); #ifdef CONFIG_X86_64 memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));