riscv: Add STACKPROTECTOR supported
Subsystems (2)
[email protected]
maintainerPATCH 1/1 riscv: Add STACKPROTECTOR supported
From: Guo Ren <[email protected]>
The -fstack-protector & -fstack-protector-strong features are from gcc. The patch only add basic kernel support to stack-protector feature and some arch could have its own solution such as ARM64_PTR_AUTH.
After enabling STACKPROTECTOR and STACKPROTECTOR_STRONG, the .text size is expanded from 0x7de066 to 0x81fb32 (only 5%) to add canary checking code.
--- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/stackprotector.h | 29 +++++++++++++++++++++++++++++ arch/riscv/kernel/process.c | 6 ++++++ 3 files changed, 36 insertions(+) create mode 100644 arch/riscv/include/asm/stackprotector.h
arch/riscv/Kconfig +1 -0
@@ -63,6 +63,7 @@ config RISCV select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN select MODULES_USE_ELF_RELA if MODULES
arch/riscv/include/asm/stackprotector.h new file +29 -0
@@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_STACKPROTECTOR_H +#define _ASM_RISCV_STACKPROTECTOR_H + +#include <linux/random.h> +#include <linux/version.h> + +extern unsigned long __stack_chk_guard; + +/* +* Initialize the stackprotector canary value. +* +* NOTE: this must only be called from functions that never return, +* and it must always be inlined. +*/ +static __always_inline void boot_init_stack_canary(void) +{ +unsigned long canary; + +/* Try to get a semi random initial value. */ +get_random_bytes (&canary,sizeof (canary)); + canary ^=LINUX_VERSION_CODE ; + canary &=CANARY_MASK ; + + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary; +} +#endif /* _ASM_RISCV_STACKPROTECTOR_H */
arch/riscv/kernel/process.c +6 -0
@@ -24,6 +24,12 @@ registerunsigned long gp_in_global __asm__("gp" ); +#ifdef CONFIG_STACKPROTECTOR +#include <linux/stackprotector.h> +unsigned long __stack_chk_guard__read_mostly ; +EXPORT_SYMBOL (__stack_chk_guard); +#endif + extern asmlinkage void ret_from_fork(void); extern asmlinkage void ret_from_kernel_thread(void);
Signature · 1 line
2.7.4
Quoted 58 lines · On Sun, Jul 05, 2020 at 06:24:15AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
The -fstack-protector & -fstack-protector-strong features are from gcc. The patch only add basic kernel support to stack-protector feature and some arch could have its own solution such as
ARM64_PTR_AUTH.After enabling STACKPROTECTOR and
STACKPROTECTOR_STRONG, the .text size is expanded from0x7de066to0x81fb32(only 5%) to add canary checking code.Signed-off-by Guo Ren <[email protected]>Cc Paul Walmsley <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Albert Ou <[email protected]>Cc Masami Hiramatsu <[email protected]>Cc Björn Töpel <[email protected]>Cc Greentime Hu <[email protected]>Cc Atish Patra <[email protected]>--- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/stackprotector.h | 29 +++++++++++++++++++++++++++++ arch/riscv/kernel/process.c | 6 ++++++ 3 files changed, 36 insertions(+) create mode 100644 arch/riscv/include/asm/stackprotector.harch/riscv/Kconfig +1
-0@@ -63,6 +63,7 @@ config RISCV select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN select MODULES_USE_ELF_RELA if MODULESarch/riscv/include/asm/stackprotector.h new file +14
-0@@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_STACKPROTECTOR_H +#define _ASM_RISCV_STACKPROTECTOR_H + +#include <linux/random.h> +#include <linux/version.h> + +extern unsigned long __stack_chk_guard; + +/* +* Initialize the stackprotector canary value. +* +* NOTE: this must only be called from functions that never return,
arch/riscv/include/asm/stackprotector.h line 24
Quoted 10 lines
arch/riscv/include/asm/stackprotector.h new file +10
-0+* and it must always be inlined. +*/ +static __always_inline void boot_init_stack_canary(void) +{ +unsigned long canary; + +/* Try to get a semi random initial value. */ +get_random_bytes (&canary,sizeof (canary)); + canary ^=LINUX_VERSION_CODE ; + canary &=CANARY_MASK ;
Does riscv have any kind of instruction counters or other trivial timers that could be mixed in here? (e.g. x86's TSC)
arch/riscv/include/asm/stackprotector.h line 27
Quoted 3 lines
arch/riscv/include/asm/stackprotector.h new file +3
-0+ + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary;
What's needed for riscv to support a per-task canary? (e.g. x86's TLS or arm64's register-specific methods)
Quoted 22 lines
arch/riscv/include/asm/stackprotector.h new file +2
-0+} +#endif /* _ASM_RISCV_STACKPROTECTOR_H */ arch/riscv/kernel/process.c +6
-0@@ -24,6 +24,12 @@ registerunsigned long gp_in_global __asm__("gp" ); +#ifdef CONFIG_STACKPROTECTOR +#include <linux/stackprotector.h> +unsigned long __stack_chk_guard__read_mostly ; +EXPORT_SYMBOL (__stack_chk_guard); +#endif + extern asmlinkage void ret_from_fork(void); extern asmlinkage void ret_from_kernel_thread(void);Signature · 1 line
2.7.4
But yes, as a starting point, better to have a single per-boot global canary than none at all. :)
Signature · 1 line
Kees Cook
Guo Ren
maintainerHi Kees,
Quoted 65 lines · Kees Cook
Quoted 63 lines · On Sun, Jul 05, 2020 at 06:24:15AM +0000, [email protected] wrote:
From: Guo Ren <[email protected]>
The -fstack-protector & -fstack-protector-strong features are from gcc. The patch only add basic kernel support to stack-protector feature and some arch could have its own solution such as
ARM64_PTR_AUTH.After enabling STACKPROTECTOR and
STACKPROTECTOR_STRONG, the .text size is expanded from0x7de066to0x81fb32(only 5%) to add canary checking code.Signed-off-by Guo Ren <[email protected]>Cc Paul Walmsley <[email protected]>Cc Palmer Dabbelt <[email protected]>Cc Albert Ou <[email protected]>Cc Masami Hiramatsu <[email protected]>Cc Björn Töpel <[email protected]>Cc Greentime Hu <[email protected]>Cc Atish Patra <[email protected]>--- arch/riscv/Kconfig | 1 + arch/riscv/include/asm/stackprotector.h | 29 +++++++++++++++++++++++++++++ arch/riscv/kernel/process.c | 6 ++++++ 3 files changed, 36 insertions(+) create mode 100644 arch/riscv/include/asm/stackprotector.harch/riscv/Kconfig +1
-0@@ -63,6 +63,7 @@ config RISCV select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select IRQ_DOMAIN select MODULES_USE_ELF_RELA if MODULESarch/riscv/include/asm/stackprotector.h new file +19
-0@@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_RISCV_STACKPROTECTOR_H +#define _ASM_RISCV_STACKPROTECTOR_H + +#include <linux/random.h> +#include <linux/version.h> + +extern unsigned long __stack_chk_guard; + +/* +* Initialize the stackprotector canary value. +* +* NOTE: this must only be called from functions that never return, +* and it must always be inlined. +*/ +static __always_inline void boot_init_stack_canary(void) +{ +unsigned long canary;
Quoted 8 lines
arch/riscv/include/asm/stackprotector.h line 24
Quoted 5 lines
arch/riscv/include/asm/stackprotector.h new file +5
-0+ +/* Try to get a semi random initial value. */ +get_random_bytes (&canary,sizeof (canary)); + canary ^=LINUX_VERSION_CODE ; + canary &=CANARY_MASK ;Does riscv have any kind of instruction counters or other trivial timers that could be mixed in here? (e.g. x86's TSC)
Do you mean:
get_random_bytes(&canary, sizeof(canary));
+ canary += get_cycles64() + (get_cycles64() << 32UL); canary ^= LINUX_VERSION_CODE;
canary &= CANARY_MASK;
Ok ?
Quoted 7 lines
arch/riscv/include/asm/stackprotector.h line 27
Quoted 4 lines
arch/riscv/include/asm/stackprotector.h new file +3
-0+ + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary;What's needed for riscv to support a per-task canary? (e.g. x86's TLS or arm64's register-specific methods)
Some archs change __stack_chk_guard in _switch_to of entry.S, but it depends on !CONFIG_SMP.
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
get value from next_task->stack_canary store value to __stack_chk_guard
#endif
It's a so limitation solution for per-task canary, so I didn't copy it into riscv?
For the register-specific, I prefer arm64's then x86, let's continue talk in this mail thread:
https://lore.kernel.org/linux-riscv/[email protected]/T/#u
Quoted 20 lines
Quoted 20 lines
arch/riscv/include/asm/stackprotector.h new file +2
-0+} +#endif /* _ASM_RISCV_STACKPROTECTOR_H */ arch/riscv/kernel/process.c +6
-0@@ -24,6 +24,12 @@ registerunsigned long gp_in_global __asm__("gp" ); +#ifdef CONFIG_STACKPROTECTOR +#include <linux/stackprotector.h> +unsigned long __stack_chk_guard__read_mostly ; +EXPORT_SYMBOL (__stack_chk_guard); +#endif + extern asmlinkage void ret_from_fork(void); extern asmlinkage void ret_from_kernel_thread(void);
Quoted 8 lines
Quoted 3 lines
--
2.7.4But yes, as a starting point, better to have a single per-boot global canary than none at all. :)
Reviewed-by Kees Cook <[email protected]>
Thank you :)
--
Best Regards
Guo Ren
Quoted 13 lines · Guo Ren
Quoted 12 lines · Kees Cook
arch/riscv/include/asm/stackprotector.h line 24
Quoted 8 lines · On Sun, Jul 05, 2020 at 06:24:15AM +0000, [email protected] wrote:
arch/riscv/include/asm/stackprotector.h new file +8
-0+static __always_inline void boot_init_stack_canary(void) +{ +unsigned long canary; + +/* Try to get a semi random initial value. */ +get_random_bytes (&canary,sizeof (canary)); + canary ^=LINUX_VERSION_CODE ; + canary &=CANARY_MASK ;Does riscv have any kind of instruction counters or other trivial timers that could be mixed in here? (e.g. x86's TSC)
Quoted 7 lines
Do you mean:
get_random_bytes(&canary, sizeof(canary));
+ canary +=get_cycles64()+ (get_cycles64()<< 32UL); canary ^=LINUX_VERSION_CODE;
canary &=CANARY_MASK;Ok ?
Sure -- I assume get_cycles64() is architecturally "simple"? (i.e. it doesn't require that the entire time-keeping subsystem has started?)
Quoted 9 lines
Quoted 7 lines
arch/riscv/include/asm/stackprotector.h line 27
Quoted 4 lines
arch/riscv/include/asm/stackprotector.h new file +3
-0+ + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary;What's needed for riscv to support a per-task canary? (e.g. x86's TLS or arm64's register-specific methods)
Some archs change
__stack_chk_guardin_switch_toofentry.S, but it depends on !CONFIG_SMP.
Oh, funny. I hadn't actually noticed that logic for the !CONFIG_SMP cases. I see to problem with that, but the more important case, I think is the per-task canaries.
Quoted 7 lines
#if
defined(CONFIG_STACKPROTECTOR)&& !defined(CONFIG_SMP)
get value fromnext_task->stack_canarystore value to__stack_chk_guard
#endifIt's a so limitation solution for per-task canary, so I didn't copy it into riscv?
Right -- it's a limited solution. On the other had, is !CONFIG_SMP expected to be a common config for riscv? If so, it's worth adding. If not, I'd say skip it. (Though it looks very simple to do...)
Signature · 1 line
Kees Cook
Guo Ren
maintainerQuoted 21 lines · Kees Cook
Quoted 19 lines · Guo Ren
Quoted 12 lines · Kees Cook
arch/riscv/include/asm/stackprotector.h line 24
Quoted 8 lines · On Sun, Jul 05, 2020 at 06:24:15AM +0000, [email protected] wrote:
arch/riscv/include/asm/stackprotector.h new file +8
-0+static __always_inline void boot_init_stack_canary(void) +{ +unsigned long canary; + +/* Try to get a semi random initial value. */ +get_random_bytes (&canary,sizeof (canary)); + canary ^=LINUX_VERSION_CODE ; + canary &=CANARY_MASK ;Does riscv have any kind of instruction counters or other trivial timers that could be mixed in here? (e.g. x86's TSC)
Do you mean:
get_random_bytes(&canary, sizeof(canary));
+ canary +=get_cycles64()+ (get_cycles64()<< 32UL); canary ^=LINUX_VERSION_CODE;
canary &=CANARY_MASK;
Quoted 4 lines
Quoted 1 line
Ok ?
Sure -- I assume
get_cycles64()is architecturally "simple"? (i.e. it doesn't require that the entire time-keeping subsystem has started?)
Yes, it's just a csr read. But it's necessary? get_random_bytes should enough.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
arch/riscv/include/asm/stackprotector.h new file +3
-0+ + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary;
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
What's needed for riscv to support a per-task canary? (e.g. x86's TLS or arm64's register-specific methods)
Some archs change
__stack_chk_guardin_switch_toofentry.S, but it depends on !CONFIG_SMP.Oh, funny. I hadn't actually noticed that logic for the !CONFIG_SMP cases. I see to problem with that, but the more important case, I think is the per-task canaries.
Maybe some race condition problems. When canary changed the in the switch to, but other CPUs still get that value concurrently.
Quoted 6 lines
Quoted 6 lines
#if
defined(CONFIG_STACKPROTECTOR)&& !defined(CONFIG_SMP)
get value fromnext_task->stack_canarystore value to__stack_chk_guard
#endif
Quoted 6 lines
Quoted 2 lines
It's a so limitation solution for per-task canary, so I didn't copy it into riscv?
Right -- it's a limited solution. On the other had, is !CONFIG_SMP expected to be a common config for riscv? If so, it's worth adding. If not, I'd say skip it. (Though it looks very simple to do...)
CONFIG_SMP is mostly default for me and let's talk about arm64/x86 per-task solution. That is the right way.
Signature · 4 lines
Best Regards Guo Ren ML: https://lore.kernel.org/linux-csky/
Quoted 4 lines · Guo Ren
Quoted 2 lines · Kees Cook
Sure -- I assume
get_cycles64()is architecturally "simple"? (i.e. it doesn't require that the entire time-keeping subsystem has started?)Yes, it's just a csr read. But it's necessary?
get_random_bytesshould enough.
Well, that depends on how early _all_ riscv platforms are able to initialize their random pool correctly. I'd include a csr mix.
Signature · 1 line
Kees Cook