Skip to content

Commit f5730d4

Browse files
committed
s390: Add stackprotector support
Stackprotector support was previously unavailable on s390 because by default compilers generate code which is not suitable for the kernel: the canary value is accessed via thread local storage, where the address of thread local storage is within access registers 0 and 1. Using those registers also for the kernel would come with a significant performance impact and more complicated kernel entry/exit code, since access registers contents would have to be exchanged on every kernel entry and exit. With the upcoming gcc 16 release new compiler options will become available which allow to generate code suitable for the kernel. [1] Compiler option -mstack-protector-guard=global instructs gcc to generate stackprotector code that refers to a global stackprotector canary value via symbol __stack_chk_guard. Access to this value is guaranteed to occur via larl and lgrl instructions. Furthermore, compiler option -mstack-protector-guard-record generates a section containing all code addresses that reference the canary value. To allow for per task canary values the instructions which load the address of __stack_chk_guard are patched so they access a lowcore field instead: a per task canary value is available within the task_struct of each task, and is written to the per-cpu lowcore location on each context switch. Also add sanity checks and debugging option to be consistent with other kernel code patching mechanisms. Full debugging output can be enabled with the following kernel command line options: debug_stackprotector bootdebug ignore_loglevel earlyprintk dyndbg="file stackprotector.c +p" Example debug output: stackprot: 0000021e402d4eda: c010005a9ae3 -> c01f00070240 where "<insn address>: <old insn> -> <new insn>". [1] gcc commit 0cd1f03939d5 ("s390: Support global stack protector") Reviewed-by: Sven Schnelle <svens@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
1 parent 1d7764c commit f5730d4

18 files changed

Lines changed: 269 additions & 4 deletions

arch/s390/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ config CC_HAS_ASM_AOR_FORMAT_FLAGS
6969
Clang versions before 19.1.0 do not support A,
7070
O, and R inline assembly format flags.
7171

72+
config CC_HAS_STACKPROTECTOR_GLOBAL
73+
def_bool $(cc-option, -mstack-protector-guard=global -mstack-protector-guard-record)
74+
7275
config S390
7376
def_bool y
7477
#
@@ -245,6 +248,7 @@ config S390
245248
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
246249
select HAVE_SETUP_PER_CPU_AREA
247250
select HAVE_SOFTIRQ_ON_OWN_STACK
251+
select HAVE_STACKPROTECTOR if CC_HAS_STACKPROTECTOR_GLOBAL
248252
select HAVE_SYSCALL_TRACEPOINTS
249253
select HAVE_VIRT_CPU_ACCOUNTING
250254
select HAVE_VIRT_CPU_ACCOUNTING_IDLE

arch/s390/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ ifdef CONFIG_EXPOLINE
8989
aflags-y += -DCC_USING_EXPOLINE
9090
endif
9191

92+
ifeq ($(CONFIG_STACKPROTECTOR),y)
93+
KBUILD_CFLAGS += -mstack-protector-guard=global -mstack-protector-guard-record
94+
endif
95+
9296
ifdef CONFIG_FUNCTION_TRACER
9397
ifeq ($(call cc-option,-mfentry -mnop-mcount),)
9498
# make use of hotpatch feature if the compiler supports it

arch/s390/boot/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
3232
obj-y += $(if $(CONFIG_KERNEL_UNCOMPRESSED),,decompressor.o) info.o
3333
obj-$(CONFIG_KERNEL_ZSTD) += clz_ctz.o
3434
obj-$(CONFIG_KMSAN) += kmsan.o
35+
obj-$(CONFIG_STACKPROTECTOR) += stackprotector.o
3536
obj-all := $(obj-y) piggy.o syms.o
3637

3738
targets := bzImage section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y)

arch/s390/boot/boot.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ struct vmlinux_info {
2828
unsigned long invalid_pg_dir_off;
2929
unsigned long alt_instructions;
3030
unsigned long alt_instructions_end;
31+
#ifdef CONFIG_STACKPROTECTOR
32+
unsigned long stack_prot_start;
33+
unsigned long stack_prot_end;
34+
#endif
3135
#ifdef CONFIG_KASAN
3236
unsigned long kasan_early_shadow_page_off;
3337
unsigned long kasan_early_shadow_pte_off;

arch/s390/boot/ipl_parm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/init.h>
44
#include <linux/ctype.h>
55
#include <linux/pgtable.h>
6+
#include <asm/arch-stackprotector.h>
67
#include <asm/abs_lowcore.h>
78
#include <asm/page-states.h>
89
#include <asm/machine.h>
@@ -294,6 +295,11 @@ void parse_boot_command_line(void)
294295
cmma_flag = 0;
295296
}
296297

