[RFC] Test new gcc stack protector option

Message ID 1511306855.2466.28.camel@kernel.crashing.org
State New
Headers show
Series
  • [RFC] Test new gcc stack protector option
Related show

Commit Message

Benjamin Herrenschmidt Nov. 21, 2017, 11:27 p.m.
This tentative patch exploits the new gcc parametrized stack
protector options, courtesy of Segher, currently available
in gcc 7.x.

Tested in simics.

Not-yet-signed-off-by...
---

Patch

diff --git a/Makefile.main b/Makefile.main
index 73c91962..83576db1 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -19,6 +19,7 @@  try = $(shell set -e; if ($(1)) >/dev/null 2>&1; \
 	else echo "$(3)"; fi )
 
 try-cflag = $(call try,$(1) $(2) -x c -c /dev/null -o /dev/null,$(2))
+test_cflag = $(call try,$(1) $(2) -x c -c /dev/null -o /dev/null,1,0)
 
 # Base warnings
 CWARNS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
@@ -84,20 +85,33 @@  ifeq ($(SKIBOOT_GCOV),1)
 CFLAGS += -fprofile-arcs -ftest-coverage -DSKIBOOT_GCOV=1
 endif
 
+# Check if the new parametrized stack protector option is supported
+# by gcc, otherwise disable stack protector
+STACK_PROT_CFLAGS := -mstack-protector-guard=tls -mstack-protector-guard-reg=%r13
+STACK_PROT_CFLAGS += -mstack-protector-guard-offset=0
+HAS_STACK_PROT := $(call test_cflag,$(CC),$(STACK_PROT_CFLAGS))
+
 # Stack protector disabled for now. gcc tends to use the TLS to
 # access the canary (depending on how gcc was built), and this won't
 # work for us.
 #
 ifeq ($(STACK_CHECK),1)
-#CFLAGS += -fstack-protector-all -pg
-CFLAGS += -fno-stack-protector -pg
+STACK_PROT_CFLAGS += -fstack-protector-all
 CPPFLAGS += -DSTACK_CHECK_ENABLED
+CFLAGS += -pg
+else
+STACK_PROT_CFLAGS += -fstack-protector
+STACK_PROT_CFLAGS += $(call try-cflag,$(CC),-fstack-protector-strong)
+endif
+
+ifeq ($(HAS_STACK_PROT),1)
+CPPFLAGS += -DHAS_STACK_PROT
+CFLAGS += $(STACK_PROT_CFLAGS)
 else
 CFLAGS += -fno-stack-protector
-#CFLAGS += -fstack-protector
-#CFLAGS += $(call try-cflag,$(CC),-fstack-protector-strong)
 endif
 
+
 CFLAGS += $(call try-cflag,$(CC),-Wjump-misses-init) \
 	  $(call try-cflag,$(CC),-Wsuggest-attribute=const) \
 	  $(call try-cflag,$(CC),-Wsuggest-attribute=noreturn) \
diff --git a/asm/head.S b/asm/head.S
index ccf09482..444907a3 100644
--- a/asm/head.S
+++ b/asm/head.S
@@ -389,6 +389,11 @@  boot_entry:
 	li	%r0,0
 	std	%r0,CPUTHREAD_STACK_BOT_MARK(%r13)
 #endif
+	/* Initialize the stack guard */
+	LOAD_IMM64(%r3,STACK_CHECK_GUARD_BASE);
+	xor	%r3,%r3,%r31
+	std	%r3,0(%r13)
+
 	/* Jump to C */
 	mr	%r3,%r27
 	bl	main_cpu_entry
diff --git a/core/cpu.c b/core/cpu.c
index 27e0d6cf..cf14d267 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -794,6 +794,7 @@  static void init_cpu_thread(struct cpu_thread *t,
 	init_lock(&t->dctl_lock);
 	init_lock(&t->job_lock);
 	list_head_init(&t->job_queue);
+	t->stack_guard = STACK_CHECK_GUARD_BASE ^ pir;
 	t->state = state;
 	t->pir = pir;
 #ifdef STACK_CHECK_ENABLED
@@ -837,7 +838,8 @@  void __nomcount pre_init_boot_cpu(void)
 {
 	struct cpu_thread *cpu = this_cpu();
 
-	memset(cpu, 0, sizeof(struct cpu_thread));
+	/* We skip the stack guard ! */
+	memset(((void *)cpu) + 8, 0, sizeof(struct cpu_thread) - 8);
 }
 
 void init_boot_cpu(void)
@@ -915,8 +917,14 @@  void init_boot_cpu(void)
 	top_of_ram += (cpu_max_pir + 1) * STACK_SIZE;
 
 	/* Clear the CPU structs */
-	for (i = 0; i <= cpu_max_pir; i++)
+	for (i = 0; i <= cpu_max_pir; i++) {
+		/* boot CPU already cleared and we don't want to clobber
+		 * its stack guard value.
+		 */
+		if (i == pir)
+			continue;
 		memset(&cpu_stacks[i].cpu, 0, sizeof(struct cpu_thread));
+	}
 
 	/* Setup boot CPU state */
 	boot_cpu = &cpu_stacks[pir].cpu;
diff --git a/core/utils.c b/core/utils.c
index d21881ef..9e2cb37c 100644
--- a/core/utils.c
+++ b/core/utils.c
@@ -22,9 +22,6 @@ 
 #include <cpu.h>
 #include <stack.h>
 
-extern unsigned long __stack_chk_guard;
-unsigned long __stack_chk_guard = 0xdeadf00dbaad300dULL;
-
 void __noreturn assert_fail(const char *msg)
 {
 	/**
diff --git a/include/cpu.h b/include/cpu.h
index 168fa994..0b3c37e8 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -44,6 +44,11 @@  struct cpu_job;
 struct xive_cpu_state;
 
 struct cpu_thread {
+	/*
+	 * "stack_guard" must be at offset 0 to match the
+	 * -mstack-protector-guard-offset=0 statement in the Makefile
+	 */
+	uint64_t			stack_guard;
 	uint32_t			pir;
 	uint32_t			server_no;
 	uint32_t			chip_id;
diff --git a/include/stack.h b/include/stack.h
index 3c9799b1..e50b34f0 100644
--- a/include/stack.h
+++ b/include/stack.h
@@ -44,6 +44,8 @@ 
  */
 #define STACK_WARNING_GAP	2048
 
+#define STACK_CHECK_GUARD_BASE	0xdeadf00dbaad300
+
 #ifndef __ASSEMBLY__
 
 #include <stdint.h>