:p
atchew
Login
Both GCC and Clang support -fstack-protector feature, which add stack canaries to functions where stack corruption is possible. This series makes possible to use this feature in Xen. I tested this on ARM64 and it is working as intended. Tested both with GCC and Clang. It is hard to enable this feature on x86, as GCC stores stack canary in %fs:40 by default, but Xen can't use %fs for various reasons. It is possibly to change stack canary location new newer GCC versions, but this will change minimal GCC requirement, which is also hard due to various reasons. So, this series focus mostly on ARM and RISCV. Changes in v2: - Patch "xen: common: add ability to enable stack protector" was divided into two patches. - Rebase onto Andrew's patch that removes -fno-stack-protector-all - Tested on RISC-V thanks to Oleksii Kurochko - Changes in individual patches covered in their respect commit messages Volodymyr Babchuk (4): common: remove -fno-stack-protector from EMBEDDED_EXTRA_CFLAGS xen: common: add ability to enable stack protector xen: arm: enable stack protector feature xen: riscv: enable stack protector feature Config.mk | 2 +- stubdom/Makefile | 2 ++ tools/firmware/Rules.mk | 2 ++ tools/tests/x86_emulator/testcase.mk | 2 ++ xen/Makefile | 6 ++++++ xen/arch/arm/Kconfig | 1 + xen/arch/arm/setup.c | 3 +++ xen/arch/riscv/Kconfig | 1 + xen/arch/riscv/setup.c | 3 +++ xen/common/Kconfig | 17 ++++++++++++++++ xen/common/Makefile | 1 + xen/common/stack-protector.c | 10 ++++++++++ xen/include/xen/stack-protector.h | 29 ++++++++++++++++++++++++++++ 13 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 xen/common/stack-protector.c create mode 100644 xen/include/xen/stack-protector.h -- 2.47.1
This patch is preparation for making stack protector configurable. First step is to remove -fno-stack-protector flag from EMBEDDED_EXTRA_CFLAGS so separate projects (Hypervisor in this case) can enable/disable this feature by themselves. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --- Changes in v2: - New in v2 --- Config.mk | 2 +- stubdom/Makefile | 2 ++ tools/firmware/Rules.mk | 2 ++ tools/tests/x86_emulator/testcase.mk | 2 ++ xen/Makefile | 2 ++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Config.mk b/Config.mk index XXXXXXX..XXXXXXX 100644 --- a/Config.mk +++ b/Config.mk @@ -XXX,XX +XXX,XX @@ endif APPEND_LDFLAGS += $(foreach i, $(APPEND_LIB), -L$(i)) APPEND_CFLAGS += $(foreach i, $(APPEND_INCLUDES), -I$(i)) -EMBEDDED_EXTRA_CFLAGS := -fno-pie -fno-stack-protector +EMBEDDED_EXTRA_CFLAGS := -fno-pie EMBEDDED_EXTRA_CFLAGS += -fno-exceptions -fno-asynchronous-unwind-tables XEN_EXTFILES_URL ?= https://xenbits.xen.org/xen-extfiles diff --git a/stubdom/Makefile b/stubdom/Makefile index XXXXXXX..XXXXXXX 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -XXX,XX +XXX,XX @@ TARGET_CFLAGS += $(CFLAGS) TARGET_CPPFLAGS += $(CPPFLAGS) $(call cc-options-add,TARGET_CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS)) +$(call cc-option-add,TARGET_CFLAGS,CC,-fno-stack-protector) + # Do not use host headers and libs GCC_INSTALL = $(shell LANG=C gcc -print-search-dirs | sed -n -e 's/install: \(.*\)/\1/p') TARGET_CPPFLAGS += -U __linux__ -U __FreeBSD__ -U __sun__ diff --git a/tools/firmware/Rules.mk b/tools/firmware/Rules.mk index XXXXXXX..XXXXXXX 100644 --- a/tools/firmware/Rules.mk +++ b/tools/firmware/Rules.mk @@ -XXX,XX +XXX,XX @@ $(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS)) $(call cc-option-add,CFLAGS,CC,-fcf-protection=none) +$(call cc-option-add,CFLAGS,CC,-fno-stack-protector) + # Do not add the .note.gnu.property section to any of the firmware objects: it # breaks the rombios binary and is not useful for firmware anyway. $(call cc-option-add,CFLAGS,CC,-Wa$$(comma)-mx86-used-note=no) diff --git a/tools/tests/x86_emulator/testcase.mk b/tools/tests/x86_emulator/testcase.mk index XXXXXXX..XXXXXXX 100644 --- a/tools/tests/x86_emulator/testcase.mk +++ b/tools/tests/x86_emulator/testcase.mk @@ -XXX,XX +XXX,XX @@ include $(XEN_ROOT)/tools/Rules.mk $(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS)) +$(call cc-option-add,CFLAGS,CC,-fno-stack-protector) + CFLAGS += -fno-builtin -g0 $($(TESTCASE)-cflags) LDFLAGS_DIRECT += $(shell { $(LD) -v --warn-rwx-segments; } >/dev/null 2>&1 && echo --no-warn-rwx-segments) diff --git a/xen/Makefile b/xen/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -XXX,XX +XXX,XX @@ else CFLAGS_UBSAN := endif +CFLAGS += -fno-stack-protector + ifeq ($(CONFIG_LTO),y) CFLAGS += -flto LDFLAGS-$(CONFIG_CC_IS_CLANG) += -plugin LLVMgold.so -- 2.47.1
Both GCC and Clang support -fstack-protector feature, which add stack canaries to functions where stack corruption is possible. This patch makes general preparations to enable this feature on different supported architectures: - Added CONFIG_HAS_STACK_PROTECTOR option so each architecture can enable this feature individually - Added user-selectable CONFIG_STACK_PROTECTOR option - Implemented code that sets up random stack canary and a basic handler for stack protector failures Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --- Changes in v2: - Moved changes to EMBEDDED_EXTRA_CFLAGS into separate patch - Renamed stack_protector.c to stack-protector.c - Renamed stack_protector.h to stack-protector.h - Removed #ifdef CONFIG_X86 in stack-protector.h - Updated comment in stack-protector.h (also, we can't call boot_stack_chk_guard_setup() from asm code in general case, because it calls get_random() and get_random() may depend in per_cpu infrastructure, which is initialized later) - Fixed coding style - Moved CONFIG_STACK_PROTECTOR into newly added "Compiler options" submenu - Marked __stack_chk_guard as __ro_after_init --- xen/Makefile | 4 ++++ xen/common/Kconfig | 17 +++++++++++++++++ xen/common/Makefile | 1 + xen/common/stack-protector.c | 10 ++++++++++ xen/include/xen/stack-protector.h | 29 +++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 xen/common/stack-protector.c create mode 100644 xen/include/xen/stack-protector.h diff --git a/xen/Makefile b/xen/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -XXX,XX +XXX,XX @@ else CFLAGS_UBSAN := endif +ifeq ($(CONFIG_STACK_PROTECTOR),y) +CFLAGS += -fstack-protector +else CFLAGS += -fno-stack-protector +endif ifeq ($(CONFIG_LTO),y) CFLAGS += -flto diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config HAS_UBSAN config HAS_VMAP bool +config HAS_STACK_PROTECTOR + bool + config MEM_ACCESS_ALWAYS_ON bool @@ -XXX,XX +XXX,XX @@ config SPECULATIVE_HARDEN_LOCK endmenu +menu "Compiler options" + +config STACK_PROTECTOR + bool "Stack protection" + depends on HAS_STACK_PROTECTOR + help + Use compiler's option -fstack-protector (supported both by GCC + and Clang) to generate code that checks for corrupted stack + and halts the system in case of any problems. + + Please note that this option will impair performance. + +endmenu + config DIT_DEFAULT bool "Data Independent Timing default" depends on HAS_DIT diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += shutdown.o obj-y += softirq.o obj-y += smp.o obj-y += spinlock.o +obj-$(CONFIG_STACK_PROTECTOR) += stack-protector.o obj-y += stop_machine.o obj-y += symbols.o obj-y += tasklet.o diff --git a/xen/common/stack-protector.c b/xen/common/stack-protector.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/stack-protector.c @@ -XXX,XX +XXX,XX @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <xen/lib.h> +#include <xen/random.h> + +unsigned long __ro_after_init __stack_chk_guard; + +void __stack_chk_fail(void) +{ + panic("Detected stack corruption\n"); +} diff --git a/xen/include/xen/stack-protector.h b/xen/include/xen/stack-protector.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/stack-protector.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XEN__STACK_PROTECTOR_H +#define XEN__STACK_PROTECTOR_H + +#ifdef CONFIG_STACKPROTECTOR + +extern unsigned long __stack_chk_guard; + +/* + * This function should be always inlined. Also it should be called + * from a function that never returns or a function that with + * stack-protector disabled. + */ +static always_inline void boot_stack_chk_guard_setup(void) +{ + __stack_chk_guard = get_random(); + if (BITS_PER_LONG == 64) + __stack_chk_guard |= ((unsigned long)get_random()) << 32; +} + +#else + +static inline void boot_stack_chk_guard_setup(void) {} + +#endif /* CONFIG_STACKPROTECTOR */ + +#endif /* XEN__STACK_PROTECTOR_H */ + -- 2.47.1
Enable previously added CONFIG_STACK_PROTECTOR feature for ARM platform. Here we can call boot_stack_chk_guard_setup() in start_xen() function, because it never returns, so stack protector code will not be triggered because of changed canary. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --- In v2: - Reordered Kconfig entry --- xen/arch/arm/Kconfig | 1 + xen/arch/arm/setup.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config ARM select HAS_ALTERNATIVE if HAS_VMAP select HAS_DEVICE_TREE select HAS_PASSTHROUGH + select HAS_STACK_PROTECTOR select HAS_UBSAN select IOMMU_FORCE_PT_SHARE diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/domain_page.h> #include <xen/grant_table.h> #include <xen/types.h> +#include <xen/stack-protector.h> #include <xen/string.h> #include <xen/serial.h> #include <xen/sched.h> @@ -XXX,XX +XXX,XX @@ void asmlinkage __init start_xen(unsigned long fdt_paddr) */ system_state = SYS_STATE_boot; + boot_stack_chk_guard_setup(); + if ( acpi_disabled ) { printk("Booting using Device Tree\n"); -- 2.47.1
Enable previously added CONFIG_STACK_PROTECTOR feature for RISC-V platform. Here we can call boot_stack_chk_guard_setup() in start_xen() function, because it never returns, so stack protector code will not be triggered because of changed canary. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> Tested-by: Oleksii Kurochko <oleksii.kurochko@gmail.com> --- In v2: - Reordered Kconfig entry - Added Oleksii's Tested-by tag --- xen/arch/riscv/Kconfig | 1 + xen/arch/riscv/setup.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/xen/arch/riscv/Kconfig b/xen/arch/riscv/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/Kconfig +++ b/xen/arch/riscv/Kconfig @@ -XXX,XX +XXX,XX @@ config RISCV select GENERIC_BUG_FRAME select HAS_DEVICE_TREE select HAS_PMAP + select HAS_STACK_PROTECTOR select HAS_VMAP config RISCV_64 diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/init.h> #include <xen/mm.h> #include <xen/shutdown.h> +#include <xen/stack-protector.h> #include <xen/vmap.h> #include <public/version.h> @@ -XXX,XX +XXX,XX @@ void __init noreturn start_xen(unsigned long bootcpu_id, if ( !boot_fdt_info(device_tree_flattened, dtb_addr) ) BUG(); + boot_stack_chk_guard_setup(); + cmdline = boot_fdt_cmdline(device_tree_flattened); printk("Command line: %s\n", cmdline); cmdline_parse(cmdline); -- 2.47.1
Both GCC and Clang support -fstack-protector feature, which add stack canaries to functions where stack corruption is possible. This series makes possible to use this feature in Xen. I tested this on ARM64 and it is working as intended. Tested both with GCC and Clang. It is hard to enable this feature on x86, as GCC stores stack canary in %fs:40 by default, but Xen can't use %fs for various reasons. It is possibly to change stack canary location new newer GCC versions, but this will change minimal GCC requirement, which is also hard due to various reasons. So, this series focus mostly on ARM and RISCV. Changes in v3: - Removed patch for riscv - Changes in individual patches are covered in their respect commit messages Changes in v2: - Patch "xen: common: add ability to enable stack protector" was divided into two patches. - Rebase onto Andrew's patch that removes -fno-stack-protector-all - Tested on RISC-V thanks to Oleksii Kurochko - Changes in individual patches covered in their respect commit messages Volodymyr Babchuk (3): common: remove -fno-stack-protector from EMBEDDED_EXTRA_CFLAGS xen: common: add ability to enable stack protector xen: arm: enable stack protector feature Config.mk | 2 +- stubdom/Makefile | 3 ++ tools/firmware/Rules.mk | 2 ++ tools/tests/x86_emulator/testcase.mk | 2 +- xen/Makefile | 6 ++++ xen/arch/arm/Kconfig | 1 + xen/arch/arm/arm64/head.S | 3 ++ xen/arch/arm/setup.c | 3 ++ xen/common/Kconfig | 15 +++++++++ xen/common/Makefile | 1 + xen/common/stack-protector.c | 47 ++++++++++++++++++++++++++++ xen/include/asm-generic/random.h | 5 +++ xen/include/xen/stack-protector.h | 30 ++++++++++++++++++ 13 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 xen/common/stack-protector.c create mode 100644 xen/include/xen/stack-protector.h -- 2.47.1
This patch is preparation for making stack protector configurable. First step is to remove -fno-stack-protector flag from EMBEDDED_EXTRA_CFLAGS so separate components (Hypervisor in this case) can enable/disable this feature by themselves. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --- Changes in v3: - Reword commit message - Use CFLAGS += instead of cc-optios-add Changes in v2: - New in v2 --- Config.mk | 2 +- stubdom/Makefile | 3 +++ tools/firmware/Rules.mk | 2 ++ tools/tests/x86_emulator/testcase.mk | 2 +- xen/Makefile | 2 ++ 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Config.mk b/Config.mk index XXXXXXX..XXXXXXX 100644 --- a/Config.mk +++ b/Config.mk @@ -XXX,XX +XXX,XX @@ endif APPEND_LDFLAGS += $(foreach i, $(APPEND_LIB), -L$(i)) APPEND_CFLAGS += $(foreach i, $(APPEND_INCLUDES), -I$(i)) -EMBEDDED_EXTRA_CFLAGS := -fno-pie -fno-stack-protector +EMBEDDED_EXTRA_CFLAGS := -fno-pie EMBEDDED_EXTRA_CFLAGS += -fno-exceptions -fno-asynchronous-unwind-tables XEN_EXTFILES_URL ?= https://xenbits.xen.org/xen-extfiles diff --git a/stubdom/Makefile b/stubdom/Makefile index XXXXXXX..XXXXXXX 100644 --- a/stubdom/Makefile +++ b/stubdom/Makefile @@ -XXX,XX +XXX,XX @@ export debug=y # Moved from config/StdGNU.mk CFLAGS += -O1 -fno-omit-frame-pointer +CFLAGS += -fno-stack-protector + ifeq (,$(findstring clean,$(MAKECMDGOALS))) ifeq ($(wildcard $(MINI_OS)/Config.mk),) $(error Please run 'make mini-os-dir' in top-level directory) @@ -XXX,XX +XXX,XX @@ TARGET_CFLAGS += $(CFLAGS) TARGET_CPPFLAGS += $(CPPFLAGS) $(call cc-options-add,TARGET_CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS)) + # Do not use host headers and libs GCC_INSTALL = $(shell LANG=C gcc -print-search-dirs | sed -n -e 's/install: \(.*\)/\1/p') TARGET_CPPFLAGS += -U __linux__ -U __FreeBSD__ -U __sun__ diff --git a/tools/firmware/Rules.mk b/tools/firmware/Rules.mk index XXXXXXX..XXXXXXX 100644 --- a/tools/firmware/Rules.mk +++ b/tools/firmware/Rules.mk @@ -XXX,XX +XXX,XX @@ ifneq ($(debug),y) CFLAGS += -DNDEBUG endif +CFLAGS += -fno-stack-protector + $(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS)) $(call cc-option-add,CFLAGS,CC,-fcf-protection=none) diff --git a/tools/tests/x86_emulator/testcase.mk b/tools/tests/x86_emulator/testcase.mk index XXXXXXX..XXXXXXX 100644 --- a/tools/tests/x86_emulator/testcase.mk +++ b/tools/tests/x86_emulator/testcase.mk @@ -XXX,XX +XXX,XX @@ include $(XEN_ROOT)/tools/Rules.mk $(call cc-options-add,CFLAGS,CC,$(EMBEDDED_EXTRA_CFLAGS)) -CFLAGS += -fno-builtin -g0 $($(TESTCASE)-cflags) +CFLAGS += -fno-builtin -fno-stack-protector -g0 $($(TESTCASE)-cflags) LDFLAGS_DIRECT += $(shell { $(LD) -v --warn-rwx-segments; } >/dev/null 2>&1 && echo --no-warn-rwx-segments) diff --git a/xen/Makefile b/xen/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -XXX,XX +XXX,XX @@ else CFLAGS_UBSAN := endif +CFLAGS += -fno-stack-protector + ifeq ($(CONFIG_LTO),y) CFLAGS += -flto LDFLAGS-$(CONFIG_CC_IS_CLANG) += -plugin LLVMgold.so -- 2.47.1
Both GCC and Clang support -fstack-protector feature, which add stack canaries to functions where stack corruption is possible. This patch makes general preparations to enable this feature on different supported architectures: - Added CONFIG_HAS_STACK_PROTECTOR option so each architecture can enable this feature individually - Added user-selectable CONFIG_STACK_PROTECTOR option - Implemented code that sets up random stack canary and a basic handler for stack protector failures Stack guard value is initialized in three phases: 1. Pre-defined randomly-selected value. 2. Early use of linear congruent random number generator. It relies on get_cycles() being available very early. If get_cycles() returns zero, it would leave pre-defined value from the previous step. Even when get_cycles() is available, it's return value may be easily predicted, especially on embedded systems, where boot time is quite consistent. 3. After hypervisor is sufficiently initialized, stack guard can be set-up with get_random() function, which is expected to provide better randomness. Also this patch adds comment to asm-generic/random.h about stack protector dependency on it. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --- Changes in v3: - Fixed coding style in stack-protector.h - Extended panic() message - Included missed random.h - Renamed Kconfig option - Used Andrew's suggestion for the Kconfig help text - Added "asmlinkage" attribute to __stack_chk_fail() to make Eclair happy - Initial stack guard value is random - Added LCG to generate stack guard value at early boot stages - Added comment to asm-generic/random.h about dependencies - Extended the commit message Changes in v2: - Moved changes to EMBEDDED_EXTRA_CFLAGS into separate patch - Renamed stack_protector.c to stack-protector.c - Renamed stack_protector.h to stack-protector.h - Removed #ifdef CONFIG_X86 in stack-protector.h - Updated comment in stack-protector.h (also, we can't call boot_stack_chk_guard_setup() from asm code in general case, because it calls get_random() and get_random() may depend in per_cpu infrastructure, which is initialized later) - Fixed coding style - Moved CONFIG_STACK_PROTECTOR into newly added "Compiler options" submenu - Marked __stack_chk_guard as __ro_after_init --- xen/Makefile | 4 +++ xen/common/Kconfig | 15 ++++++++++ xen/common/Makefile | 1 + xen/common/stack-protector.c | 47 +++++++++++++++++++++++++++++++ xen/include/asm-generic/random.h | 5 ++++ xen/include/xen/stack-protector.h | 30 ++++++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 xen/common/stack-protector.c create mode 100644 xen/include/xen/stack-protector.h diff --git a/xen/Makefile b/xen/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -XXX,XX +XXX,XX @@ else CFLAGS_UBSAN := endif +ifeq ($(CONFIG_STACK_PROTECTOR),y) +CFLAGS += -fstack-protector +else CFLAGS += -fno-stack-protector +endif ifeq ($(CONFIG_LTO),y) CFLAGS += -flto diff --git a/xen/common/Kconfig b/xen/common/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -XXX,XX +XXX,XX @@ config HAS_UBSAN config HAS_VMAP bool +config HAS_STACK_PROTECTOR + bool + config MEM_ACCESS_ALWAYS_ON bool @@ -XXX,XX +XXX,XX @@ config SPECULATIVE_HARDEN_LOCK endmenu +menu "Compiler options" + +config STACK_PROTECTOR + bool "Stack protector" + depends on HAS_STACK_PROTECTOR + help + Enable the Stack Protector compiler hardening option. This inserts a + canary value in the stack frame of functions, and performs an integrity + check on exit. + +endmenu + config DIT_DEFAULT bool "Data Independent Timing default" depends on HAS_DIT diff --git a/xen/common/Makefile b/xen/common/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -XXX,XX +XXX,XX @@ obj-y += shutdown.o obj-y += softirq.o obj-y += smp.o obj-y += spinlock.o +obj-$(CONFIG_STACK_PROTECTOR) += stack-protector.o obj-y += stop_machine.o obj-y += symbols.o obj-y += tasklet.o diff --git a/xen/common/stack-protector.c b/xen/common/stack-protector.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/common/stack-protector.c @@ -XXX,XX +XXX,XX @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/random.h> +#include <xen/time.h> + +/* + * Initial value is chosen by a fair dice roll. + * It will be updated during boot process. + */ +#if BITS_PER_LONG == 32 +unsigned long __ro_after_init __stack_chk_guard = 0xdd2cc927UL; +#else +unsigned long __ro_after_init __stack_chk_guard = 0x2d853605a4d9a09cUL; +#endif + +/* This function should be called from ASM only */ +void __init asmlinkage boot_stack_chk_guard_setup_early(void) +{ + /* + * Linear congruent generator (X_n+1 = X_n * a + c). + * + * Constant is taken from "Tables Of Linear Congruential + * Generators Of Different Sizes And Good Lattice Structure" by + * Pierre L’Ecuyer. + */ +#if BITS_PER_LONG == 32 + const unsigned long a = 2891336453UL; +#else + const unsigned long a = 2862933555777941757UL; +#endif + const unsigned long c = 1; + + unsigned long cycles = get_cycles(); + + /* Use the initial value if we can't generate random one */ + if ( !cycles ) + return; + + __stack_chk_guard = cycles * a + c; +} + +void asmlinkage __stack_chk_fail(void) +{ + panic("Stack Protector integrity violation identified in %ps\n", + __builtin_return_address(0)); +} diff --git a/xen/include/asm-generic/random.h b/xen/include/asm-generic/random.h index XXXXXXX..XXXXXXX 100644 --- a/xen/include/asm-generic/random.h +++ b/xen/include/asm-generic/random.h @@ -XXX,XX +XXX,XX @@ #ifndef __ASM_GENERIC_RANDOM_H__ #define __ASM_GENERIC_RANDOM_H__ +/* + * When implementing arch_get_random(), please make sure that + * it can provide random data before stack protector is initialized + * (i.e. before boot_stack_chk_guard_setup() is called). + */ static inline unsigned int arch_get_random(void) { return 0; diff --git a/xen/include/xen/stack-protector.h b/xen/include/xen/stack-protector.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/include/xen/stack-protector.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XEN__STACK_PROTECTOR_H +#define XEN__STACK_PROTECTOR_H + +#ifdef CONFIG_STACK_PROTECTOR + +#include <xen/random.h> + +extern unsigned long __stack_chk_guard; + +/* + * This function should be always inlined. Also it should be called + * from a function that never returns or a function that has + * stack-protector disabled. + */ +static always_inline void boot_stack_chk_guard_setup(void) +{ + __stack_chk_guard = get_random(); + if (BITS_PER_LONG == 64) + __stack_chk_guard |= ((unsigned long)get_random()) << 32; +} + +#else + +static inline void boot_stack_chk_guard_setup(void) {} + +#endif /* CONFIG_STACK_PROTECTOR */ + +#endif /* XEN__STACK_PROTECTOR_H */ -- 2.47.1
Enable previously added CONFIG_STACK_PROTECTOR feature for ARM platform. We initialize stack protector in two stages: from head.S using boot_stack_chk_guard_setup_early() function and from start_xen() using boot_stack_chk_guard_setup(). This ensures that all C code from the very beginning can use stack protector. We call boot_stack_chk_guard_setup() only after time subsystem was initialized to make sure that generic random number generator will be working properly. Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com> --- In v3: - Call boot_stack_chk_guard_setup_early from head.S to ensure that stack is protected from early boot stages - Call boot_stack_chk_guard_setup() later, when time subsystem is sufficiently initialized to provide values for the random number generator. In v2: - Reordered Kconfig entry --- xen/arch/arm/Kconfig | 1 + xen/arch/arm/arm64/head.S | 3 +++ xen/arch/arm/setup.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -XXX,XX +XXX,XX @@ config ARM select HAS_ALTERNATIVE if HAS_VMAP select HAS_DEVICE_TREE select HAS_PASSTHROUGH + select HAS_STACK_PROTECTOR select HAS_UBSAN select IOMMU_FORCE_PT_SHARE diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -XXX,XX +XXX,XX @@ real_start_efi: #endif PRINT("- Boot CPU booting -\r\n") +#ifdef CONFIG_STACK_PROTECTOR + bl boot_stack_chk_guard_setup_early +#endif bl check_cpu_mode bl cpu_init diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -XXX,XX +XXX,XX @@ #include <xen/domain_page.h> #include <xen/grant_table.h> #include <xen/types.h> +#include <xen/stack-protector.h> #include <xen/string.h> #include <xen/serial.h> #include <xen/sched.h> @@ -XXX,XX +XXX,XX @@ void asmlinkage __init start_xen(unsigned long fdt_paddr) preinit_xen_time(); + boot_stack_chk_guard_setup(); + gic_preinit(); uart_init(); -- 2.47.1