298+
#ifdef CONFIG_STACKPROTECTOR
299+
if (!strcmp(param, "debug_stackprotector"))
300+
stack_protector_debug = 1;
301+
#endif
302+
297303
#if IS_ENABLED(CONFIG_KVM)
298304
if (!strcmp(param, "prot_virt")) {
299305
rc = kstrtobool(val, &enabled);

arch/s390/boot/stackprotector.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#define boot_fmt(fmt) "stackprot: " fmt
4+
5+
#include "boot.h"
6+
#include "../kernel/stackprotector.c"

arch/s390/boot/startup.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include <asm/uv.h>
2121
#include <asm/abs_lowcore.h>
2222
#include <asm/physmem_info.h>
23+
#include <asm/stacktrace.h>
24+
#include <asm/asm-offsets.h>
25+
#include <asm/arch-stackprotector.h>
2326
#include "decompressor.h"
2427
#include "boot.h"
2528
#include "uv.h"
@@ -477,6 +480,10 @@ static void kaslr_adjust_vmlinux_info(long offset)
477480
vmlinux.invalid_pg_dir_off += offset;
478481
vmlinux.alt_instructions += offset;
479482
vmlinux.alt_instructions_end += offset;
483+
#ifdef CONFIG_STACKPROTECTOR
484+
vmlinux.stack_prot_start += offset;
485+
vmlinux.stack_prot_end += offset;
486+
#endif
480487
#ifdef CONFIG_KASAN
481488
vmlinux.kasan_early_shadow_page_off += offset;
482489
vmlinux.kasan_early_shadow_pte_off += offset;
@@ -622,6 +629,7 @@ void startup_kernel(void)
622629
__apply_alternatives((struct alt_instr *)_vmlinux_info.alt_instructions,
623630
(struct alt_instr *)_vmlinux_info.alt_instructions_end,
624631
ALT_CTX_EARLY);
632+
stack_protector_apply_early(text_lma);
625633

626634
/*
627635
* Save KASLR offset for early dumps, before vmcore_info is set.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef _ASM_S390_ARCH_STACKPROTECTOR_H
4+
#define _ASM_S390_ARCH_STACKPROTECTOR_H
5+
6+
extern unsigned long __stack_chk_guard;
7+
extern int stack_protector_debug;
8+
9+
void __stack_protector_apply_early(unsigned long kernel_start);
10+
int __stack_protector_apply(unsigned long *start, unsigned long *end, unsigned long kernel_start);
11+
12+
static inline void stack_protector_apply_early(unsigned long kernel_start)
13+
{
14+
if (IS_ENABLED(CONFIG_STACKPROTECTOR))
15+
__stack_protector_apply_early(kernel_start);
16+
}
17+
18+
static inline int stack_protector_apply(unsigned long *start, unsigned long *end)
19+
{
20+
if (IS_ENABLED(CONFIG_STACKPROTECTOR))
21+
return __stack_protector_apply(start, end, 0);
22+
return 0;
23+
}
24+
25+
#endif /* _ASM_S390_ARCH_STACKPROTECTOR_H */

arch/s390/include/asm/lowcore.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ struct lowcore {
100100

101101
/* Save areas. */
102102
__u64 save_area[8]; /* 0x0200 */
103-
__u8 pad_0x0240[0x0280-0x0240]; /* 0x0240 */
103+
__u64 stack_canary; /* 0x0240 */
104+
__u8 pad_0x0248[0x0280-0x0248]; /* 0x0248 */
104105
__u64 save_area_restart[1]; /* 0x0280 */
105106

106107
__u64 pcpu; /* 0x0288 */
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef _ASM_S390_STACKPROTECTOR_H
4+
#define _ASM_S390_STACKPROTECTOR_H
5+
6+
#include <linux/sched.h>
7+
#include <asm/current.h>
8+
#include <asm/lowcore.h>
9+
10+
static __always_inline void boot_init_stack_canary(void)
11+
{
12+
current->stack_canary = get_random_canary();
13+
get_lowcore()->stack_canary = current->stack_canary;
14+
}
15+
16+
#endif /* _ASM_S390_STACKPROTECTOR_H */

0 commit comments

Comments
 (0)