[PATCH] lib: utils: Initial compiler built-in stack protector support
Alvin Chang
alvinga at andestech.com
Sun May 18 18:48:56 PDT 2025
Hi Yu-Chien,
> -----Original Message-----
> From: Yu-Chien Lin <mail at yclin.org>
> Sent: Wednesday, May 7, 2025 10:35 PM
> To: opensbi at lists.infradead.org; Alvin Che-Chia Chang(å¼µå²å)
> <alvinga at andestech.com>
> Subject: Re: [PATCH] lib: utils: Initial compiler built-in stack
> protector support
>
> [EXTERNAL MAIL]
>
> Hi Alvin,
>
> I encountered an issue when building with DEBUG=1 and
> CONFIG_STACK_PROTECTOR_ALL=y. An exception occurs at the
> __check_csr_64 macro which calls sbi_hart_expected_trap_addr().
> Not sure the root cause but here's a workaround that disables stack
> protection specifically for this function:
>
> + #pragma GCC push_options
> + #pragma GCC optimize ("no-stack-protector")
> static inline ulong sbi_hart_expected_trap_addr(void) {
> return (ulong)sbi_hart_expected_trap; }
> + #pragma GCC pop_options
>
> Regards,
> Peter Lin
Thanks for reporting this issue.
The root cause is that when OpenSBI is compiled with -O0 optimization level,
the sbi_hart_expected_trap_addr() in the following code block becomes a "regular function call" rather than "inline function":
#define csr_read_allowed(csr_num, trap) \
({ \
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4"); \
register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong ret = 0; \
((struct sbi_trap_info *)(trap))->cause = 0; \
asm volatile( \
"add %[ttmp], %[tinfo], zero\n" \
"csrrw %[mtvec], " STR(CSR_MTVEC) ", %[mtvec]\n" \
"csrr %[ret], %[csr]\n" \
"csrw " STR(CSR_MTVEC) ", %[mtvec]" \
: [mtvec] "+&r"(mtvec), [tinfo] "+&r"(tinfo), \
[ttmp] "+&r"(ttmp), [ret] "=&r" (ret) \
: [csr] "i" (csr_num) \
: "memory"); \
ret; \
}) \
When compiling OpenSBI with -O0 and -fstack-protector-all:
Compiler uses register a3 in sbi_hart_expected_trap_addr() to check the stack guard variable.
However, register a3 is not preserved when calling sbi_hart_expected_trap_addr(), so a3 is clobbered by sbi_hart_expected_trap_addr().
val = csr_read_allowed(CSR_TSELECT, &trap);
6dae: fb040793 addi a5,s0,-80
6db2: 86be mv a3,a5
6db4: af5ff0ef jal 68a8 <sbi_hart_expected_trap_addr>
6db8: 84aa mv s1,a0
6dba: fa043823 sd zero,-80(s0)
6dbe: 87a6 mv a5,s1
6dc0: 00068733 add a4,a3,zero
6dc4: 305797f3 csrrw a5,mtvec,a5
6dc8: 7a002673 csrr a2,tselect
6dcc: 30579073 csrw mtvec,a5
6dd0: 8932 mv s2,a2
6dd2: 87ca mv a5,s2
6dd4: f8f43023 sd a5,-128(s0)
In addition to the workaround you provided, there are two workarounds I found:
1. Instead of calling sbi_hart_expected_trap_addr(), we can directly cast sbi_hart_expected_trap since it is extern variable.
- register ulong mtvec = sbi_hart_expected_trap_addr();
+ register ulong mtvec = (ulong)sbi_hart_expected_trap;
2. Reorder sbi_hart_expected_trap_addr() before using a3:
register ulong mtvec = sbi_hart_expected_trap_addr(); \
register ulong tinfo asm("a3") = (ulong)trap; \
register ulong ttmp asm("a4");
I am not sure which workaround is the best one.
Maybe there are better solutions which I am not aware of.
Need other reviewer's comments.
Regards,
Alvin Chang
>
> On 5/4/25 12:19 AM, Alvin Chang wrote:
> > Add stack_protector.c which defines the stack guard variable and the
> > function which will be referenced by compiler built-in stack protector.
> >
> > This patch just try to support stack-protector so the value of the
> > stack guard variable is simply fixed for now. It could be improved
> > by deriving from a random number generator, such as Zkr extension or
> > any platform-specific random number sources.
> >
> > Introduce three configurations for the stack protector:
> > 1. CONFIG_STACK_PROTECTOR to enable the stack protector feature by
> > providing "-fstack-protector" compiler flag 2.
> > CONFIG_STACK_PROTECTOR_STRONG to provide "-fstack-protector-strong"
> > 3. CONFIG_STACK_PROTECTOR_ALL to provide "-fstack-protector-all"
> >
> > Instead of fixing the compiler flag of stack-protector feature as
> > "-fstack-protector", we derive it from the introduced Kconfig
> > configurations. The compiler flag "stack-protector-cflags-y" is
> > defined as Makefile "immediately expanded variables" with ":=".
> > Thus, the stronger configuration of the stack protector can
> > overwrite the preceding one.
> >
> > Signed-off-by: Alvin Chang <alvinga at andestech.com>
> > ---
> > Makefile | 3 ++-
> > lib/utils/Kconfig | 2 ++
> > lib/utils/stack_protector/Kconfig | 28
> +++++++++++++++++++++
> > lib/utils/stack_protector/objects.mk | 18 +++++++++++++
> > lib/utils/stack_protector/stack_protector.c | 18 +++++++++++++
> > 5 files changed, 68 insertions(+), 1 deletion(-)
> > create mode 100644 lib/utils/stack_protector/Kconfig
> > create mode 100644 lib/utils/stack_protector/objects.mk
> > create mode 100644 lib/utils/stack_protector/stack_protector.c
> >
> > diff --git a/Makefile b/Makefile
> > index e90836c..eae6d16 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -360,7 +360,7 @@ GENFLAGS += $(libsbiutils-genflags-y)
> > GENFLAGS += $(platform-genflags-y)
> > GENFLAGS += $(firmware-genflags-y)
> >
> > -CFLAGS = -g -Wall -Werror -ffreestanding -nostdlib
> -fno-stack-protector -fno-strict-aliasing -ffunction-sections
> -fdata-sections
> > +CFLAGS = -g -Wall -Werror -ffreestanding
> -nostdlib -fno-strict-aliasing -ffunction-sections -fdata-sections
> > CFLAGS += -fno-omit-frame-pointer
> -fno-optimize-sibling-calls
> > # Optionally supported flags
> > ifeq ($(CC_SUPPORT_VECTOR),y)
> > @@ -379,6 +379,7 @@ CFLAGS += $(GENFLAGS)
> > CFLAGS += $(platform-cflags-y)
> > CFLAGS += -fPIE -pie
> > CFLAGS += $(firmware-cflags-y)
> > +CFLAGS += $(stack-protector-cflags-y)
> >
> > CPPFLAGS += $(GENFLAGS)
> > CPPFLAGS += $(platform-cppflags-y)
> > diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig index
> > 901ba56..40e5633 100644
> > --- a/lib/utils/Kconfig
> > +++ b/lib/utils/Kconfig
> > @@ -26,6 +26,8 @@ source "$(OPENSBI_SRC_DIR)/lib/utils/reset/Kconfig"
> >
> > source "$(OPENSBI_SRC_DIR)/lib/utils/serial/Kconfig"
> >
> > +source "$(OPENSBI_SRC_DIR)/lib/utils/stack_protector/Kconfig"
> > +
> > source "$(OPENSBI_SRC_DIR)/lib/utils/suspend/Kconfig"
> >
> > source "$(OPENSBI_SRC_DIR)/lib/utils/sys/Kconfig"
> > diff --git a/lib/utils/stack_protector/Kconfig
> > b/lib/utils/stack_protector/Kconfig
> > new file mode 100644
> > index 0000000..c1fee19
> > --- /dev/null
> > +++ b/lib/utils/stack_protector/Kconfig
> > @@ -0,0 +1,28 @@
> > +# SPDX-License-Identifier: BSD-2-Clause
> > +
> > +menu "Stack Protector Support"
> > +
> > +config STACK_PROTECTOR
> > + bool "Stack Protector buffer overflow detection"
> > + default n
> > + help
> > + This option turns on the "stack-protector" compiler feature.
> > +
> > +config STACK_PROTECTOR_STRONG
> > + bool "Strong Stack Protector"
> > + depends on STACK_PROTECTOR
> > + default n
> > + help
> > + Turn on the "stack-protector" with "-fstack-protector-strong"
> option.
> > + Like -fstack-protector but includes additional functions to be
> > + protected.
> > +
> > +config STACK_PROTECTOR_ALL
> > + bool "Almighty Stack Protector"
> > + depends on STACK_PROTECTOR
> > + default n
> > + help
> > + Turn on the "stack-protector" with "-fstack-protector-all" option.
> > + Like -fstack-protector except that all functions are protected.
> > +
> > +endmenu
> > diff --git a/lib/utils/stack_protector/objects.mk
> > b/lib/utils/stack_protector/objects.mk
> > new file mode 100644
> > index 0000000..d7563e3
> > --- /dev/null
> > +++ b/lib/utils/stack_protector/objects.mk
> > @@ -0,0 +1,18 @@
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2025
> > +Andes Technology Corporation # # Authors:
> > +# Alvin Chang <alvinga at andestech.com>
> > +#
> > +
> > +libsbiutils-objs-$(CONFIG_STACK_PROTECTOR) +=
> > +stack_protector/stack_protector.o
> > +
> > +ifeq ($(CONFIG_STACK_PROTECTOR),y)
> > +stack-protector-cflags-$(CONFIG_STACK_PROTECTOR) :=
> > +-fstack-protector
> > +stack-protector-cflags-$(CONFIG_STACK_PROTECTOR_STRONG) :=
> > +-fstack-protector-strong
> > +stack-protector-cflags-$(CONFIG_STACK_PROTECTOR_ALL) :=
> > +-fstack-protector-all else stack-protector-cflags-y :=
> > +-fno-stack-protector endif
> > diff --git a/lib/utils/stack_protector/stack_protector.c
> > b/lib/utils/stack_protector/stack_protector.c
> > new file mode 100644
> > index 0000000..3088421
> > --- /dev/null
> > +++ b/lib/utils/stack_protector/stack_protector.c
> > @@ -0,0 +1,18 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 Andes Technology Corporation
> > + *
> > + * Authors:
> > + * Alvin Chang <alvinga at andestech.com>
> > + */
> > +
> > +#include <sbi/sbi_console.h>
> > +#include <sbi/sbi_types.h>
> > +
> > +void *__stack_chk_guard = (void *)0x95B5FF5AUL;
> > +
> > +void __noreturn __stack_chk_fail(void) {
> > + sbi_panic("Stack corruption detected\n"); }
More information about the opensbi
mailing list