Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3855816imm; Tue, 29 May 2018 15:21:36 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKbVPAOwWWOjY9QyHahcHq1992fS7an91iDGsk7Mppz7Sds8LUPJBEbGb524JlehtWdkgtp X-Received: by 2002:a62:c4dd:: with SMTP id h90-v6mr238605pfk.86.1527632496714; Tue, 29 May 2018 15:21:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527632496; cv=none; d=google.com; s=arc-20160816; b=DQzIR8xr4LPUgxxoGL4lBVIONqiwuM9DsblBjEPabgURnN8oQUOplqHjcePNH4dctb ZxkekLvDFU4h4oNwODnuYTf/oDgC6KHhJYpr+vL7A059566f2/LbbcYaKHVmcgXWCmag Lcxn8GndeVLFm44ea8HEMdw1wy5T5UHAna/GUn8p9Uz+NVBCoK9wToa6sfbee2X4mcN/ a8tf5PlZB7tjk1ewdgx6nVzRS12fUtxJFXbakm/iPaQwPwBTNmkJ7U0+1rBzvcmh3Zog W2GkUW2QL7DMRfZNcZC8LdniCDjeZeRQj2KNuSwdbqd17PkKvKAsCnYi+rWzP29XATVf XGZw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=yGXXGfuhvpf3fFuHpT+V2pZjK4crlqW5Z56cv/SBQ1c=; b=rEUe8OeKhBUG93ADtzeohL6eQ+j36FPEA/XRCMyV/Niv1O7a91nc/y09KhIwoQVjyp C2H+7+Yu4PVbfwgWM+jccfhDyRkgJHmK/fL2eLOULnjCmLjLO/uQ9RZVvmTdPzw5XLdW Ofs0R1foMSb9ybyN1WimPlwXnY+Un5D2ltBr6IdP1oo2B1Fr0GH2Z3k3b36WZU2Zd9CK wMMzYu4BdfubC8RPA0i0noCb80cM7zgNVJevFSMSjllgiZaIzbiGIwXlIJQmiUCCu5ju Vg/BmJ7njuFLkvmHiEDR6KN2YnCjQN6Rjh3FwRPvfSqFsTiD/h/FQJycGOtnduvJGvT7 5ldQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=fbau+YSw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v9-v6si34330463plg.124.2018.05.29.15.21.22; Tue, 29 May 2018 15:21:36 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=fbau+YSw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030266AbeE2WSD (ORCPT + 99 others); Tue, 29 May 2018 18:18:03 -0400 Received: from mail-pl0-f68.google.com ([209.85.160.68]:44315 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030220AbeE2WRz (ORCPT ); Tue, 29 May 2018 18:17:55 -0400 Received: by mail-pl0-f68.google.com with SMTP id z9-v6so6423617plk.11 for ; Tue, 29 May 2018 15:17:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=yGXXGfuhvpf3fFuHpT+V2pZjK4crlqW5Z56cv/SBQ1c=; b=fbau+YSwaiG57HzLQl5XQNFiqHGu7upHg29coJcPQ+Dj1ozSGPi+6NMx32FaOlF0SN A3ri4oFEV1SPZfZi8q97K4GlMuqLJYpyLTrVFfC4B8cLtIqiMSSijW5Upa4u/PpRQN3I 6jQt8Hv77JOpvGd82pQwB/dzSz6beLdeIiBuSolpPPDOvu+UyDX0j2zINwufz0+YRD7e K2/MYCrh+9qm2NCiIG1YjrnW1J5rofUM6s8kC8I1p/RWBYJzo7Wx3Xtv818KBX0/ZdRp 8wOKZxSbPghS2varhnDiF/JnM0Je8fgzo94Mm1uzJ6mDHRPs5w7bQ9IK1FJbDBQNGGjm jaIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=yGXXGfuhvpf3fFuHpT+V2pZjK4crlqW5Z56cv/SBQ1c=; b=itri3n0xH8UiOqqMF9ykdRcpm98VIAxWNA4j3V799KnirD/+AsZEtmiSYPlvUBZPZH inDNJwv5DoVHmhd7zN34M07ARa/662z28ix2dBsOZZ1qjzxBfDT1x6tDgS3ParIQCStj XKpfF8ri2hxySgbL2lGre9BMOI+gL/UJWVHWAM0txwg8wuvMYi8T72JdZVQcrRYis2C+ zDvD8/1Qdrkp1eQgQWKZBwCWY+D0ZcvsP1KF9/FYz0mw+jI5YmOMuGrx9A8+3aD4/Hjp i1GJqBazl7Qvp/kACKj/2xNTp2x1Qhhmw+HAc6pdbNZTcZpA8Ri3b+LjRnTg3WQaUXe9 LXiA== X-Gm-Message-State: ALKqPwcYUEBT7SIskuGanKo/Wgc7DQbrquJ1FQA64UzZxsExEvyueKs3 fcNf0Cv8lgvKKguKvHmxAZXH9g== X-Received: by 2002:a17:902:1566:: with SMTP id b35-v6mr219096plh.107.1527632274086; Tue, 29 May 2018 15:17:54 -0700 (PDT) Received: from skynet.sea.corp.google.com ([2620:15c:17:4:29de:3bb1:1270:e679]) by smtp.gmail.com with ESMTPSA id o84-v6sm78767935pfi.27.2018.05.29.15.17.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 May 2018 15:17:53 -0700 (PDT) From: Thomas Garnier To: kernel-hardening@lists.openwall.com Cc: Thomas Garnier , Skip Vitaly Kuznetsov , Skip Mathieu Desnoyers , Skip Michael Kelley , Skip Josh Poimboeuf , "Skip Kirill A. Shutemov" , Skip Kees Cook , Skip Tobias Klauser , Skip Nadav Amit , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , x86@kernel.org, Borislav Petkov , David Woodhouse , Andy Lutomirski , Greg Kroah-Hartman , Dave Hansen , Dominik Brodowski , Kate Stewart , Rik van Riel , Philippe Ombredanne , "Peter Zijlstra (Intel)" , Juergen Gross , Jia Zhang , Boris Ostrovsky , Konrad Rzeszutek Wilk , Ricardo Neri , Tom Lendacky , linux-kernel@vger.kernel.org Subject: [PATCH v4 20/27] x86: Support global stack cookie Date: Tue, 29 May 2018 15:15:21 -0700 Message-Id: <20180529221625.33541-21-thgarnie@google.com> X-Mailer: git-send-email 2.17.0.921.gf22659ad46-goog In-Reply-To: <20180529221625.33541-1-thgarnie@google.com> References: <20180529221625.33541-1-thgarnie@google.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add an off-by-default configuration option to use a global stack cookie instead of the default TLS. This configuration option will only be used with PIE binaries. For kernel stack cookie, the compiler uses the mcmodel=kernel to switch between the fs segment to gs segment. A PIE binary does not use mcmodel=kernel because it can be relocated anywhere, therefore the compiler will default to the fs segment register. This is fixed on the latest version of gcc. If the segment selector is available, it will be automatically added. If the automatic configuration was selected, a warning is written and the global variable stack cookie is used. If a specific stack mode was selected (regular or strong) and the compiler does not support selecting the segment register, an error is emitted. Signed-off-by: Thomas Garnier --- arch/x86/Kconfig | 12 ++++++++++++ arch/x86/Makefile | 9 +++++++++ arch/x86/entry/entry_32.S | 3 ++- arch/x86/entry/entry_64.S | 3 ++- arch/x86/include/asm/processor.h | 3 ++- arch/x86/include/asm/stackprotector.h | 19 ++++++++++++++----- arch/x86/kernel/asm-offsets.c | 3 ++- arch/x86/kernel/asm-offsets_32.c | 3 ++- arch/x86/kernel/asm-offsets_64.c | 3 ++- arch/x86/kernel/cpu/common.c | 3 ++- arch/x86/kernel/head_32.S | 3 ++- arch/x86/kernel/process.c | 5 +++++ 12 files changed, 56 insertions(+), 13 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1434ec78e556..177e712201d1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2198,6 +2198,18 @@ config RANDOMIZE_MEMORY_PHYSICAL_PADDING If unsure, leave at the default value. +config X86_GLOBAL_STACKPROTECTOR + bool "Stack cookie using a global variable" + depends on CC_STACKPROTECTOR_AUTO + default n + ---help--- + This option turns on the "stack-protector" GCC feature using a global + variable instead of a segment register. It is useful when the + compiler does not support custom segment registers when building a + position independent (PIE) binary. + + If unsure, say N + config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" depends on SMP diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 60135cbd905c..277ffc57ae13 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -141,6 +141,15 @@ else KBUILD_CFLAGS += $(call cc-option,-funit-at-a-time) endif +ifdef CONFIG_X86_GLOBAL_STACKPROTECTOR + ifeq ($(call cc-option, -mstack-protector-guard=global),) + $(error Cannot use CONFIG_X86_GLOBAL_STACKPROTECTOR: \ + -mstack-protector-guard=global not supported \ + by compiler) + endif + KBUILD_CFLAGS += -mstack-protector-guard=global +endif + ifdef CONFIG_X86_X32 x32_ld_ok := $(call try-run,\ /bin/echo -e '1: .quad 1b' | \ diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index bef8e2b202a8..b7d5bc710ae7 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -239,7 +239,8 @@ ENTRY(__switch_to_asm) movl %esp, TASK_threadsp(%eax) movl TASK_threadsp(%edx), %esp -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) movl TASK_stack_canary(%edx), %ebx movl %ebx, PER_CPU_VAR(stack_canary)+stack_canary_offset #endif diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index f9b42ca4bf60..a3d1ca4ec516 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -357,7 +357,8 @@ ENTRY(__switch_to_asm) movq %rsp, TASK_threadsp(%rdi) movq TASK_threadsp(%rsi), %rsp -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) movq TASK_stack_canary(%rsi), %rbx movq %rbx, PER_CPU_VAR(irq_stack_union + stack_canary_offset) #endif diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 8162b5a24d8c..566fa5c56148 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -414,7 +414,8 @@ extern asmlinkage void ignore_sysret(void); void save_fsgs_for_kvm(void); #endif #else /* X86_64 */ -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) /* * Make sure stack canary segment base is cached-aligned: * "For Intel Atom processors, avoid non zero segment base address diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index 371b3a4af000..5063f57d99f5 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -52,6 +52,10 @@ #define GDT_STACK_CANARY_INIT \ [GDT_ENTRY_STACK_CANARY] = GDT_ENTRY_INIT(0x4090, 0, 0x18), +#ifdef CONFIG_X86_GLOBAL_STACKPROTECTOR +extern unsigned long __stack_chk_guard; +#endif + /* * Initialize the stackprotector canary value. * @@ -63,7 +67,7 @@ static __always_inline void boot_init_stack_canary(void) u64 canary; u64 tsc; -#ifdef CONFIG_X86_64 +#if defined(CONFIG_X86_64) && !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) BUILD_BUG_ON(offsetof(union irq_stack_union, stack_canary) != 40); #endif /* @@ -77,17 +81,22 @@ static __always_inline void boot_init_stack_canary(void) canary += tsc + (tsc << 32UL); canary &= CANARY_MASK; +#ifdef CONFIG_X86_GLOBAL_STACKPROTECTOR + if (__stack_chk_guard == 0) + __stack_chk_guard = canary ?: 1; +#else /* !CONFIG_X86_GLOBAL_STACKPROTECTOR */ current->stack_canary = canary; #ifdef CONFIG_X86_64 this_cpu_write(irq_stack_union.stack_canary, canary); -#else +#else /* CONFIG_X86_32 */ this_cpu_write(stack_canary.canary, canary); #endif +#endif } static inline void setup_stack_canary_segment(int cpu) { -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) unsigned long canary = (unsigned long)&per_cpu(stack_canary, cpu); struct desc_struct *gdt_table = get_cpu_gdt_rw(cpu); struct desc_struct desc; @@ -100,7 +109,7 @@ static inline void setup_stack_canary_segment(int cpu) static inline void load_stack_canary_segment(void) { -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) asm("mov %0, %%gs" : : "r" (__KERNEL_STACK_CANARY) : "memory"); #endif } @@ -116,7 +125,7 @@ static inline void setup_stack_canary_segment(int cpu) static inline void load_stack_canary_segment(void) { -#ifdef CONFIG_X86_32 +#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) asm volatile ("mov %0, %%gs" : : "r" (0)); #endif } diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 76417a9aab73..4c9e1b667bda 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -32,7 +32,8 @@ void common(void) { BLANK(); OFFSET(TASK_threadsp, task_struct, thread.sp); -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) OFFSET(TASK_stack_canary, task_struct, stack_canary); #endif diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index f91ba53e06c8..cf8ef55a8b82 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -50,7 +50,8 @@ void foo(void) DEFINE(TSS_sysenter_sp0, offsetof(struct cpu_entry_area, tss.x86_tss.sp0) - offsetofend(struct cpu_entry_area, entry_stack_page.stack)); -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) BLANK(); OFFSET(stack_canary_offset, stack_canary, canary); #endif diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c index bf51e51d808d..a3c7e14f6434 100644 --- a/arch/x86/kernel/asm-offsets_64.c +++ b/arch/x86/kernel/asm-offsets_64.c @@ -69,7 +69,8 @@ int main(void) OFFSET(TSS_sp1, tss_struct, x86_tss.sp1); BLANK(); -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) DEFINE(stack_canary_offset, offsetof(union irq_stack_union, stack_canary)); BLANK(); #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a7f5b4c81c68..4d7bd08f97d6 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1577,7 +1577,8 @@ DEFINE_PER_CPU(unsigned long, cpu_current_top_of_stack) = (unsigned long)&init_thread_union + THREAD_SIZE; EXPORT_PER_CPU_SYMBOL(cpu_current_top_of_stack); -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); #endif diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index b59e4fb40fd9..0e849242de91 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -375,7 +375,8 @@ ENDPROC(startup_32_smp) */ __INIT setup_once: -#ifdef CONFIG_CC_STACKPROTECTOR +#if defined(CONFIG_CC_STACKPROTECTOR) && \ + !defined(CONFIG_X86_GLOBAL_STACKPROTECTOR) /* * Configure the stack canary. The linker can't handle this by * relocation. Manually set base address in stack canary diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 30ca2d1a9231..ace68dbfedf5 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -87,6 +87,11 @@ EXPORT_PER_CPU_SYMBOL(cpu_tss_rw); DEFINE_PER_CPU(bool, __tss_limit_invalid); EXPORT_PER_CPU_SYMBOL_GPL(__tss_limit_invalid); +#ifdef CONFIG_X86_GLOBAL_STACKPROTECTOR +unsigned long __stack_chk_guard __read_mostly; +EXPORT_SYMBOL(__stack_chk_guard); +#endif + /* * this gets called so that we can store lazy state into memory and copy the * current task into the new thread. -- 2.17.0.921.gf22659ad46-goog