Changes since v3 (https://lore.kernel.org/cover.1750980516.git.jpoim...@kernel.org):
- Get rid of the SHF_MERGE+SHF_WRITE toolchain shenanigans in favor of simple .discard.annotate_data annotations - Fix potential double free in elf_create_reloc() - Sync interval_tree_generic.h (Peter) - Refactor prefix symbol creation error handling - Rebase on tip/master and fix new issue (--checksum getting added with --noabs) (v3..v4 diff below) ---- This series introduces new objtool features and a klp-build script to generate livepatch modules using a source .patch as input. This builds on concepts from the longstanding out-of-tree kpatch [1] project which began in 2012 and has been used for many years to generate livepatch modules for production kernels. However, this is a complete rewrite which incorporates hard-earned lessons from 12+ years of maintaining kpatch. Key improvements compared to kpatch-build: - Integrated with objtool: Leverages objtool's existing control-flow graph analysis to help detect changed functions. - Works on vmlinux.o: Supports late-linked objects, making it compatible with LTO, IBT, and similar. - Simplified code base: ~3k fewer lines of code. - Upstream: No more out-of-tree #ifdef hacks, far less cruft. - Cleaner internals: Vastly simplified logic for symbol/section/reloc inclusion and special section extraction. - Robust __LINE__ macro handling: Avoids false positive binary diffs caused by the __LINE__ macro by introducing a fix-patch-lines script which injects #line directives into the source .patch to preserve the original line numbers at compile time. The primary user interface is the klp-build script which does the following: - Builds an original kernel with -function-sections and -fdata-sections, plus objtool function checksumming. - Applies the .patch file and rebuilds the kernel using the same options. - Runs 'objtool klp diff' to detect changed functions and generate intermediate binary diff objects. - Builds a kernel module which links the diff objects with some livepatch module init code (scripts/livepatch/init.c). - Finalizes the livepatch module (aka work around linker wreckage) using 'objtool klp post-link'. I've tested with a variety of patches on defconfig and Fedora-config kernels with both GCC and Clang. These patches can also be found at: git://git.kernel.org/pub/scm/linux/kernel/git/jpoimboe/linux.git klp-build-v3 Please test! [1] https://github.com/dynup/kpatch Josh Poimboeuf (63): s390/vmlinux.lds.S: Prevent thunk functions from getting placed with normal text vmlinux.lds: Unify TEXT_MAIN, DATA_MAIN, and related macros x86/module: Improve relocation error messages x86/kprobes: Remove STACK_FRAME_NON_STANDARD annotation compiler: Tweak __UNIQUE_ID() naming compiler.h: Make addressable symbols less of an eyesore elfnote: Change ELFNOTE() to use __UNIQUE_ID() kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME modpost: Ignore unresolved section bounds symbols x86/alternative: Refactor INT3 call emulation selftest interval_tree: Sync interval_tree_generic.h with tools interval_tree: Fix ITSTATIC usage for *_subtree_search() objtool: Make find_symbol_containing() less arbitrary objtool: Fix broken error handling in read_symbols() objtool: Propagate elf_truncate_section() error in elf_write() objtool: Remove error handling boilerplate objtool: Add empty symbols to the symbol tree again objtool: Fix interval tree insertion for zero-length symbols objtool: Fix weak symbol detection objtool: Fix x86 addend calculation objtool: Fix __pa_symbol() relocation handling objtool: Fix "unexpected end of section" warning for alternatives objtool: Check for missing annotation entries in read_annotate() objtool: Const string cleanup objtool: Clean up compiler flag usage objtool: Remove .parainstructions reference objtool: Convert elf iterator macros to use 'struct elf' objtool: Add section/symbol type helpers objtool: Mark .cold subfunctions objtool: Fix weak symbol hole detection for .cold functions objtool: Mark prefix functions objtool: Simplify reloc offset calculation in unwind_read_hints() objtool: Avoid emptying lists for duplicate sections objtool: Rename --Werror to --werror objtool: Resurrect --backup option objtool: Reindent check_options[] objtool: Refactor add_jump_destinations() objtool: Simplify special symbol handling in elf_update_symbol() objtool: Generalize elf_create_symbol() objtool: Generalize elf_create_section() objtool: Add elf_create_data() objtool: Add elf_create_reloc() and elf_init_reloc() objtool: Add elf_create_file() objtool: Add annotype() helper objtool: Move ANNOTATE* macros to annotate.h objtool: Add ANNOTATE_DATA_SPECIAL x86/asm: Annotate special section entries objtool: Unify STACK_FRAME_NON_STANDARD entry sizes objtool/klp: Add --checksum option to generate per-function checksums objtool/klp: Add --debug-checksum=<funcs> to show per-instruction checksums objtool/klp: Introduce klp diff subcommand for diffing object files objtool/klp: Add --debug option to show cloning decisions objtool/klp: Add post-link subcommand to finalize livepatch modules objtool: Refactor prefix symbol creation code objtool: Add base objtool support for livepatch modules livepatch: Add CONFIG_KLP_BUILD kbuild,objtool: Defer objtool validation step for CONFIG_KLP_BUILD livepatch/klp-build: Introduce fix-patch-lines script to avoid __LINE__ diff noise livepatch/klp-build: Add stub init code for livepatch modules livepatch/klp-build: Introduce klp-build script for generating livepatch modules livepatch/klp-build: Add --debug option to show cloning decisions livepatch/klp-build: Add --show-first-changed option to show function divergence livepatch: Introduce source code helpers for livepatch modules MAINTAINERS | 3 +- arch/s390/include/asm/nospec-insn.h | 2 +- arch/s390/kernel/vmlinux.lds.S | 2 +- arch/x86/Kconfig | 1 + arch/x86/include/asm/alternative.h | 4 + arch/x86/include/asm/asm.h | 5 + arch/x86/include/asm/bug.h | 1 + arch/x86/include/asm/cpufeature.h | 1 + arch/x86/include/asm/jump_label.h | 1 + arch/x86/kernel/alternative.c | 51 +- arch/x86/kernel/kprobes/opt.c | 4 - arch/x86/kernel/module.c | 15 +- include/asm-generic/vmlinux.lds.h | 40 +- include/linux/annotate.h | 134 ++ include/linux/compiler.h | 8 +- include/linux/elfnote.h | 13 +- include/linux/init.h | 3 +- include/linux/interval_tree.h | 4 + include/linux/interval_tree_generic.h | 2 +- include/linux/livepatch.h | 25 +- include/linux/livepatch_external.h | 76 + include/linux/livepatch_helpers.h | 77 + include/linux/mm.h | 2 + include/linux/objtool.h | 96 +- include/linux/objtool_types.h | 2 + kernel/livepatch/Kconfig | 12 + kernel/livepatch/core.c | 8 +- scripts/Makefile.lib | 7 +- scripts/Makefile.vmlinux_o | 2 +- scripts/link-vmlinux.sh | 3 +- scripts/livepatch/fix-patch-lines | 79 + scripts/livepatch/init.c | 108 ++ scripts/livepatch/klp-build | 827 ++++++++ scripts/mod/modpost.c | 5 + scripts/module.lds.S | 22 +- tools/include/linux/interval_tree_generic.h | 10 +- tools/include/linux/livepatch_external.h | 76 + tools/include/linux/objtool_types.h | 2 + tools/include/linux/string.h | 14 + tools/objtool/Build | 4 +- tools/objtool/Makefile | 48 +- tools/objtool/arch/loongarch/decode.c | 6 +- tools/objtool/arch/loongarch/orc.c | 1 - tools/objtool/arch/powerpc/decode.c | 7 +- tools/objtool/arch/x86/decode.c | 63 +- tools/objtool/arch/x86/orc.c | 1 - tools/objtool/arch/x86/special.c | 2 +- tools/objtool/builtin-check.c | 96 +- tools/objtool/builtin-klp.c | 53 + tools/objtool/check.c | 875 +++++---- tools/objtool/elf.c | 781 ++++++-- tools/objtool/include/objtool/arch.h | 5 +- tools/objtool/include/objtool/builtin.h | 11 +- tools/objtool/include/objtool/check.h | 6 +- tools/objtool/include/objtool/checksum.h | 43 + .../objtool/include/objtool/checksum_types.h | 25 + tools/objtool/include/objtool/elf.h | 196 +- tools/objtool/include/objtool/endianness.h | 9 +- tools/objtool/include/objtool/klp.h | 35 + tools/objtool/include/objtool/objtool.h | 4 +- tools/objtool/include/objtool/util.h | 19 + tools/objtool/include/objtool/warn.h | 40 + tools/objtool/klp-diff.c | 1723 +++++++++++++++++ tools/objtool/klp-post-link.c | 168 ++ tools/objtool/objtool.c | 42 +- tools/objtool/orc_dump.c | 1 - tools/objtool/orc_gen.c | 9 +- tools/objtool/special.c | 14 +- tools/objtool/sync-check.sh | 2 + tools/objtool/weak.c | 7 + 70 files changed, 5152 insertions(+), 891 deletions(-) create mode 100644 include/linux/annotate.h create mode 100644 include/linux/livepatch_external.h create mode 100644 include/linux/livepatch_helpers.h create mode 100755 scripts/livepatch/fix-patch-lines create mode 100644 scripts/livepatch/init.c create mode 100755 scripts/livepatch/klp-build create mode 100644 tools/include/linux/livepatch_external.h create mode 100644 tools/objtool/builtin-klp.c create mode 100644 tools/objtool/include/objtool/checksum.h create mode 100644 tools/objtool/include/objtool/checksum_types.h create mode 100644 tools/objtool/include/objtool/klp.h create mode 100644 tools/objtool/include/objtool/util.h create mode 100644 tools/objtool/klp-diff.c create mode 100644 tools/objtool/klp-post-link.c -- 2.50.0 diff --git a/arch/Kconfig b/arch/Kconfig index 4fb74eade61af..b13e86ad23e2f 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1368,9 +1368,6 @@ config HAVE_NOINSTR_HACK config HAVE_NOINSTR_VALIDATION bool -config NEED_MODULE_PERMISSIONS_FIX - bool - config HAVE_UACCESS_VALIDATION bool select OBJTOOL diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index 1b9b82bbe3220..b6810db24ca4d 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -5,6 +5,7 @@ generic-y += device.h generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h +generic-y += extable.h generic-y += ftrace.h generic-y += hw_irq.h generic-y += irq_regs.h diff --git a/arch/um/include/shared/common-offsets.h b/arch/um/include/shared/common-offsets.h index a6f77cb6aa7e1..8ca66a1918c3a 100644 --- a/arch/um/include/shared/common-offsets.h +++ b/arch/um/include/shared/common-offsets.h @@ -18,6 +18,3 @@ DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); DEFINE(UM_KERN_GDT_ENTRY_TLS_ENTRIES, GDT_ENTRY_TLS_ENTRIES); DEFINE(UM_SECCOMP_ARCH_NATIVE, SECCOMP_ARCH_NATIVE); - -DEFINE(ALT_INSTR_SIZE, sizeof(struct alt_instr)); -DEFINE(EXTABLE_SIZE, sizeof(struct exception_table_entry)); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 073274e35da5e..986d31587e999 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -305,7 +305,6 @@ config X86 select HOTPLUG_SPLIT_STARTUP if SMP && X86_32 select IRQ_FORCED_THREADING select LOCK_MM_AND_FIND_VMA - select NEED_MODULE_PERMISSIONS_FIX select NEED_PER_CPU_EMBED_FIRST_CHUNK select NEED_PER_CPU_PAGE_FIRST_CHUNK select NEED_SG_DMA_LENGTH diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index eb24d9ba30d7f..b14c045679e16 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -197,8 +197,8 @@ static inline int alternatives_text_reserved(void *start, void *end) "773:\n" #define ALTINSTR_ENTRY(ft_flags) \ - ".pushsection .altinstructions, \"aM\", @progbits, " \ - __stringify(ALT_INSTR_SIZE) "\n" \ + ".pushsection .altinstructions,\"a\"\n" \ + ANNOTATE_DATA_SPECIAL \ " .long 771b - .\n" /* label */ \ " .long 774f - .\n" /* new instruction */ \ " .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \ @@ -208,6 +208,7 @@ static inline int alternatives_text_reserved(void *start, void *end) #define ALTINSTR_REPLACEMENT(newinstr) /* replacement */ \ ".pushsection .altinstr_replacement, \"ax\"\n" \ + ANNOTATE_DATA_SPECIAL \ "# ALT: replacement\n" \ "774:\n\t" newinstr "\n775:\n" \ ".popsection\n" @@ -338,6 +339,7 @@ void nop_func(void); * instruction. See apply_alternatives(). */ .macro altinstr_entry orig alt ft_flags orig_len alt_len + ANNOTATE_DATA_SPECIAL .long \orig - . .long \alt - . .4byte \ft_flags @@ -361,11 +363,12 @@ void nop_func(void); 741: \ .skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;\ 742: \ - .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE ;\ + .pushsection .altinstructions,"a" ; \ altinstr_entry 740b,743f,flag,742b-740b,744f-743f ; \ .popsection ; \ .pushsection .altinstr_replacement,"ax" ; \ 743: \ + ANNOTATE_DATA_SPECIAL ; \ newinst ; \ 744: \ .popsection ; diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index ecb28d2bc6730..bd62bd87a841e 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_ASM_H #define _ASM_X86_ASM_H +#include <linux/annotate.h> + #ifdef __ASSEMBLER__ # define __ASM_FORM(x, ...) x,## __VA_ARGS__ # define __ASM_FORM_RAW(x, ...) x,## __VA_ARGS__ @@ -124,21 +126,18 @@ static __always_inline __pure void *rip_rel_ptr(void *p) #ifdef __KERNEL__ -#ifndef COMPILE_OFFSETS -#include <asm/asm-offsets.h> -#endif - # include <asm/extable_fixup_types.h> /* Exception table entry */ #ifdef __ASSEMBLER__ -# define _ASM_EXTABLE_TYPE(from, to, type) \ - .pushsection "__ex_table", "aM", @progbits, EXTABLE_SIZE; \ - .balign 4 ; \ - .long (from) - . ; \ - .long (to) - . ; \ - .long type ; \ +# define _ASM_EXTABLE_TYPE(from, to, type) \ + .pushsection "__ex_table","a" ; \ + .balign 4 ; \ + ANNOTATE_DATA_SPECIAL ; \ + .long (from) - . ; \ + .long (to) - . ; \ + .long type ; \ .popsection # ifdef CONFIG_KPROBES @@ -181,18 +180,18 @@ static __always_inline __pure void *rip_rel_ptr(void *p) ".purgem extable_type_reg\n" # define _ASM_EXTABLE_TYPE(from, to, type) \ - " .pushsection __ex_table, \"aM\", @progbits, " \ - __stringify(EXTABLE_SIZE) "\n" \ + " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + ANNOTATE_DATA_SPECIAL \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ " .long " __stringify(type) " \n" \ " .popsection\n" # define _ASM_EXTABLE_TYPE_REG(from, to, type, reg) \ - " .pushsection __ex_table, \"aM\", @progbits, " \ - __stringify(EXTABLE_SIZE) "\n" \ + " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + ANNOTATE_DATA_SPECIAL \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ DEFINE_EXTABLE_TYPE_REG \ diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index db1522fdbd108..3910db28e2f5b 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -56,7 +56,8 @@ #define _BUG_FLAGS_ASM(ins, file, line, flags, size, extra) \ "1:\t" ins "\n" \ - ".pushsection __bug_table, \"aM\", @progbits, " size "\n" \ + ".pushsection __bug_table,\"aw\"\n" \ + ANNOTATE_DATA_SPECIAL \ __BUG_ENTRY(file, line, flags) \ "\t.org 2b + " size "\n" \ ".popsection\n" \ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 893cbca37fe99..fc5f32d4da6e1 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -101,6 +101,7 @@ static __always_inline bool _static_cpu_has(u16 bit) asm goto(ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]") ".pushsection .altinstr_aux,\"ax\"\n" "6:\n" + ANNOTATE_DATA_SPECIAL " testb %[bitnum], %a[cap_byte]\n" " jnz %l[t_yes]\n" " jmp %l[t_no]\n" diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index 7a6b0e5d85c19..e0a6930a4029a 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -12,17 +12,13 @@ #include <linux/stringify.h> #include <linux/types.h> -#ifndef COMPILE_OFFSETS -#include <generated/bounds.h> -#endif - -#define JUMP_TABLE_ENTRY(key, label) \ - ".pushsection __jump_table, \"aM\", @progbits, " \ - __stringify(JUMP_ENTRY_SIZE) "\n\t" \ - _ASM_ALIGN "\n\t" \ - ".long 1b - . \n\t" \ - ".long " label " - . \n\t" \ - _ASM_PTR " " key " - . \n\t" \ +#define JUMP_TABLE_ENTRY(key, label) \ + ".pushsection __jump_table, \"aw\" \n\t" \ + _ASM_ALIGN "\n\t" \ + ANNOTATE_DATA_SPECIAL \ + ".long 1b - . \n\t" \ + ".long " label " - . \n\t" \ + _ASM_PTR " " key " - . \n\t" \ ".popsection \n\t" /* This macro is also expanded on the Rust side. */ diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h index e03ad9bbbf59d..41502bd2afd64 100644 --- a/arch/x86/include/asm/static_call.h +++ b/arch/x86/include/asm/static_call.h @@ -58,8 +58,7 @@ ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0) #define ARCH_ADD_TRAMP_KEY(name) \ - asm(".pushsection .static_call_tramp_key, \"aM\", @progbits, " \ - __stringify(STATIC_CALL_TRAMP_KEY_SIZE) "\n" \ + asm(".pushsection .static_call_tramp_key, \"a\" \n" \ ".long " STATIC_CALL_TRAMP_STR(name) " - . \n" \ ".long " STATIC_CALL_KEY_STR(name) " - . \n" \ ".popsection \n") diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 0586d237b8866..32ba599a51f88 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -124,7 +124,4 @@ static void __used common(void) OFFSET(ARIA_CTX_rounds, aria_ctx, rounds); #endif - BLANK(); - DEFINE(ALT_INSTR_SIZE, sizeof(struct alt_instr)); - DEFINE(EXTABLE_SIZE, sizeof(struct exception_table_entry)); } diff --git a/arch/x86/um/shared/sysdep/kernel-offsets.h b/arch/x86/um/shared/sysdep/kernel-offsets.h index 8215a0200ddd9..6fd1ed4003992 100644 --- a/arch/x86/um/shared/sysdep/kernel-offsets.h +++ b/arch/x86/um/shared/sysdep/kernel-offsets.h @@ -1,5 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#define COMPILE_OFFSETS #include <linux/stddef.h> #include <linux/sched.h> #include <linux/elf.h> @@ -8,7 +7,6 @@ #include <linux/audit.h> #include <asm/mman.h> #include <asm/seccomp.h> -#include <asm/extable.h> /* workaround for a warning with -Wmissing-prototypes */ void foo(void); diff --git a/include/linux/annotate.h b/include/linux/annotate.h new file mode 100644 index 0000000000000..7c10d34d198cf --- /dev/null +++ b/include/linux/annotate.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_ANNOTATE_H +#define _LINUX_ANNOTATE_H + +#include <linux/objtool_types.h> + +#ifdef CONFIG_OBJTOOL + +#ifndef __ASSEMBLY__ + +#define __ASM_ANNOTATE(section, label, type) \ + ".pushsection " section ",\"M\", @progbits, 8\n\t" \ + ".long " __stringify(label) " - .\n\t" \ + ".long " __stringify(type) "\n\t" \ + ".popsection\n\t" + +#define ASM_ANNOTATE_LABEL(label, type) \ + __ASM_ANNOTATE(".discard.annotate_insn", label, type) + +#define ASM_ANNOTATE(type) \ + "911:\n\t" \ + ASM_ANNOTATE_LABEL(911b, type) + +#define ASM_ANNOTATE_DATA(type) \ + "912:\n\t" \ + __ASM_ANNOTATE(".discard.annotate_data", 912b, type) + +#else /* __ASSEMBLY__ */ + +.macro __ANNOTATE section, type +.Lhere_\@: + .pushsection \section, "M", @progbits, 8 + .long .Lhere_\@ - . + .long \type + .popsection +.endm + +.macro ANNOTATE type + __ANNOTATE ".discard.annotate_insn", \type +.endm + +.macro ANNOTATE_DATA type + __ANNOTATE ".discard.annotate_data", \type +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_OBJTOOL */ +#ifndef __ASSEMBLY__ +#define ASM_ANNOTATE_LABEL(label, type) "" +#define ASM_ANNOTATE(type) +#define ASM_ANNOTATE_DATA(type) +#else /* __ASSEMBLY__ */ +.macro ANNOTATE type +.endm +.macro ANNOTATE_DATA type +.endm +#endif /* __ASSEMBLY__ */ +#endif /* !CONFIG_OBJTOOL */ + +#ifndef __ASSEMBLY__ + +/* + * Annotate away the various 'relocation to !ENDBR` complaints; knowing that + * these relocations will never be used for indirect calls. + */ +#define ANNOTATE_NOENDBR ASM_ANNOTATE(ANNOTYPE_NOENDBR) +#define ANNOTATE_NOENDBR_SYM(sym) asm(ASM_ANNOTATE_LABEL(sym, ANNOTYPE_NOENDBR)) + +/* + * This should be used immediately before an indirect jump/call. It tells + * objtool the subsequent indirect jump/call is vouched safe for retpoline + * builds. + */ +#define ANNOTATE_RETPOLINE_SAFE ASM_ANNOTATE(ANNOTYPE_RETPOLINE_SAFE) +/* + * See linux/instrumentation.h + */ +#define ANNOTATE_INSTR_BEGIN(label) ASM_ANNOTATE_LABEL(label, ANNOTYPE_INSTR_BEGIN) +#define ANNOTATE_INSTR_END(label) ASM_ANNOTATE_LABEL(label, ANNOTYPE_INSTR_END) +/* + * objtool annotation to ignore the alternatives and only consider the original + * instruction(s). + */ +#define ANNOTATE_IGNORE_ALTERNATIVE ASM_ANNOTATE(ANNOTYPE_IGNORE_ALTS) +/* + * This macro indicates that the following intra-function call is valid. + * Any non-annotated intra-function call will cause objtool to issue a warning. + */ +#define ANNOTATE_INTRA_FUNCTION_CALL ASM_ANNOTATE(ANNOTYPE_INTRA_FUNCTION_CALL) +/* + * Use objtool to validate the entry requirement that all code paths do + * VALIDATE_UNRET_END before RET. + * + * NOTE: The macro must be used at the beginning of a global symbol, otherwise + * it will be ignored. + */ +#define ANNOTATE_UNRET_BEGIN ASM_ANNOTATE(ANNOTYPE_UNRET_BEGIN) +/* + * This should be used to refer to an instruction that is considered + * terminating, like a noreturn CALL or UD2 when we know they are not -- eg + * WARN using UD2. + */ +#define ANNOTATE_REACHABLE(label) ASM_ANNOTATE_LABEL(label, ANNOTYPE_REACHABLE) +/* + * This should not be used; it annotates away CFI violations. There are a few + * valid use cases like kexec handover to the next kernel image, and there is + * no security concern there. + * + * There are also a few real issues annotated away, like EFI because we can't + * control the EFI code. + */ +#define ANNOTATE_NOCFI_SYM(sym) asm(ASM_ANNOTATE_LABEL(sym, ANNOTYPE_NOCFI)) + +/* + * Annotate a special section entry. This emables livepatch module generation + * to find and extract individual special section entries as needed. + */ +#define ANNOTATE_DATA_SPECIAL ASM_ANNOTATE_DATA(ANNOTYPE_DATA_SPECIAL) + +#else /* __ASSEMBLY__ */ +#define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR +#define ANNOTATE_RETPOLINE_SAFE ANNOTATE type=ANNOTYPE_RETPOLINE_SAFE +/* ANNOTATE_INSTR_BEGIN ANNOTATE type=ANNOTYPE_INSTR_BEGIN */ +/* ANNOTATE_INSTR_END ANNOTATE type=ANNOTYPE_INSTR_END */ +#define ANNOTATE_IGNORE_ALTERNATIVE ANNOTATE type=ANNOTYPE_IGNORE_ALTS +#define ANNOTATE_INTRA_FUNCTION_CALL ANNOTATE type=ANNOTYPE_INTRA_FUNCTION_CALL +#define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN +#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE +#define ANNOTATE_NOCFI_SYM ANNOTATE type=ANNOTYPE_NOCFI +#define ANNOTATE_DATA_SPECIAL ANNOTATE_DATA type=ANNOTYPE_DATA_SPECIAL +#endif /* __ASSEMBLY__ */ + +#endif /* _LINUX_ANNOTATE_H */ diff --git a/include/linux/interval_tree.h b/include/linux/interval_tree.h index 2b8026a399064..9d5791e9f737a 100644 --- a/include/linux/interval_tree.h +++ b/include/linux/interval_tree.h @@ -19,6 +19,10 @@ extern void interval_tree_remove(struct interval_tree_node *node, struct rb_root_cached *root); +extern struct interval_tree_node * +interval_tree_subtree_search(struct interval_tree_node *node, + unsigned long start, unsigned long last); + extern struct interval_tree_node * interval_tree_iter_first(struct rb_root_cached *root, unsigned long start, unsigned long last); diff --git a/include/linux/interval_tree_generic.h b/include/linux/interval_tree_generic.h index 1b400f26f63d6..c5a2fed49eb0d 100644 --- a/include/linux/interval_tree_generic.h +++ b/include/linux/interval_tree_generic.h @@ -77,7 +77,7 @@ ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, \ * Cond2: start <= ITLAST(node) \ */ \ \ -static ITSTRUCT * \ +ITSTATIC ITSTRUCT * \ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ { \ while (true) { \ diff --git a/include/linux/livepatch_helpers.h b/include/linux/livepatch_helpers.h index 337bee91d7daf..99d68d0773fa8 100644 --- a/include/linux/livepatch_helpers.h +++ b/include/linux/livepatch_helpers.h @@ -36,8 +36,6 @@ __PASTE(__KLP_POST_UNPATCH_PREFIX, KLP_OBJNAME) = func /* - * KLP_STATIC_CALL - * * Replace static_call() usage with this macro when create-diff-object * recommends it due to the original static call key living in a module. * diff --git a/include/linux/mm.h b/include/linux/mm.h index 1ae97a0b8ec75..69baa9a1e2cb4 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3265,6 +3265,8 @@ void vma_interval_tree_insert_after(struct vm_area_struct *node, struct rb_root_cached *root); void vma_interval_tree_remove(struct vm_area_struct *node, struct rb_root_cached *root); +struct vm_area_struct *vma_interval_tree_subtree_search(struct vm_area_struct *node, + unsigned long start, unsigned long last); struct vm_area_struct *vma_interval_tree_iter_first(struct rb_root_cached *root, unsigned long start, unsigned long last); struct vm_area_struct *vma_interval_tree_iter_next(struct vm_area_struct *node, diff --git a/include/linux/objtool.h b/include/linux/objtool.h index b5081aea3b69d..b18ab53561c99 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -2,22 +2,17 @@ #ifndef _LINUX_OBJTOOL_H #define _LINUX_OBJTOOL_H -#ifndef COMPILE_OFFSETS -#include <generated/bounds.h> -#endif - #include <linux/objtool_types.h> +#include <linux/annotate.h> #ifdef CONFIG_OBJTOOL -#include <asm/asm.h> - #ifndef __ASSEMBLY__ #define UNWIND_HINT(type, sp_reg, sp_offset, signal) \ "987: \n\t" \ - ".pushsection .discard.unwind_hints, \"M\", @progbits, "\ - __stringify(UNWIND_HINT_SIZE) "\n\t" \ + ".pushsection .discard.unwind_hints\n\t" \ + ANNOTATE_DATA_SPECIAL \ /* struct unwind_hint */ \ ".long 987b - .\n\t" \ ".short " __stringify(sp_offset) "\n\t" \ @@ -58,16 +53,6 @@ #define __ASM_BREF(label) label ## b -#define __ASM_ANNOTATE(label, type) \ - ".pushsection .discard.annotate_insn,\"M\",@progbits,8\n\t" \ - ".long " __stringify(label) " - .\n\t" \ - ".long " __stringify(type) "\n\t" \ - ".popsection\n\t" - -#define ASM_ANNOTATE(type) \ - "911:\n\t" \ - __ASM_ANNOTATE(911b, type) - #else /* __ASSEMBLY__ */ /* @@ -93,7 +78,8 @@ */ .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .Lhere_\@: - .pushsection .discard.unwind_hints, "M", @progbits, UNWIND_HINT_SIZE + .pushsection .discard.unwind_hints + ANNOTATE_DATA_SPECIAL /* struct unwind_hint */ .long .Lhere_\@ - . .short \sp_offset @@ -116,14 +102,6 @@ #endif .endm -.macro ANNOTATE type:req -.Lhere_\@: - .pushsection .discard.annotate_insn,"M",@progbits,8 - .long .Lhere_\@ - . - .long \type - .popsection -.endm - #endif /* __ASSEMBLY__ */ #else /* !CONFIG_OBJTOOL */ @@ -133,84 +111,15 @@ #define UNWIND_HINT(type, sp_reg, sp_offset, signal) "\n\t" #define STACK_FRAME_NON_STANDARD(func) #define STACK_FRAME_NON_STANDARD_FP(func) -#define __ASM_ANNOTATE(label, type) "" -#define ASM_ANNOTATE(type) #else .macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 .endm .macro STACK_FRAME_NON_STANDARD func:req .endm -.macro ANNOTATE type:req -.endm #endif #endif /* CONFIG_OBJTOOL */ -#ifndef __ASSEMBLY__ -/* - * Annotate away the various 'relocation to !ENDBR` complaints; knowing that - * these relocations will never be used for indirect calls. - */ -#define ANNOTATE_NOENDBR ASM_ANNOTATE(ANNOTYPE_NOENDBR) -#define ANNOTATE_NOENDBR_SYM(sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOENDBR)) - -/* - * This should be used immediately before an indirect jump/call. It tells - * objtool the subsequent indirect jump/call is vouched safe for retpoline - * builds. - */ -#define ANNOTATE_RETPOLINE_SAFE ASM_ANNOTATE(ANNOTYPE_RETPOLINE_SAFE) -/* - * See linux/instrumentation.h - */ -#define ANNOTATE_INSTR_BEGIN(label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_BEGIN) -#define ANNOTATE_INSTR_END(label) __ASM_ANNOTATE(label, ANNOTYPE_INSTR_END) -/* - * objtool annotation to ignore the alternatives and only consider the original - * instruction(s). - */ -#define ANNOTATE_IGNORE_ALTERNATIVE ASM_ANNOTATE(ANNOTYPE_IGNORE_ALTS) -/* - * This macro indicates that the following intra-function call is valid. - * Any non-annotated intra-function call will cause objtool to issue a warning. - */ -#define ANNOTATE_INTRA_FUNCTION_CALL ASM_ANNOTATE(ANNOTYPE_INTRA_FUNCTION_CALL) -/* - * Use objtool to validate the entry requirement that all code paths do - * VALIDATE_UNRET_END before RET. - * - * NOTE: The macro must be used at the beginning of a global symbol, otherwise - * it will be ignored. - */ -#define ANNOTATE_UNRET_BEGIN ASM_ANNOTATE(ANNOTYPE_UNRET_BEGIN) -/* - * This should be used to refer to an instruction that is considered - * terminating, like a noreturn CALL or UD2 when we know they are not -- eg - * WARN using UD2. - */ -#define ANNOTATE_REACHABLE(label) __ASM_ANNOTATE(label, ANNOTYPE_REACHABLE) -/* - * This should not be used; it annotates away CFI violations. There are a few - * valid use cases like kexec handover to the next kernel image, and there is - * no security concern there. - * - * There are also a few real issues annotated away, like EFI because we can't - * control the EFI code. - */ -#define ANNOTATE_NOCFI_SYM(sym) asm(__ASM_ANNOTATE(sym, ANNOTYPE_NOCFI)) - -#else -#define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR -#define ANNOTATE_RETPOLINE_SAFE ANNOTATE type=ANNOTYPE_RETPOLINE_SAFE -/* ANNOTATE_INSTR_BEGIN ANNOTATE type=ANNOTYPE_INSTR_BEGIN */ -/* ANNOTATE_INSTR_END ANNOTATE type=ANNOTYPE_INSTR_END */ -#define ANNOTATE_IGNORE_ALTERNATIVE ANNOTATE type=ANNOTYPE_IGNORE_ALTS -#define ANNOTATE_INTRA_FUNCTION_CALL ANNOTATE type=ANNOTYPE_INTRA_FUNCTION_CALL -#define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN -#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE -#define ANNOTATE_NOCFI_SYM ANNOTATE type=ANNOTYPE_NOCFI -#endif - #if defined(CONFIG_NOINSTR_VALIDATION) && \ (defined(CONFIG_MITIGATION_UNRET_ENTRY) || defined(CONFIG_MITIGATION_SRSO)) #define VALIDATE_UNRET_BEGIN ANNOTATE_UNRET_BEGIN diff --git a/include/linux/objtool_types.h b/include/linux/objtool_types.h index aceac94632c8a..c6def4049b1ae 100644 --- a/include/linux/objtool_types.h +++ b/include/linux/objtool_types.h @@ -67,4 +67,6 @@ struct unwind_hint { #define ANNOTYPE_REACHABLE 8 #define ANNOTYPE_NOCFI 9 +#define ANNOTYPE_DATA_SPECIAL 1 + #endif /* _LINUX_OBJTOOL_TYPES_H */ diff --git a/include/linux/static_call.h b/include/linux/static_call.h index 5210612817f2e..78a77a4ae0ea8 100644 --- a/include/linux/static_call.h +++ b/include/linux/static_call.h @@ -172,6 +172,12 @@ struct static_call_mod { struct static_call_site *sites; }; +/* For finding the key associated with a trampoline */ +struct static_call_tramp_key { + s32 tramp; + s32 key; +}; + extern void __static_call_update(struct static_call_key *key, void *tramp, void *func); extern int static_call_mod_init(struct module *mod); extern int static_call_text_reserved(void *start, void *end); diff --git a/include/linux/static_call_types.h b/include/linux/static_call_types.h index eb772df625d4e..5a00b8b2cf9fc 100644 --- a/include/linux/static_call_types.h +++ b/include/linux/static_call_types.h @@ -34,12 +34,6 @@ struct static_call_site { s32 key; }; -/* For finding the key associated with a trampoline */ -struct static_call_tramp_key { - s32 tramp; - s32 key; -}; - #define DECLARE_STATIC_CALL(name, func) \ extern struct static_call_key STATIC_CALL_KEY(name); \ extern typeof(func) STATIC_CALL_TRAMP(name); diff --git a/kernel/bounds.c b/kernel/bounds.c index f9bc13727721e..29b2cd00df2cc 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -6,16 +6,12 @@ */ #define __GENERATING_BOUNDS_H -#define COMPILE_OFFSETS /* Include headers that define the enum constants of interest */ #include <linux/page-flags.h> #include <linux/mmzone.h> #include <linux/kbuild.h> #include <linux/log2.h> #include <linux/spinlock_types.h> -#include <linux/jump_label.h> -#include <linux/static_call_types.h> -#include <linux/objtool_types.h> int main(void) { @@ -32,15 +28,6 @@ int main(void) #else DEFINE(LRU_GEN_WIDTH, 0); DEFINE(__LRU_REFS_WIDTH, 0); -#endif -#if defined(CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE) && defined(CONFIG_JUMP_LABEL) - DEFINE(JUMP_ENTRY_SIZE, sizeof(struct jump_entry)); -#endif -#ifdef CONFIG_HAVE_STATIC_CALL_INLINE - DEFINE(STATIC_CALL_TRAMP_KEY_SIZE, sizeof(struct static_call_tramp_key)); -#endif -#ifdef CONFIG_OBJTOOL - DEFINE(UNWIND_HINT_SIZE, sizeof(struct unwind_hint)); #endif /* End of constants */ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 28a1c08e3b221..f4b33919ec371 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -173,6 +173,7 @@ ifdef CONFIG_OBJTOOL objtool := $(objtree)/tools/objtool/objtool +objtool-args-$(CONFIG_KLP_BUILD) += --checksum objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) += --hacks=jump_label objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) += --hacks=noinstr objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) += --hacks=skylake diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 7a888e1ff70f2..542ba462ed3ec 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -28,24 +28,12 @@ ccflags-remove-y := $(CC_FLAGS_CFI) .module-common.o: $(srctree)/scripts/module-common.c FORCE $(call if_changed_rule,cc_o_c) -ifdef CONFIG_NEED_MODULE_PERMISSIONS_FIX -cmd_fix_mod_permissions = \ - $(OBJCOPY) --set-section-flags __jump_table=alloc,data \ - --set-section-flags __bug_table=alloc,data $@ \ - --set-section-flags .static_call_sites=alloc,data $@ -endif - quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^) -define rule_ld_ko_o - $(call cmd_and_savecmd,ld_ko_o) - $(call cmd,fix_mod_permissions) -endef - quiet_cmd_btf_ko = BTF [M] $@ cmd_btf_ko = \ if [ ! -f $(objtree)/vmlinux ]; then \ @@ -58,11 +46,14 @@ quiet_cmd_btf_ko = BTF [M] $@ # Same as newer-prereqs, but allows to exclude specified extra dependencies newer_prereqs_except = $(filter-out $(PHONY) $(1),$?) -if_changed_rule_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check),$(rule_$(1)),@:) +# Same as if_changed, but allows to exclude specified extra dependencies +if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ + $(cmd); \ + printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) # Re-generate module BTFs if either module's .ko or vmlinux changed %.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE - +$(call if_changed_rule_except,ld_ko_o,$(objtree)/vmlinux) + +$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) endif diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build index e47056f75475e..881e052e7faef 100755 --- a/scripts/livepatch/klp-build +++ b/scripts/livepatch/klp-build @@ -489,11 +489,8 @@ clean_kernel() { build_kernel() { local log="$TMP_DIR/build.log" - local objtool_args=() local cmd=() - objtool_args=("--checksum") - cmd=("make") # When a patch to a kernel module references a newly created unexported @@ -516,7 +513,6 @@ build_kernel() { cmd+=("$VERBOSE") cmd+=("-j$JOBS") cmd+=("KCFLAGS=-ffunction-sections -fdata-sections") - cmd+=("OBJTOOL_ARGS=${objtool_args[*]}") cmd+=("vmlinux") cmd+=("modules") @@ -794,7 +790,7 @@ process_args "$@" do_init if (( SHORT_CIRCUIT <= 1 )); then - status "Validating patches" + status "Validating patch(es)" validate_patches status "Building original kernel" clean_kernel @@ -804,7 +800,7 @@ if (( SHORT_CIRCUIT <= 1 )); then fi if (( SHORT_CIRCUIT <= 2 )); then - status "Fixing patches" + status "Fixing patch(es)" fix_patches apply_patches status "Building patched kernel" diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index ef2ffb68f69d1..d3d00e85edf73 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#define COMPILE_OFFSETS #include <linux/kbuild.h> #include <linux/mod_devicetable.h> diff --git a/tools/include/linux/interval_tree_generic.h b/tools/include/linux/interval_tree_generic.h index c0ec9dbdfbaf2..c5a2fed49eb0d 100644 --- a/tools/include/linux/interval_tree_generic.h +++ b/tools/include/linux/interval_tree_generic.h @@ -104,12 +104,8 @@ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ if (ITSTART(node) <= last) { /* Cond1 */ \ if (start <= ITLAST(node)) /* Cond2 */ \ return node; /* node is leftmost match */ \ - if (node->ITRB.rb_right) { \ - node = rb_entry(node->ITRB.rb_right, \ - ITSTRUCT, ITRB); \ - if (start <= node->ITSUBTREE) \ - continue; \ - } \ + node = rb_entry(node->ITRB.rb_right, ITSTRUCT, ITRB); \ + continue; \ } \ return NULL; /* No match */ \ } \ diff --git a/tools/include/linux/objtool_types.h b/tools/include/linux/objtool_types.h index aceac94632c8a..c6def4049b1ae 100644 --- a/tools/include/linux/objtool_types.h +++ b/tools/include/linux/objtool_types.h @@ -67,4 +67,6 @@ struct unwind_hint { #define ANNOTYPE_REACHABLE 8 #define ANNOTYPE_NOCFI 9 +#define ANNOTYPE_DATA_SPECIAL 1 + #endif /* _LINUX_OBJTOOL_TYPES_H */ diff --git a/tools/include/linux/static_call_types.h b/tools/include/linux/static_call_types.h index eb772df625d4e..5a00b8b2cf9fc 100644 --- a/tools/include/linux/static_call_types.h +++ b/tools/include/linux/static_call_types.h @@ -34,12 +34,6 @@ struct static_call_site { s32 key; }; -/* For finding the key associated with a trampoline */ -struct static_call_tramp_key { - s32 tramp; - s32 key; -}; - #define DECLARE_STATIC_CALL(name, func) \ extern struct static_call_key STATIC_CALL_KEY(name); \ extern typeof(func) STATIC_CALL_TRAMP(name); diff --git a/tools/objtool/arch/loongarch/orc.c b/tools/objtool/arch/loongarch/orc.c index b58c5ff443c92..ffd3a3c858ae7 100644 --- a/tools/objtool/arch/loongarch/orc.c +++ b/tools/objtool/arch/loongarch/orc.c @@ -5,7 +5,6 @@ #include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn) { diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/powerpc/decode.c index d4cb02120a6bd..3a9b748216edc 100644 --- a/tools/objtool/arch/powerpc/decode.c +++ b/tools/objtool/arch/powerpc/decode.c @@ -7,7 +7,6 @@ #include <objtool/arch.h> #include <objtool/warn.h> #include <objtool/builtin.h> -#include <objtool/endianness.h> int arch_ftrace_match(const char *name) { diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 6f3aa117027a6..5c72beeaa3a71 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -19,7 +19,6 @@ #include <objtool/elf.h> #include <objtool/arch.h> #include <objtool/warn.h> -#include <objtool/endianness.h> #include <objtool/builtin.h> #include <arch/elf.h> diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c index 7176b9ec5b058..735e150ca6b73 100644 --- a/tools/objtool/arch/x86/orc.c +++ b/tools/objtool/arch/x86/orc.c @@ -5,7 +5,6 @@ #include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn) { diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index c4e45236a561d..b20b0077449b2 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -74,7 +74,7 @@ static int parse_hacks(const struct option *opt, const char *str, int unset) static const struct option check_options[] = { OPT_GROUP("Actions:"), OPT_BOOLEAN(0, "checksum", &opts.checksum, "generate per-function checksums"), - OPT_BOOLEAN(0 , "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"), + OPT_BOOLEAN(0, "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"), OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks), OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), @@ -162,7 +162,6 @@ static bool opts_valid(void) return false; } - #ifndef BUILD_KLP if (opts.checksum) { ERROR("--checksum not supported; install xxhash-devel and recompile"); diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 2f0c86ba14a5c..ba591a325d52e 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -15,8 +15,8 @@ #include <objtool/check.h> #include <objtool/special.h> #include <objtool/warn.h> -#include <objtool/endianness.h> #include <objtool/checksum.h> +#include <objtool/util.h> #include <linux/objtool_types.h> #include <linux/hashtable.h> @@ -660,15 +660,8 @@ static int create_static_call_sections(struct objtool_file *file) if (!sec) return -1; - /* - * Set SHF_MERGE to prevent tooling from stripping entsize. - * - * SHF_WRITE would also get set here to allow modules to modify the low - * bits of static_call_site::key, but the LLVM linker doesn't allow - * SHF_MERGE+SHF_WRITE for whatever reason. That gets fixed up by the - * makefiles with CONFIG_NEED_MODULE_PERMISSIONS_FIX. - */ - sec->sh.sh_flags |= SHF_MERGE; + /* Allow modules to modify the low bits of static_call_site::key */ + sec->sh.sh_flags |= SHF_WRITE; idx = 0; list_for_each_entry(insn, &file->static_call_list, call_node) { @@ -1003,10 +996,10 @@ static int create_sym_checksum_section(struct objtool_file *file) struct sym_checksum *checksum; size_t entsize = sizeof(struct sym_checksum); - sec = find_section_by_name(file->elf, SYM_CHECKSUM_SEC); + sec = find_section_by_name(file->elf, ".discard.sym_checksum"); if (sec) { if (!opts.dryrun) - WARN("file already has " SYM_CHECKSUM_SEC " section, skipping"); + WARN("file already has .discard.sym_checksum section, skipping"); return 0; } @@ -2349,9 +2342,7 @@ static int read_annotate(struct objtool_file *file, } for_each_reloc(sec->rsec, reloc) { - type = *(u32 *)(sec->data->d_buf + (reloc_idx(reloc) * sec->sh.sh_entsize) + 4); - type = bswap_if_needed(file->elf, type); - + type = annotype(file->elf, sec, reloc); offset = reloc->sym->offset + reloc_addend(reloc); insn = find_insn(file, reloc->sym->sec, offset); @@ -4283,48 +4274,82 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio return false; } -static int add_prefix_symbol(struct objtool_file *file, struct symbol *func) +/* + * For FineIBT or kCFI, a certain number of bytes preceding the function may be + * NOPs. Those NOPs may be rewritten at runtime and executed, so give them a + * proper function name: __pfx_<func>. + * + * The NOPs may not exist for the following cases: + * + * - compiler cloned functions (*.cold, *.part0, etc) + * - asm functions created with inline asm or without SYM_FUNC_START() + * + * Also, the function may already have a prefix from a previous objtool run + * (livepatch extracted functions, or manually running objtool multiple times). + * + * So return 0 if the NOPs are missing or the function already has a prefix + * symbol. + */ +static int create_prefix_symbol(struct objtool_file *file, struct symbol *func) { struct instruction *insn, *prev; + char name[SYM_NAME_LEN]; struct cfi_state *cfi; - insn = find_insn(file, func->sec, func->offset); - if (!insn) + if (!is_func_sym(func) || is_prefix_func(func) || + func->cold || func->static_call_tramp) + return 0; + + if ((strlen(func->name) + sizeof("__pfx_") > SYM_NAME_LEN)) { + WARN("%s: symbol name too long, can't create __pfx_ symbol", + func->name); + return 0; + } + + if (snprintf_check(name, SYM_NAME_LEN, "__pfx_%s", func->name)) return -1; + if (file->klp) { + struct symbol *pfx; + + pfx = find_symbol_by_offset(func->sec, func->offset - opts.prefix); + if (pfx && is_prefix_func(pfx) && !strcmp(pfx->name, name)) + return 0; + } + + insn = find_insn(file, func->sec, func->offset); + if (!insn) { + WARN("%s: can't find starting instruction", func->name); + return -1; + } + for (prev = prev_insn_same_sec(file, insn); prev; prev = prev_insn_same_sec(file, prev)) { - struct symbol *sym_pfx; u64 offset; if (prev->type != INSN_NOP) - return -1; + return 0; offset = func->offset - prev->offset; if (offset > opts.prefix) - return -1; + return 0; if (offset < opts.prefix) continue; - /* - * Ignore attempts to make duplicate symbols in livepatch - * modules. They've already extracted the prefix symbols - * except for the newly compiled init.c. - */ - sym_pfx = elf_create_prefix_symbol(file->elf, func, opts.prefix); - if (!sym_pfx && !file->klp) { - WARN("duplicate prefix symbol for %s\n", func->name); + if (!elf_create_symbol(file->elf, name, func->sec, + GELF_ST_BIND(func->sym.st_info), + GELF_ST_TYPE(func->sym.st_info), + prev->offset, opts.prefix)) return -1; - } break; } if (!prev) - return -1; + return 0; if (!insn->cfi) { /* @@ -4342,7 +4367,7 @@ static int add_prefix_symbol(struct objtool_file *file, struct symbol *func) return 0; } -static int add_prefix_symbols(struct objtool_file *file) +static int create_prefix_symbols(struct objtool_file *file) { struct section *sec; struct symbol *func; @@ -4352,14 +4377,8 @@ static int add_prefix_symbols(struct objtool_file *file) continue; sec_for_each_sym(sec, func) { - if (!is_func_sym(func)) - continue; - - /* - * Ignore this error on purpose, there are valid - * reasons for this to fail. - */ - add_prefix_symbol(file, func); + if (create_prefix_symbol(file, func)) + return -1; } } @@ -4987,7 +5006,7 @@ int check(struct objtool_file *file) } if (opts.prefix) { - ret = add_prefix_symbols(file); + ret = create_prefix_symbols(file); if (ret) goto out; } diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 2551a5727949f..5feeefc7fc8f8 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -945,32 +945,6 @@ struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec) return sym; } -struct symbol * -elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, size_t size) -{ - size_t namelen = strlen(orig->name) + sizeof("__pfx_"); - char name[SYM_NAME_LEN]; - unsigned long offset; - struct symbol *sym; - - snprintf(name, namelen, "__pfx_%s", orig->name); - - sym = orig; - offset = orig->sym.st_value - size; - - sec_for_each_sym_continue_reverse(orig->sec, sym) { - if (sym->offset < offset) - break; - if (sym->offset == offset && !strcmp(sym->name, name)) - return NULL; - } - - return elf_create_symbol(elf, name, orig->sec, - GELF_ST_BIND(orig->sym.st_info), - GELF_ST_TYPE(orig->sym.st_info), - offset, size); -} - struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, unsigned int reloc_idx, unsigned long offset, struct symbol *sym, s64 addend, unsigned int type) @@ -1075,8 +1049,10 @@ static int read_relocs(struct elf *elf) rsec->base->rsec = rsec; - rsec->nr_alloc_relocs = sec_num_entries(rsec); - rsec->relocs = calloc(rsec->nr_alloc_relocs, sizeof(*reloc)); + /* nr_alloc_relocs=0: libelf owns d_buf */ + rsec->nr_alloc_relocs = 0; + + rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc)); if (!rsec->relocs) { ERROR_GLIBC("calloc"); return -1; @@ -1496,15 +1472,32 @@ static int elf_alloc_reloc(struct elf *elf, struct section *rsec) nr_alloc = MAX(64, ALIGN_UP_POW2(nr_relocs_new)); if (nr_alloc <= rsec->nr_alloc_relocs) return 0; - rsec->nr_alloc_relocs = nr_alloc; - rsec->data->d_buf = realloc(rsec->data->d_buf, - nr_alloc * elf_rela_size(elf)); - if (!rsec->data->d_buf) { - ERROR_GLIBC("realloc"); - return -1; + if (rsec->data->d_buf && !rsec->nr_alloc_relocs) { + void *orig_buf = rsec->data->d_buf; + + /* + * The original d_buf is owned by libelf so it can't be + * realloced. + */ + rsec->data->d_buf = malloc(nr_alloc * elf_rela_size(elf)); + if (!rsec->data->d_buf) { + ERROR_GLIBC("malloc"); + return -1; + } + memcpy(rsec->data->d_buf, orig_buf, + nr_relocs_old * elf_rela_size(elf)); + } else { + rsec->data->d_buf = realloc(rsec->data->d_buf, + nr_alloc * elf_rela_size(elf)); + if (!rsec->data->d_buf) { + ERROR_GLIBC("realloc"); + return -1; + } } + rsec->nr_alloc_relocs = nr_alloc; + old_relocs = rsec->relocs; new_relocs = calloc(nr_alloc, sizeof(struct reloc)); if (!new_relocs) { @@ -1623,6 +1616,8 @@ struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, if (elf_alloc_reloc(elf, rsec)) return NULL; + mark_sec_changed(elf, rsec, true); + return elf_init_reloc(elf, rsec, sec_num_entries(rsec) - 1, offset, sym, addend, type); } diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index 8a0d42aa4d858..bb0b25eb08ba4 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -10,6 +10,7 @@ struct opts { /* actions: */ bool cfi; + bool checksum; bool dump_orc; bool hack_jump_label; bool hack_noinstr; @@ -25,7 +26,6 @@ struct opts { bool sls; bool stackval; bool static_call; - bool checksum; bool uaccess; int prefix; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 64e75ade01c90..21d8b825fd8f0 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -14,12 +14,15 @@ #include <linux/rbtree.h> #include <linux/jhash.h> +#include <objtool/endianness.h> #include <objtool/checksum_types.h> #include <arch/elf.h> #define SEC_NAME_LEN 1024 #define SYM_NAME_LEN 512 +#define bswap_if_needed(elf, val) __bswap_if_needed(&elf->ehdr, val) + #ifdef LIBELF_USE_DEPRECATED # define elf_getshdrnum elf_getshnum # define elf_getshdrstrndx elf_getshstrndx @@ -146,8 +149,6 @@ struct symbol *elf_create_symbol(struct elf *elf, const char *name, unsigned int type, unsigned long offset, size_t size); struct symbol *elf_create_section_symbol(struct elf *elf, struct section *sec); -struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, - size_t size); void *elf_add_data(struct elf *elf, struct section *sec, const void *data, size_t size); @@ -274,7 +275,7 @@ static inline bool is_local_sym(struct symbol *sym) static inline bool is_prefix_func(struct symbol *sym) { - return is_func_sym(sym) && sym->prefix; + return sym->prefix; } static inline bool is_reloc_sec(struct section *sec) @@ -414,6 +415,15 @@ static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned mark_sec_changed(elf, reloc->sec, true); } +static inline unsigned int annotype(struct elf *elf, struct section *sec, + struct reloc *reloc) +{ + unsigned int type; + + type = *(u32 *)(sec->data->d_buf + (reloc_idx(reloc) * 8) + 4); + return bswap_if_needed(elf, type); +} + #define RELOC_JUMP_TABLE_BIT 1UL /* Does reloc mark the beginning of a jump table? */ @@ -445,9 +455,6 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next) #define sec_for_each_sym(sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) -#define sec_for_each_sym_continue_reverse(sec, sym) \ - list_for_each_entry_continue_reverse(sym, &sec->symbol_list, list) - #define sec_prev_sym(sym) \ sym->sec && sym->list.prev != &sym->sec->symbol_list ? \ list_prev_entry(sym, list) : NULL @@ -467,6 +474,10 @@ static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next) #define for_each_reloc_from(rsec, reloc) \ for (; reloc; reloc = rsec_next_reloc(rsec, reloc)) +#define for_each_reloc_continue(rsec, reloc) \ + for (reloc = rsec_next_reloc(rsec, reloc); reloc; \ + reloc = rsec_next_reloc(rsec, reloc)) + #define sym_for_each_reloc(elf, sym, reloc) \ for (reloc = find_reloc_by_dest_range(elf, sym->sec, \ sym->offset, sym->len); \ diff --git a/tools/objtool/include/objtool/endianness.h b/tools/objtool/include/objtool/endianness.h index 4d2aa9b0fe2fd..aebcd23386685 100644 --- a/tools/objtool/include/objtool/endianness.h +++ b/tools/objtool/include/objtool/endianness.h @@ -4,7 +4,6 @@ #include <linux/kernel.h> #include <endian.h> -#include <objtool/elf.h> /* * Does a byte swap if target file endianness doesn't match the host, i.e. cross @@ -12,16 +11,16 @@ * To be used for multi-byte values conversion, which are read from / about * to be written to a target native endianness ELF file. */ -static inline bool need_bswap(struct elf *elf) +static inline bool need_bswap(GElf_Ehdr *ehdr) { return (__BYTE_ORDER == __LITTLE_ENDIAN) ^ - (elf->ehdr.e_ident[EI_DATA] == ELFDATA2LSB); + (ehdr->e_ident[EI_DATA] == ELFDATA2LSB); } -#define bswap_if_needed(elf, val) \ +#define __bswap_if_needed(ehdr, val) \ ({ \ __typeof__(val) __ret; \ - bool __need_bswap = need_bswap(elf); \ + bool __need_bswap = need_bswap(ehdr); \ switch (sizeof(val)) { \ case 8: \ __ret = __need_bswap ? bswap_64(val) : (val); break; \ diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h index 731965a742e99..f7051bbe0bcb2 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -14,8 +14,6 @@ #define __weak __attribute__((weak)) -#define SYM_CHECKSUM_SEC ".discard.sym_checksum" - struct pv_state { bool clean; struct list_head targets; diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index 15b554b53da63..4d1f9e9977eb9 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -14,6 +14,7 @@ #include <objtool/util.h> #include <arch/special.h> +#include <linux/objtool_types.h> #include <linux/livepatch_external.h> #include <linux/stringify.h> #include <linux/string.h> @@ -167,15 +168,15 @@ static int read_sym_checksums(struct elf *elf) { struct section *sec; - sec = find_section_by_name(elf, SYM_CHECKSUM_SEC); + sec = find_section_by_name(elf, ".discard.sym_checksum"); if (!sec) { - ERROR("'%s' missing " SYM_CHECKSUM_SEC " section, file not processed by 'objtool --checksum'?", + ERROR("'%s' missing .discard.sym_checksum section, file not processed by 'objtool --checksum'?", elf->name); return -1; } if (!sec->rsec) { - ERROR("missing reloc section for " SYM_CHECKSUM_SEC); + ERROR("missing reloc section for .discard.sym_checksum"); return -1; } @@ -297,7 +298,7 @@ static bool is_special_section(struct section *sec) static const char * const non_special_discards[] = { ".discard.addressable", - SYM_CHECKSUM_SEC, + ".discard.sym_checksum", }; if (is_text_sec(sec)) @@ -1150,6 +1151,135 @@ static int clone_sym_relocs(struct elfs *e, struct symbol *patched_sym) } +static int create_fake_symbol(struct elf *elf, struct section *sec, + unsigned long offset, size_t size) +{ + char name[SYM_NAME_LEN]; + unsigned int type; + static int ctr; + char *c; + + if (snprintf_check(name, SYM_NAME_LEN, "%s_%d", sec->name, ctr++)) + return -1; + + for (c = name; *c; c++) + if (*c == '.') + *c = '_'; + + /* + * STT_NOTYPE: Prevent objtool from validating .altinstr_replacement + * while still allowing objdump to disassemble it. + */ + type = is_text_sec(sec) ? STT_NOTYPE : STT_OBJECT; + return elf_create_symbol(elf, name, sec, STB_LOCAL, type, offset, size) ? 0 : -1; +} + +/* + * Special sections (alternatives, etc) are basically arrays of structs. + * For all the special sections, create a symbol for each struct entry. This + * is a bit cumbersome, but it makes the extracting of the individual entries + * much more straightforward. + * + * There are three ways to identify the entry sizes for a special section: + * + * 1) ELF section header sh_entsize: Ideally this would be used almost + * everywhere. But unfortunately the toolchains make it difficult. The + * assembler .[push]section directive syntax only takes entsize when + * combined with SHF_MERGE. But Clang disallows combining SHF_MERGE with + * SHF_WRITE. And some special sections do need to be writable. + * + * Another place this wouldn't work is .altinstr_replacement, whose entries + * don't have a fixed size. + * + * 2) ANNOTATE_DATA_SPECIAL: This is a lightweight objtool annotation which + * points to the beginning of each entry. The size of the entry is then + * inferred by the location of the subsequent annotation (or end of + * section). + * + * 3) Simple array of pointers: If the special section is just a basic array of + * pointers, the entry size can be inferred by the number of relocations. + * No annotations needed. + * + * Note I also tried to create per-entry symbols at the time of creation, in + * the original [inline] asm. Unfortunately, creating uniquely named symbols + * is trickier than one might think, especially with Clang inline asm. I + * eventually just gave up trying to make that work, in favor of using + * ANNOTATE_DATA_SPECIAL and creating the symbols here after the fact. + */ +static int create_fake_symbols(struct elf *elf) +{ + struct section *sec; + struct reloc *reloc; + + /* + * 1) Make symbols for all the ANNOTATE_DATA_SPECIAL entries: + */ + + sec = find_section_by_name(elf, ".discard.annotate_data"); + if (!sec || !sec->rsec) + return 0; + + for_each_reloc(sec->rsec, reloc) { + unsigned long offset, size; + struct reloc *next_reloc; + + if (annotype(elf, sec, reloc) != ANNOTYPE_DATA_SPECIAL) + continue; + + offset = reloc_addend(reloc); + + size = 0; + next_reloc = reloc; + for_each_reloc_continue(sec->rsec, next_reloc) { + if (annotype(elf, sec, next_reloc) != ANNOTYPE_DATA_SPECIAL || + next_reloc->sym->sec != reloc->sym->sec) + continue; + + size = reloc_addend(next_reloc) - offset; + break; + } + + if (!size) + size = sec_size(reloc->sym->sec) - offset; + + if (create_fake_symbol(elf, reloc->sym->sec, offset, size)) + return -1; + } + + /* + * 2) Make symbols for sh_entsize, and simple arrays of pointers: + */ + + for_each_sec(elf, sec) { + unsigned int entry_size; + unsigned long offset; + + if (!is_special_section(sec) || find_symbol_by_offset(sec, 0)) + continue; + + if (!sec->rsec) { + ERROR("%s: missing special section relocations", sec->name); + return -1; + } + + entry_size = sec->sh.sh_entsize; + if (!entry_size) { + entry_size = arch_reloc_size(sec->rsec->relocs); + if (sec_size(sec) != entry_size * sec_num_entries(sec->rsec)) { + ERROR("%s: missing special section entsize or annotations", sec->name); + return -1; + } + } + + for (offset = 0; offset < sec_size(sec); offset += entry_size) { + if (create_fake_symbol(elf, sec, offset, entry_size)) + return -1; + } + } + + return 0; +} + /* Keep a special section entry if it references an included function */ static bool should_keep_special_sym(struct elf *elf, struct symbol *sym) { @@ -1260,99 +1390,12 @@ static int validate_special_section_klp_reloc(struct elfs *e, struct symbol *sym return ret; } -static int special_section_entry_size(struct section *sec) -{ - unsigned int reloc_size; - - if ((sec->sh.sh_flags & SHF_MERGE) && sec->sh.sh_entsize) - return sec->sh.sh_entsize; - - if (!sec->rsec) - return 0; - - /* Check for a simple array of pointers */ - reloc_size = arch_reloc_size(sec->rsec->relocs); - if (sec_size(sec) == reloc_size * sec_num_entries(sec->rsec)) - return reloc_size; - - return 0; -} - -static int create_fake_symbol(struct elf *elf, struct section *sec, - unsigned long offset, size_t size) -{ - char name[SYM_NAME_LEN]; - unsigned int type; - static int ctr; - char *c; - - if (snprintf_check(name, SYM_NAME_LEN, "__DISCARD_%s_%d", sec->name, ctr++)) - return -1; - - for (c = name; *c; c++) - if (*c == '.') - *c = '_'; - - /* - * STT_NOTYPE: Prevent objtool from validating .altinstr_replacement - * while still allowing objdump to disassemble it. - */ - type = is_text_sec(sec) ? STT_NOTYPE : STT_OBJECT; - if (!elf_create_symbol(elf, name, sec, STB_LOCAL, type, offset, size)) - return -1; - - return 0; -} - static int clone_special_section(struct elfs *e, struct section *patched_sec) { struct symbol *patched_sym; - unsigned int entry_size; - unsigned long offset; - - entry_size = special_section_entry_size(patched_sec); - if (!entry_size) { - /* - * Any special section more complex than a simple array of - * pointers must have its entry size specified in sh_entsize - * (and the SHF_MERGE flag set so the linker preserves it). - * - * Clang older than version 20 doesn't properly preserve - * sh_entsize and will error out here. - */ - ERROR("%s: buggy linker and/or missing sh_entsize", patched_sec->name); - return -1; - } /* - * In the patched object, create a fake symbol for each special section - * entry. This makes the below extracting of entries much easier. - */ - for (offset = 0; offset < sec_size(patched_sec); offset += entry_size) { - if (create_fake_symbol(e->patched, patched_sec, offset, entry_size)) - return -1; - - /* Symbolize alternative replacements: */ - if (!strcmp(patched_sec->name, ".altinstructions")) { - struct reloc *reloc; - unsigned char size; - - reloc = find_reloc_by_dest(e->patched, patched_sec, offset + ALT_NEW_OFFSET); - if (!reloc) { - ERROR_FUNC(patched_sec, offset + ALT_NEW_OFFSET, "can't find new reloc"); - return -1; - } - - size = *(unsigned char *)(patched_sec->data->d_buf + offset + ALT_NEW_LEN_OFFSET); - - if (create_fake_symbol(e->patched, reloc->sym->sec, - reloc->sym->offset + reloc_addend(reloc), size)) - return -1; - } - } - - /* - * Extract all special section entries (and their dependencies) which + * Extract all special section symbols (and their dependencies) which * reference included functions. */ sec_for_each_sym(patched_sec, patched_sym) { @@ -1382,6 +1425,9 @@ static int clone_special_sections(struct elfs *e) { struct section *patched_sec; + if (create_fake_symbols(e->patched)) + return -1; + for_each_sec(e->patched, patched_sec) { if (is_special_section(patched_sec)) { if (clone_special_section(e, patched_sec)) diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index 1dd9fc18fe624..5a979f52425ab 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -8,7 +8,6 @@ #include <objtool/objtool.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> int orc_dump(const char *filename) { diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 9d380abc2ed35..1045e1380ffde 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -12,7 +12,6 @@ #include <objtool/check.h> #include <objtool/orc.h> #include <objtool/warn.h> -#include <objtool/endianness.h> struct orc_list_entry { struct list_head list; diff --git a/tools/objtool/special.c b/tools/objtool/special.c index fc2cf8dba1c03..e262af9171436 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -15,7 +15,6 @@ #include <objtool/builtin.h> #include <objtool/special.h> #include <objtool/warn.h> -#include <objtool/endianness.h> struct special_entry { const char *sec; diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index e1d98fb031575..e38167ca56a95 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -16,6 +16,7 @@ arch/x86/include/asm/orc_types.h arch/x86/include/asm/emulate_prefix.h arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk +include/linux/interval_tree_generic.h include/linux/livepatch_external.h include/linux/static_call_types.h "