forked from Minki/linux
x86/stackprotector/32: Make the canary into a regular percpu variable
On 32-bit kernels, the stackprotector canary is quite nasty -- it is stored at %gs:(20), which is nasty because 32-bit kernels use %fs for percpu storage. It's even nastier because it means that whether %gs contains userspace state or kernel state while running kernel code depends on whether stackprotector is enabled (this is CONFIG_X86_32_LAZY_GS), and this setting radically changes the way that segment selectors work. Supporting both variants is a maintenance and testing mess. Merely rearranging so that percpu and the stack canary share the same segment would be messy as the 32-bit percpu address layout isn't currently compatible with putting a variable at a fixed offset. Fortunately, GCC 8.1 added options that allow the stack canary to be accessed as %fs:__stack_chk_guard, effectively turning it into an ordinary percpu variable. This lets us get rid of all of the code to manage the stack canary GDT descriptor and the CONFIG_X86_32_LAZY_GS mess. (That name is special. We could use any symbol we want for the %fs-relative mode, but for CONFIG_SMP=n, gcc refuses to let us use any name other than __stack_chk_guard.) Forcibly disable stackprotector on older compilers that don't support the new options and turn the stack canary into a percpu variable. The "lazy GS" approach is now used for all 32-bit configurations. Also makes load_gs_index() work on 32-bit kernels. On 64-bit kernels, it loads the GS selector and updates the user GSBASE accordingly. (This is unchanged.) On 32-bit kernels, it loads the GS selector and updates GSBASE, which is now always the user base. This means that the overall effect is the same on 32-bit and 64-bit, which avoids some ifdeffery. [ bp: Massage commit message. ] Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lkml.kernel.org/r/c0ff7dba14041c7e5d1cae5d4df052f03759bef3.1613243844.git.luto@kernel.org
This commit is contained in:
parent
a38fd87484
commit
3fb0fdb3bb
@ -360,10 +360,6 @@ config X86_64_SMP
|
|||||||
def_bool y
|
def_bool y
|
||||||
depends on X86_64 && SMP
|
depends on X86_64 && SMP
|
||||||
|
|
||||||
config X86_32_LAZY_GS
|
|
||||||
def_bool y
|
|
||||||
depends on X86_32 && !STACKPROTECTOR
|
|
||||||
|
|
||||||
config ARCH_SUPPORTS_UPROBES
|
config ARCH_SUPPORTS_UPROBES
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
@ -386,7 +382,8 @@ config CC_HAS_SANE_STACKPROTECTOR
|
|||||||
default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC))
|
default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC))
|
||||||
help
|
help
|
||||||
We have to make sure stack protector is unconditionally disabled if
|
We have to make sure stack protector is unconditionally disabled if
|
||||||
the compiler produces broken code.
|
the compiler produces broken code or if it does not let us control
|
||||||
|
the segment on 32-bit kernels.
|
||||||
|
|
||||||
menu "Processor type and features"
|
menu "Processor type and features"
|
||||||
|
|
||||||
|
@ -79,6 +79,14 @@ ifeq ($(CONFIG_X86_32),y)
|
|||||||
|
|
||||||
# temporary until string.h is fixed
|
# temporary until string.h is fixed
|
||||||
KBUILD_CFLAGS += -ffreestanding
|
KBUILD_CFLAGS += -ffreestanding
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_STACKPROTECTOR),y)
|
||||||
|
ifeq ($(CONFIG_SMP),y)
|
||||||
|
KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard
|
||||||
|
else
|
||||||
|
KBUILD_CFLAGS += -mstack-protector-guard=global
|
||||||
|
endif
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
BITS := 64
|
BITS := 64
|
||||||
UTS_MACHINE := x86_64
|
UTS_MACHINE := x86_64
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* 1C(%esp) - %ds
|
* 1C(%esp) - %ds
|
||||||
* 20(%esp) - %es
|
* 20(%esp) - %es
|
||||||
* 24(%esp) - %fs
|
* 24(%esp) - %fs
|
||||||
* 28(%esp) - %gs saved iff !CONFIG_X86_32_LAZY_GS
|
* 28(%esp) - unused -- was %gs on old stackprotector kernels
|
||||||
* 2C(%esp) - orig_eax
|
* 2C(%esp) - orig_eax
|
||||||
* 30(%esp) - %eip
|
* 30(%esp) - %eip
|
||||||
* 34(%esp) - %cs
|
* 34(%esp) - %cs
|
||||||
@ -56,14 +56,9 @@
|
|||||||
/*
|
/*
|
||||||
* User gs save/restore
|
* User gs save/restore
|
||||||
*
|
*
|
||||||
* %gs is used for userland TLS and kernel only uses it for stack
|
* This is leftover junk from CONFIG_X86_32_LAZY_GS. A subsequent patch
|
||||||
* canary which is required to be at %gs:20 by gcc. Read the comment
|
* will remove it entirely.
|
||||||
* at the top of stackprotector.h for more info.
|
|
||||||
*
|
|
||||||
* Local labels 98 and 99 are used.
|
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32_LAZY_GS
|
|
||||||
|
|
||||||
/* unfortunately push/pop can't be no-op */
|
/* unfortunately push/pop can't be no-op */
|
||||||
.macro PUSH_GS
|
.macro PUSH_GS
|
||||||
pushl $0
|
pushl $0
|
||||||
@ -86,49 +81,6 @@
|
|||||||
.macro SET_KERNEL_GS reg
|
.macro SET_KERNEL_GS reg
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
#else /* CONFIG_X86_32_LAZY_GS */
|
|
||||||
|
|
||||||
.macro PUSH_GS
|
|
||||||
pushl %gs
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro POP_GS pop=0
|
|
||||||
98: popl %gs
|
|
||||||
.if \pop <> 0
|
|
||||||
add $\pop, %esp
|
|
||||||
.endif
|
|
||||||
.endm
|
|
||||||
.macro POP_GS_EX
|
|
||||||
.pushsection .fixup, "ax"
|
|
||||||
99: movl $0, (%esp)
|
|
||||||
jmp 98b
|
|
||||||
.popsection
|
|
||||||
_ASM_EXTABLE(98b, 99b)
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro PTGS_TO_GS
|
|
||||||
98: mov PT_GS(%esp), %gs
|
|
||||||
.endm
|
|
||||||
.macro PTGS_TO_GS_EX
|
|
||||||
.pushsection .fixup, "ax"
|
|
||||||
99: movl $0, PT_GS(%esp)
|
|
||||||
jmp 98b
|
|
||||||
.popsection
|
|
||||||
_ASM_EXTABLE(98b, 99b)
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro GS_TO_REG reg
|
|
||||||
movl %gs, \reg
|
|
||||||
.endm
|
|
||||||
.macro REG_TO_PTGS reg
|
|
||||||
movl \reg, PT_GS(%esp)
|
|
||||||
.endm
|
|
||||||
.macro SET_KERNEL_GS reg
|
|
||||||
movl $(__KERNEL_STACK_CANARY), \reg
|
|
||||||
movl \reg, %gs
|
|
||||||
.endm
|
|
||||||
|
|
||||||
#endif /* CONFIG_X86_32_LAZY_GS */
|
|
||||||
|
|
||||||
/* Unconditionally switch to user cr3 */
|
/* Unconditionally switch to user cr3 */
|
||||||
.macro SWITCH_TO_USER_CR3 scratch_reg:req
|
.macro SWITCH_TO_USER_CR3 scratch_reg:req
|
||||||
@ -779,7 +731,7 @@ SYM_CODE_START(__switch_to_asm)
|
|||||||
|
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
#ifdef CONFIG_STACKPROTECTOR
|
||||||
movl TASK_stack_canary(%edx), %ebx
|
movl TASK_stack_canary(%edx), %ebx
|
||||||
movl %ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset
|
movl %ebx, PER_CPU_VAR(__stack_chk_guard)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_RETPOLINE
|
#ifdef CONFIG_RETPOLINE
|
||||||
|
@ -439,6 +439,9 @@ struct fixed_percpu_data {
|
|||||||
* GCC hardcodes the stack canary as %gs:40. Since the
|
* GCC hardcodes the stack canary as %gs:40. Since the
|
||||||
* irq_stack is the object at %gs:0, we reserve the bottom
|
* irq_stack is the object at %gs:0, we reserve the bottom
|
||||||
* 48 bytes of the irq stack for the canary.
|
* 48 bytes of the irq stack for the canary.
|
||||||
|
*
|
||||||
|
* Once we are willing to require -mstack-protector-guard-symbol=
|
||||||
|
* support for x86_64 stackprotector, we can get rid of this.
|
||||||
*/
|
*/
|
||||||
char gs_base[40];
|
char gs_base[40];
|
||||||
unsigned long stack_canary;
|
unsigned long stack_canary;
|
||||||
@ -460,17 +463,7 @@ extern asmlinkage void ignore_sysret(void);
|
|||||||
void current_save_fsgs(void);
|
void current_save_fsgs(void);
|
||||||
#else /* X86_64 */
|
#else /* X86_64 */
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
#ifdef CONFIG_STACKPROTECTOR
|
||||||
/*
|
DECLARE_PER_CPU(unsigned long, __stack_chk_guard);
|
||||||
* Make sure stack canary segment base is cached-aligned:
|
|
||||||
* "For Intel Atom processors, avoid non zero segment base address
|
|
||||||
* that is not aligned to cache line boundary at all cost."
|
|
||||||
* (Optim Ref Manual Assembly/Compiler Coding Rule 15.)
|
|
||||||
*/
|
|
||||||
struct stack_canary {
|
|
||||||
char __pad[20]; /* canary at %gs:20 */
|
|
||||||
unsigned long canary;
|
|
||||||
};
|
|
||||||
DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
|
|
||||||
#endif
|
#endif
|
||||||
DECLARE_PER_CPU(struct irq_stack *, hardirq_stack_ptr);
|
DECLARE_PER_CPU(struct irq_stack *, hardirq_stack_ptr);
|
||||||
DECLARE_PER_CPU(struct irq_stack *, softirq_stack_ptr);
|
DECLARE_PER_CPU(struct irq_stack *, softirq_stack_ptr);
|
||||||
|
@ -37,7 +37,10 @@ struct pt_regs {
|
|||||||
unsigned short __esh;
|
unsigned short __esh;
|
||||||
unsigned short fs;
|
unsigned short fs;
|
||||||
unsigned short __fsh;
|
unsigned short __fsh;
|
||||||
/* On interrupt, gs and __gsh store the vector number. */
|
/*
|
||||||
|
* On interrupt, gs and __gsh store the vector number. They never
|
||||||
|
* store gs any more.
|
||||||
|
*/
|
||||||
unsigned short gs;
|
unsigned short gs;
|
||||||
unsigned short __gsh;
|
unsigned short __gsh;
|
||||||
/* On interrupt, this is the error code. */
|
/* On interrupt, this is the error code. */
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
*
|
*
|
||||||
* 26 - ESPFIX small SS
|
* 26 - ESPFIX small SS
|
||||||
* 27 - per-cpu [ offset to per-cpu data area ]
|
* 27 - per-cpu [ offset to per-cpu data area ]
|
||||||
* 28 - stack_canary-20 [ for stack protector ] <=== cacheline #8
|
* 28 - unused
|
||||||
* 29 - unused
|
* 29 - unused
|
||||||
* 30 - unused
|
* 30 - unused
|
||||||
* 31 - TSS for double fault handler
|
* 31 - TSS for double fault handler
|
||||||
@ -118,7 +118,6 @@
|
|||||||
|
|
||||||
#define GDT_ENTRY_ESPFIX_SS 26
|
#define GDT_ENTRY_ESPFIX_SS 26
|
||||||
#define GDT_ENTRY_PERCPU 27
|
#define GDT_ENTRY_PERCPU 27
|
||||||
#define GDT_ENTRY_STACK_CANARY 28
|
|
||||||
|
|
||||||
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
|
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
|
||||||
|
|
||||||
@ -158,12 +157,6 @@
|
|||||||
# define __KERNEL_PERCPU 0
|
# define __KERNEL_PERCPU 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
|
||||||
# define __KERNEL_STACK_CANARY (GDT_ENTRY_STACK_CANARY*8)
|
|
||||||
#else
|
|
||||||
# define __KERNEL_STACK_CANARY 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else /* 64-bit: */
|
#else /* 64-bit: */
|
||||||
|
|
||||||
#include <asm/cache.h>
|
#include <asm/cache.h>
|
||||||
@ -364,22 +357,15 @@ static inline void __loadsegment_fs(unsigned short value)
|
|||||||
asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
|
asm("mov %%" #seg ",%0":"=r" (value) : : "memory")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* x86-32 user GS accessors:
|
* x86-32 user GS accessors. This is ugly and could do with some cleaning up.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
# ifdef CONFIG_X86_32_LAZY_GS
|
# define get_user_gs(regs) (u16)({ unsigned long v; savesegment(gs, v); v; })
|
||||||
# define get_user_gs(regs) (u16)({ unsigned long v; savesegment(gs, v); v; })
|
# define set_user_gs(regs, v) loadsegment(gs, (unsigned long)(v))
|
||||||
# define set_user_gs(regs, v) loadsegment(gs, (unsigned long)(v))
|
# define task_user_gs(tsk) ((tsk)->thread.gs)
|
||||||
# define task_user_gs(tsk) ((tsk)->thread.gs)
|
# define lazy_save_gs(v) savesegment(gs, (v))
|
||||||
# define lazy_save_gs(v) savesegment(gs, (v))
|
# define lazy_load_gs(v) loadsegment(gs, (v))
|
||||||
# define lazy_load_gs(v) loadsegment(gs, (v))
|
# define load_gs_index(v) loadsegment(gs, (v))
|
||||||
# else /* X86_32_LAZY_GS */
|
|
||||||
# define get_user_gs(regs) (u16)((regs)->gs)
|
|
||||||
# define set_user_gs(regs, v) do { (regs)->gs = (v); } while (0)
|
|
||||||
# define task_user_gs(tsk) (task_pt_regs(tsk)->gs)
|
|
||||||
# define lazy_save_gs(v) do { } while (0)
|
|
||||||
# define lazy_load_gs(v) do { } while (0)
|
|
||||||
# endif /* X86_32_LAZY_GS */
|
|
||||||
#endif /* X86_32 */
|
#endif /* X86_32 */
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
@ -5,30 +5,23 @@
|
|||||||
* Stack protector works by putting predefined pattern at the start of
|
* Stack protector works by putting predefined pattern at the start of
|
||||||
* the stack frame and verifying that it hasn't been overwritten when
|
* the stack frame and verifying that it hasn't been overwritten when
|
||||||
* returning from the function. The pattern is called stack canary
|
* returning from the function. The pattern is called stack canary
|
||||||
* and unfortunately gcc requires it to be at a fixed offset from %gs.
|
* and unfortunately gcc historically required it to be at a fixed offset
|
||||||
* On x86_64, the offset is 40 bytes and on x86_32 20 bytes. x86_64
|
* from the percpu segment base. On x86_64, the offset is 40 bytes.
|
||||||
* and x86_32 use segment registers differently and thus handles this
|
|
||||||
* requirement differently.
|
|
||||||
*
|
*
|
||||||
* On x86_64, %gs is shared by percpu area and stack canary. All
|
* The same segment is shared by percpu area and stack canary. On
|
||||||
* percpu symbols are zero based and %gs points to the base of percpu
|
* x86_64, percpu symbols are zero based and %gs (64-bit) points to the
|
||||||
* area. The first occupant of the percpu area is always
|
* base of percpu area. The first occupant of the percpu area is always
|
||||||
* fixed_percpu_data which contains stack_canary at offset 40. Userland
|
* fixed_percpu_data which contains stack_canary at the approproate
|
||||||
* %gs is always saved and restored on kernel entry and exit using
|
* offset. On x86_32, the stack canary is just a regular percpu
|
||||||
* swapgs, so stack protector doesn't add any complexity there.
|
* variable.
|
||||||
*
|
*
|
||||||
* On x86_32, it's slightly more complicated. As in x86_64, %gs is
|
* Putting percpu data in %fs on 32-bit is a minor optimization compared to
|
||||||
* used for userland TLS. Unfortunately, some processors are much
|
* using %gs. Since 32-bit userspace normally has %fs == 0, we are likely
|
||||||
* slower at loading segment registers with different value when
|
* to load 0 into %fs on exit to usermode, whereas with percpu data in
|
||||||
* entering and leaving the kernel, so the kernel uses %fs for percpu
|
* %gs, we are likely to load a non-null %gs on return to user mode.
|
||||||
* area and manages %gs lazily so that %gs is switched only when
|
|
||||||
* necessary, usually during task switch.
|
|
||||||
*
|
*
|
||||||
* As gcc requires the stack canary at %gs:20, %gs can't be managed
|
* Once we are willing to require GCC 8.1 or better for 64-bit stackprotector
|
||||||
* lazily if stack protector is enabled, so the kernel saves and
|
* support, we can remove some of this complexity.
|
||||||
* restores userland %gs on kernel entry and exit. This behavior is
|
|
||||||
* controlled by CONFIG_X86_32_LAZY_GS and accessors are defined in
|
|
||||||
* system.h to hide the details.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _ASM_STACKPROTECTOR_H
|
#ifndef _ASM_STACKPROTECTOR_H
|
||||||
@ -44,14 +37,6 @@
|
|||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* 24 byte read-only segment initializer for stack canary. Linker
|
|
||||||
* can't handle the address bit shifting. Address will be set in
|
|
||||||
* head_32 for boot CPU and setup_per_cpu_areas() for others.
|
|
||||||
*/
|
|
||||||
#define GDT_STACK_CANARY_INIT \
|
|
||||||
[GDT_ENTRY_STACK_CANARY] = GDT_ENTRY_INIT(0x4090, 0, 0x18),
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the stackprotector canary value.
|
* Initialize the stackprotector canary value.
|
||||||
*
|
*
|
||||||
@ -86,7 +71,7 @@ static __always_inline void boot_init_stack_canary(void)
|
|||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
this_cpu_write(fixed_percpu_data.stack_canary, canary);
|
this_cpu_write(fixed_percpu_data.stack_canary, canary);
|
||||||
#else
|
#else
|
||||||
this_cpu_write(stack_canary.canary, canary);
|
this_cpu_write(__stack_chk_guard, canary);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,48 +80,16 @@ static inline void cpu_init_stack_canary(int cpu, struct task_struct *idle)
|
|||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
per_cpu(fixed_percpu_data.stack_canary, cpu) = idle->stack_canary;
|
per_cpu(fixed_percpu_data.stack_canary, cpu) = idle->stack_canary;
|
||||||
#else
|
#else
|
||||||
per_cpu(stack_canary.canary, cpu) = idle->stack_canary;
|
per_cpu(__stack_chk_guard, cpu) = idle->stack_canary;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
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_rw(cpu);
|
|
||||||
struct desc_struct desc;
|
|
||||||
|
|
||||||
desc = gdt_table[GDT_ENTRY_STACK_CANARY];
|
|
||||||
set_desc_base(&desc, canary);
|
|
||||||
write_gdt_entry(gdt_table, GDT_ENTRY_STACK_CANARY, &desc, DESCTYPE_S);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void load_stack_canary_segment(void)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
asm("mov %0, %%gs" : : "r" (__KERNEL_STACK_CANARY) : "memory");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* STACKPROTECTOR */
|
#else /* STACKPROTECTOR */
|
||||||
|
|
||||||
#define GDT_STACK_CANARY_INIT
|
|
||||||
|
|
||||||
/* dummy boot_init_stack_canary() is defined in linux/stackprotector.h */
|
/* dummy boot_init_stack_canary() is defined in linux/stackprotector.h */
|
||||||
|
|
||||||
static inline void setup_stack_canary_segment(int cpu)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
static inline void cpu_init_stack_canary(int cpu, struct task_struct *idle)
|
static inline void cpu_init_stack_canary(int cpu, struct task_struct *idle)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
static inline void load_stack_canary_segment(void)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
asm volatile ("mov %0, %%gs" : : "r" (0));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* STACKPROTECTOR */
|
#endif /* STACKPROTECTOR */
|
||||||
#endif /* _ASM_STACKPROTECTOR_H */
|
#endif /* _ASM_STACKPROTECTOR_H */
|
||||||
|
@ -13,12 +13,10 @@
|
|||||||
/* image of the saved processor state */
|
/* image of the saved processor state */
|
||||||
struct saved_context {
|
struct saved_context {
|
||||||
/*
|
/*
|
||||||
* On x86_32, all segment registers, with the possible exception of
|
* On x86_32, all segment registers except gs are saved at kernel
|
||||||
* gs, are saved at kernel entry in pt_regs.
|
* entry in pt_regs.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32_LAZY_GS
|
|
||||||
u16 gs;
|
u16 gs;
|
||||||
#endif
|
|
||||||
unsigned long cr0, cr2, cr3, cr4;
|
unsigned long cr0, cr2, cr3, cr4;
|
||||||
u64 misc_enable;
|
u64 misc_enable;
|
||||||
bool misc_enable_saved;
|
bool misc_enable_saved;
|
||||||
|
@ -53,11 +53,6 @@ void foo(void)
|
|||||||
offsetof(struct cpu_entry_area, tss.x86_tss.sp1) -
|
offsetof(struct cpu_entry_area, tss.x86_tss.sp1) -
|
||||||
offsetofend(struct cpu_entry_area, entry_stack_page.stack));
|
offsetofend(struct cpu_entry_area, entry_stack_page.stack));
|
||||||
|
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
|
||||||
BLANK();
|
|
||||||
OFFSET(stack_canary_offset, stack_canary, canary);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
BLANK();
|
BLANK();
|
||||||
DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
|
DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,6 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
|
|||||||
|
|
||||||
[GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
|
[GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
|
||||||
[GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
|
[GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
|
||||||
GDT_STACK_CANARY_INIT
|
|
||||||
#endif
|
#endif
|
||||||
} };
|
} };
|
||||||
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
|
EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
|
||||||
@ -599,7 +598,6 @@ void load_percpu_segment(int cpu)
|
|||||||
__loadsegment_simple(gs, 0);
|
__loadsegment_simple(gs, 0);
|
||||||
wrmsrl(MSR_GS_BASE, cpu_kernelmode_gs_base(cpu));
|
wrmsrl(MSR_GS_BASE, cpu_kernelmode_gs_base(cpu));
|
||||||
#endif
|
#endif
|
||||||
load_stack_canary_segment();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
@ -1796,7 +1794,8 @@ DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) =
|
|||||||
EXPORT_PER_CPU_SYMBOL(cpu_current_top_of_stack);
|
EXPORT_PER_CPU_SYMBOL(cpu_current_top_of_stack);
|
||||||
|
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
#ifdef CONFIG_STACKPROTECTOR
|
||||||
DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
|
DEFINE_PER_CPU(unsigned long, __stack_chk_guard);
|
||||||
|
EXPORT_PER_CPU_SYMBOL(__stack_chk_guard);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
@ -100,9 +100,7 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack) = {
|
|||||||
.ss = __KERNEL_DS,
|
.ss = __KERNEL_DS,
|
||||||
.ds = __USER_DS,
|
.ds = __USER_DS,
|
||||||
.fs = __KERNEL_PERCPU,
|
.fs = __KERNEL_PERCPU,
|
||||||
#ifndef CONFIG_X86_32_LAZY_GS
|
.gs = 0,
|
||||||
.gs = __KERNEL_STACK_CANARY,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.__cr3 = __pa_nodebug(swapper_pg_dir),
|
.__cr3 = __pa_nodebug(swapper_pg_dir),
|
||||||
},
|
},
|
||||||
|
@ -318,8 +318,8 @@ SYM_FUNC_START(startup_32_smp)
|
|||||||
movl $(__KERNEL_PERCPU), %eax
|
movl $(__KERNEL_PERCPU), %eax
|
||||||
movl %eax,%fs # set this cpu's percpu
|
movl %eax,%fs # set this cpu's percpu
|
||||||
|
|
||||||
movl $(__KERNEL_STACK_CANARY),%eax
|
xorl %eax,%eax
|
||||||
movl %eax,%gs
|
movl %eax,%gs # clear possible garbage in %gs
|
||||||
|
|
||||||
xorl %eax,%eax # Clear LDT
|
xorl %eax,%eax # Clear LDT
|
||||||
lldt %ax
|
lldt %ax
|
||||||
@ -339,20 +339,6 @@ SYM_FUNC_END(startup_32_smp)
|
|||||||
*/
|
*/
|
||||||
__INIT
|
__INIT
|
||||||
setup_once:
|
setup_once:
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
|
||||||
/*
|
|
||||||
* Configure the stack canary. The linker can't handle this by
|
|
||||||
* relocation. Manually set base address in stack canary
|
|
||||||
* segment descriptor.
|
|
||||||
*/
|
|
||||||
movl $gdt_page,%eax
|
|
||||||
movl $stack_canary,%ecx
|
|
||||||
movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
|
|
||||||
shrl $16, %ecx
|
|
||||||
movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
|
|
||||||
movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
andl $0,setup_once_ref /* Once is enough, thanks */
|
andl $0,setup_once_ref /* Once is enough, thanks */
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
@ -224,7 +224,6 @@ void __init setup_per_cpu_areas(void)
|
|||||||
per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu);
|
per_cpu(this_cpu_off, cpu) = per_cpu_offset(cpu);
|
||||||
per_cpu(cpu_number, cpu) = cpu;
|
per_cpu(cpu_number, cpu) = cpu;
|
||||||
setup_percpu_segment(cpu);
|
setup_percpu_segment(cpu);
|
||||||
setup_stack_canary_segment(cpu);
|
|
||||||
/*
|
/*
|
||||||
* Copy data used in early init routines from the
|
* Copy data used in early init routines from the
|
||||||
* initial arrays to the per cpu data areas. These
|
* initial arrays to the per cpu data areas. These
|
||||||
|
@ -164,17 +164,11 @@ int do_set_thread_area(struct task_struct *p, int idx,
|
|||||||
savesegment(fs, sel);
|
savesegment(fs, sel);
|
||||||
if (sel == modified_sel)
|
if (sel == modified_sel)
|
||||||
loadsegment(fs, sel);
|
loadsegment(fs, sel);
|
||||||
|
#endif
|
||||||
|
|
||||||
savesegment(gs, sel);
|
savesegment(gs, sel);
|
||||||
if (sel == modified_sel)
|
if (sel == modified_sel)
|
||||||
load_gs_index(sel);
|
load_gs_index(sel);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32_LAZY_GS
|
|
||||||
savesegment(gs, sel);
|
|
||||||
if (sel == modified_sel)
|
|
||||||
loadsegment(gs, sel);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
if (p->thread.fsindex == modified_sel)
|
if (p->thread.fsindex == modified_sel)
|
||||||
|
@ -404,10 +404,6 @@ static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx)
|
|||||||
case INAT_SEG_REG_FS:
|
case INAT_SEG_REG_FS:
|
||||||
return (unsigned short)(regs->fs & 0xffff);
|
return (unsigned short)(regs->fs & 0xffff);
|
||||||
case INAT_SEG_REG_GS:
|
case INAT_SEG_REG_GS:
|
||||||
/*
|
|
||||||
* GS may or may not be in regs as per CONFIG_X86_32_LAZY_GS.
|
|
||||||
* The macro below takes care of both cases.
|
|
||||||
*/
|
|
||||||
return get_user_gs(regs);
|
return get_user_gs(regs);
|
||||||
case INAT_SEG_REG_IGNORE:
|
case INAT_SEG_REG_IGNORE:
|
||||||
default:
|
default:
|
||||||
|
@ -46,10 +46,8 @@
|
|||||||
|
|
||||||
#define PVH_GDT_ENTRY_CS 1
|
#define PVH_GDT_ENTRY_CS 1
|
||||||
#define PVH_GDT_ENTRY_DS 2
|
#define PVH_GDT_ENTRY_DS 2
|
||||||
#define PVH_GDT_ENTRY_CANARY 3
|
|
||||||
#define PVH_CS_SEL (PVH_GDT_ENTRY_CS * 8)
|
#define PVH_CS_SEL (PVH_GDT_ENTRY_CS * 8)
|
||||||
#define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8)
|
#define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8)
|
||||||
#define PVH_CANARY_SEL (PVH_GDT_ENTRY_CANARY * 8)
|
|
||||||
|
|
||||||
SYM_CODE_START_LOCAL(pvh_start_xen)
|
SYM_CODE_START_LOCAL(pvh_start_xen)
|
||||||
cld
|
cld
|
||||||
@ -111,17 +109,6 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
|
|||||||
|
|
||||||
#else /* CONFIG_X86_64 */
|
#else /* CONFIG_X86_64 */
|
||||||
|
|
||||||
/* Set base address in stack canary descriptor. */
|
|
||||||
movl $_pa(gdt_start),%eax
|
|
||||||
movl $_pa(canary),%ecx
|
|
||||||
movw %cx, (PVH_GDT_ENTRY_CANARY * 8) + 2(%eax)
|
|
||||||
shrl $16, %ecx
|
|
||||||
movb %cl, (PVH_GDT_ENTRY_CANARY * 8) + 4(%eax)
|
|
||||||
movb %ch, (PVH_GDT_ENTRY_CANARY * 8) + 7(%eax)
|
|
||||||
|
|
||||||
mov $PVH_CANARY_SEL,%eax
|
|
||||||
mov %eax,%gs
|
|
||||||
|
|
||||||
call mk_early_pgtbl_32
|
call mk_early_pgtbl_32
|
||||||
|
|
||||||
mov $_pa(initial_page_table), %eax
|
mov $_pa(initial_page_table), %eax
|
||||||
@ -165,7 +152,6 @@ SYM_DATA_START_LOCAL(gdt_start)
|
|||||||
.quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* PVH_CS_SEL */
|
.quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* PVH_CS_SEL */
|
||||||
#endif
|
#endif
|
||||||
.quad GDT_ENTRY(0xc092, 0, 0xfffff) /* PVH_DS_SEL */
|
.quad GDT_ENTRY(0xc092, 0, 0xfffff) /* PVH_DS_SEL */
|
||||||
.quad GDT_ENTRY(0x4090, 0, 0x18) /* PVH_CANARY_SEL */
|
|
||||||
SYM_DATA_END_LABEL(gdt_start, SYM_L_LOCAL, gdt_end)
|
SYM_DATA_END_LABEL(gdt_start, SYM_L_LOCAL, gdt_end)
|
||||||
|
|
||||||
.balign 16
|
.balign 16
|
||||||
|
@ -99,11 +99,8 @@ static void __save_processor_state(struct saved_context *ctxt)
|
|||||||
/*
|
/*
|
||||||
* segment registers
|
* segment registers
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32_LAZY_GS
|
|
||||||
savesegment(gs, ctxt->gs);
|
savesegment(gs, ctxt->gs);
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
savesegment(gs, ctxt->gs);
|
|
||||||
savesegment(fs, ctxt->fs);
|
savesegment(fs, ctxt->fs);
|
||||||
savesegment(ds, ctxt->ds);
|
savesegment(ds, ctxt->ds);
|
||||||
savesegment(es, ctxt->es);
|
savesegment(es, ctxt->es);
|
||||||
@ -232,7 +229,6 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
|||||||
wrmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
|
wrmsrl(MSR_GS_BASE, ctxt->kernelmode_gs_base);
|
||||||
#else
|
#else
|
||||||
loadsegment(fs, __KERNEL_PERCPU);
|
loadsegment(fs, __KERNEL_PERCPU);
|
||||||
loadsegment(gs, __KERNEL_STACK_CANARY);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Restore the TSS, RO GDT, LDT, and usermode-relevant MSRs. */
|
/* Restore the TSS, RO GDT, LDT, and usermode-relevant MSRs. */
|
||||||
@ -255,7 +251,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
|
|||||||
*/
|
*/
|
||||||
wrmsrl(MSR_FS_BASE, ctxt->fs_base);
|
wrmsrl(MSR_FS_BASE, ctxt->fs_base);
|
||||||
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base);
|
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->usermode_gs_base);
|
||||||
#elif defined(CONFIG_X86_32_LAZY_GS)
|
#else
|
||||||
loadsegment(gs, ctxt->gs);
|
loadsegment(gs, ctxt->gs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1204,7 +1204,6 @@ static void __init xen_setup_gdt(int cpu)
|
|||||||
pv_ops.cpu.write_gdt_entry = xen_write_gdt_entry_boot;
|
pv_ops.cpu.write_gdt_entry = xen_write_gdt_entry_boot;
|
||||||
pv_ops.cpu.load_gdt = xen_load_gdt_boot;
|
pv_ops.cpu.load_gdt = xen_load_gdt_boot;
|
||||||
|
|
||||||
setup_stack_canary_segment(cpu);
|
|
||||||
switch_to_new_gdt(cpu);
|
switch_to_new_gdt(cpu);
|
||||||
|
|
||||||
pv_ops.cpu.write_gdt_entry = xen_write_gdt_entry;
|
pv_ops.cpu.write_gdt_entry = xen_write_gdt_entry;
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
|
# This requires GCC 8.1 or better. Specifically, we require
|
||||||
|
# -mstack-protector-guard-reg, added by
|
||||||
|
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81708
|
||||||
|
|
||||||
|
echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard - -o - 2> /dev/null | grep -q "%fs"
|
||||||
|
Loading…
Reference in New Issue
Block a user