From ca2c0049a2a5cd36b46a70c190df8633ad5256e6 Mon Sep 17 00:00:00 2001 From: "Madhavan T. Venkataraman" Date: Sun, 29 Jan 2023 12:54:06 -0600 Subject: [PATCH] arm64: Build the kernel with ORC information Add code to scripts/Makefile.lib to define objtool options to generate ORC data for frame pointer validation. Define kernel configs: - to enable dynamic FRAME_POINTER_VALIDATION - to enable the generation of ORC data using objtool When these configs are enabled, objtool is invoked on relocatable files during kernel build with the following command: objtool --stackval --orc Objtool creates special sections in the object files: .orc_unwind_ip PC array. .orc_unwind ORC structure table. .orc_lookup ORC lookup table. Change arch/arm64/kernel/vmlinux.lds.S to include ORC_UNWIND_TABLE in the data section so that the special sections get included there. For modules, these sections will be added to the kernel during module load. In the future, the kernel can use these sections to find the ORC for a given instruction address. The unwinder can then compute the FP at an instruction address and validate the actual FP with that. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/Kconfig | 2 ++ arch/arm64/Kconfig.debug | 32 ++++++++++++++++++++++++++++++++ arch/arm64/include/asm/module.h | 12 +++++++++++- arch/arm64/kernel/vmlinux.lds.S | 3 +++ include/linux/objtool.h | 2 ++ scripts/Makefile | 4 +++- scripts/Makefile.lib | 9 +++++++++ tools/include/linux/objtool.h | 2 ++ 8 files changed, 64 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 505c8a1ccbe0cd..73c3f30a37c776 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -230,6 +230,8 @@ config ARM64 select TRACE_IRQFLAGS_SUPPORT select TRACE_IRQFLAGS_NMI_SUPPORT select HAVE_SOFTIRQ_ON_OWN_STACK + select HAVE_STACK_VALIDATION if FRAME_POINTER_VALIDATION + select STACK_VALIDATION if HAVE_STACK_VALIDATION help ARM 64-bit (AArch64) Linux support. diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index 265c4461031f4d..a50caabdb18ec8 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -20,4 +20,36 @@ config ARM64_RELOC_TEST depends on m tristate "Relocation testing module" +config UNWINDER_ORC + bool "ORC unwinder" + depends on FRAME_POINTER_VALIDATION + select HAVE_MOD_ARCH_SPECIFIC + select OBJTOOL + help + This option enables ORC (Oops Rewind Capability) for ARM64. This + allows the unwinder to look up ORC data for an instruction address + and compute the frame pointer at that address. The computed frame + pointer is used to validate the actual frame pointer. + +config UNWINDER_FRAME_POINTER + bool "Frame pointer unwinder" + depends on FRAME_POINTER_VALIDATION + select FRAME_POINTER + help + ARM64 already uses the frame pointer for unwinding kernel stack + traces. We need to enable this config to enable STACK_VALIDATION. + STACK_VALIDATION is needed to get objtool to do static analysis + of kernel code. + +config FRAME_POINTER_VALIDATION + bool "Dynamic Frame pointer validation" + select UNWINDER_FRAME_POINTER + select UNWINDER_ORC + help + This invokes objtool on every object file causing it to + generate ORC data for the object file. ORC data is in a custom + data format which is a simplified version of the DWARF + Call Frame Information standard. See UNWINDER_ORC for more + details. + source "drivers/hwtracing/coresight/Kconfig" diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index 18734fed3bdd76..4362f44aae61ee 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -6,6 +6,7 @@ #define __ASM_MODULE_H #include +#include #ifdef CONFIG_ARM64_MODULE_PLTS struct mod_plt_sec { @@ -13,15 +14,24 @@ struct mod_plt_sec { int plt_num_entries; int plt_max_entries; }; +#endif +#ifdef CONFIG_HAVE_MOD_ARCH_SPECIFIC struct mod_arch_specific { +#ifdef CONFIG_ARM64_MODULE_PLTS struct mod_plt_sec core; struct mod_plt_sec init; /* for CONFIG_DYNAMIC_FTRACE */ struct plt_entry *ftrace_trampolines; -}; #endif +#ifdef CONFIG_UNWINDER_ORC + unsigned int num_orcs; + int *orc_unwind_ip; + struct orc_entry *orc_unwind; +#endif +}; +#endif /* CONFIG_HAVE_MOD_ARCH_SPECIFIC */ u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, void *loc, const Elf64_Rela *rela, diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 45131e354e27f1..bf7b55ae10eef1 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -61,6 +61,7 @@ #define RUNTIME_DISCARD_EXIT #include +#include #include #include #include @@ -294,6 +295,8 @@ SECTIONS __mmuoff_data_end = .; } + ORC_UNWIND_TABLE + PECOFF_EDATA_PADDING __pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin); _edata = .; diff --git a/include/linux/objtool.h b/include/linux/objtool.h index dcbd365944f696..c980522190f71c 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -31,7 +31,9 @@ #ifdef CONFIG_OBJTOOL +#ifndef CONFIG_ARM64 #include +#endif #ifndef __ASSEMBLY__ diff --git a/scripts/Makefile b/scripts/Makefile index 1575af84d557bd..df3e4d90f195e6 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -23,8 +23,10 @@ HOSTLDLIBS_sign-file = $(shell $(HOSTPKG_CONFIG) --libs libcrypto 2> /dev/null | ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) ARCH := x86 -endif HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/x86/include +else +HOSTCFLAGS_sorttable.o += -I$(srctree)/tools/arch/$(ARCH)/include +endif HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 3aa384cec76b8b..d364871a1046b2 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -252,6 +252,13 @@ ifdef CONFIG_OBJTOOL objtool := $(objtree)/tools/objtool/objtool +ifdef CONFIG_FRAME_POINTER_VALIDATION + +objtool-args-$(CONFIG_STACK_VALIDATION) += --stackval +objtool-args-$(CONFIG_UNWINDER_ORC) += --orc + +else + objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr objtool-args-$(CONFIG_X86_KERNEL_IBT) += --ibt @@ -265,6 +272,8 @@ objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE) += --static-call objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION) += --uaccess objtool-args-$(CONFIG_GCOV_KERNEL) += --no-unreachable +endif + objtool-args = $(objtool-args-y) \ $(if $(delay-objtool), --link) \ $(if $(part-of-module), --module) diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index dcbd365944f696..c980522190f71c 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -31,7 +31,9 @@ #ifdef CONFIG_OBJTOOL +#ifndef CONFIG_ARM64 #include +#endif #ifndef __ASSEMBLY__