[RFC PATCH v3 18/22] arm64: Build the kernel with ORC information

madvenka at linux.microsoft.com madvenka at linux.microsoft.com
Wed Feb 1 23:40:32 PST 2023


From: "Madhavan T. Venkataraman" <madvenka at linux.microsoft.com>

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 <object-file>

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 <madvenka at linux.microsoft.com>
---
 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 505c8a1ccbe0..73c3f30a37c7 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 265c4461031f..a50caabdb18e 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 18734fed3bdd..4362f44aae61 100644
--- a/arch/arm64/include/asm/module.h
+++ b/arch/arm64/include/asm/module.h
@@ -6,6 +6,7 @@
 #define __ASM_MODULE_H
 
 #include <asm-generic/module.h>
+#include <asm/orc_types.h>
 
 #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 45131e354e27..bf7b55ae10ee 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -61,6 +61,7 @@
 #define RUNTIME_DISCARD_EXIT
 
 #include <asm-generic/vmlinux.lds.h>
+#include <asm-generic/orc_lookup.h>
 #include <asm/cache.h>
 #include <asm/kernel-pgtable.h>
 #include <asm/kexec.h>
@@ -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 dcbd365944f6..c980522190f7 100644
--- a/include/linux/objtool.h
+++ b/include/linux/objtool.h
@@ -31,7 +31,9 @@
 
 #ifdef CONFIG_OBJTOOL
 
+#ifndef CONFIG_ARM64
 #include <asm/asm.h>
+#endif
 
 #ifndef __ASSEMBLY__
 
diff --git a/scripts/Makefile b/scripts/Makefile
index 1575af84d557..df3e4d90f195 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 3aa384cec76b..d364871a1046 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 dcbd365944f6..c980522190f7 100644
--- a/tools/include/linux/objtool.h
+++ b/tools/include/linux/objtool.h
@@ -31,7 +31,9 @@
 
 #ifdef CONFIG_OBJTOOL
 
+#ifndef CONFIG_ARM64
 #include <asm/asm.h>
+#endif
 
 #ifndef __ASSEMBLY__
 
-- 
2.25.1




More information about the linux-arm-kernel mailing list