diff options
26 files changed, 214 insertions, 72 deletions
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index b6810db24ca4d3..1b9b82bbe3220a 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -5,7 +5,6 @@ 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/kernel/asm-offsets.c b/arch/um/kernel/asm-offsets.c index d38447e39d5ed2..d620b6f6de9bba 100644 --- a/arch/um/kernel/asm-offsets.c +++ b/arch/um/kernel/asm-offsets.c @@ -9,6 +9,7 @@ #include <linux/fs.h> #include <asm/mman.h> #include <asm/seccomp.h> +#include <asm/extable.h> /* workaround for a warning with -Wmissing-prototypes */ void foo(void); @@ -42,4 +43,7 @@ void foo(void) DEFINE(HOSTFS_ATTR_CTIME, ATTR_CTIME); DEFINE(HOSTFS_ATTR_ATIME_SET, ATTR_ATIME_SET); DEFINE(HOSTFS_ATTR_MTIME_SET, ATTR_MTIME_SET); + + DEFINE(ALT_INSTR_SIZE, sizeof(struct alt_instr)); + DEFINE(EXTABLE_SIZE, sizeof(struct exception_table_entry)); } diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index b14c045679e160..03364510d5fe2e 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,\"a\"\n" \ - ANNOTATE_DATA_SPECIAL \ + ".pushsection .altinstructions, \"aM\", @progbits, " \ + __stringify(ALT_INSTR_SIZE) "\n" \ " .long 771b - .\n" /* label */ \ " .long 774f - .\n" /* new instruction */ \ " .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \ @@ -208,7 +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 \ + ANNOTATE_DATA_SPECIAL "\n" \ "# ALT: replacement\n" \ "774:\n\t" newinstr "\n775:\n" \ ".popsection\n" @@ -339,7 +339,6 @@ 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 @@ -363,7 +362,7 @@ void nop_func(void); 741: \ .skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;\ 742: \ - .pushsection .altinstructions,"a" ; \ + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE ;\ altinstr_entry 740b,743f,flag,742b-740b,744f-743f ; \ .popsection ; \ .pushsection .altinstr_replacement,"ax" ; \ diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index bd62bd87a841e3..0e8c611bc9e2a1 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -126,18 +126,21 @@ 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","a" ; \ - .balign 4 ; \ - ANNOTATE_DATA_SPECIAL ; \ - .long (from) - . ; \ - .long (to) - . ; \ - .long type ; \ +# define _ASM_EXTABLE_TYPE(from, to, type) \ + .pushsection "__ex_table", "aM", @progbits, EXTABLE_SIZE ; \ + .balign 4 ; \ + .long (from) - . ; \ + .long (to) - . ; \ + .long type ; \ .popsection # ifdef CONFIG_KPROBES @@ -180,18 +183,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\",\"a\"\n" \ + " .pushsection __ex_table, \"aM\", @progbits, " \ + __stringify(EXTABLE_SIZE) "\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\",\"a\"\n" \ + " .pushsection __ex_table, \"aM\", @progbits, " \ + __stringify(EXTABLE_SIZE) "\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 ab5bba6cf7f52b..ee23b98353d735 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -70,7 +70,7 @@ extern void __WARN_trap(struct bug_entry *bug, ...); #define _BUG_FLAGS_ASM(format, file, line, flags, size, extra) \ ".pushsection __bug_table,\"aw\"\n\t" \ - ANNOTATE_DATA_SPECIAL \ + ANNOTATE_DATA_SPECIAL "\n\t" \ "2:\n\t" \ __BUG_ENTRY(format, file, line, flags) \ "\t.org 2b + " size "\n" \ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 4b1a6ade17003e..3ddc1d33399be9 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -101,7 +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 + ANNOTATE_DATA_SPECIAL "\n" " testb %[bitnum], %a[cap_byte]\n" " jnz %l[t_yes]\n" " jmp %l[t_no]\n" diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h index 735c3a491f6047..8325b79f2ac6a4 100644 --- a/arch/x86/include/asm/irq_stack.h +++ b/arch/x86/include/asm/irq_stack.h @@ -101,7 +101,7 @@ #define ASM_CALL_ARG0 \ "1: call %c[__func] \n" \ - ANNOTATE_REACHABLE(1b) + ANNOTATE_REACHABLE(1b) " \n" #define ASM_CALL_ARG1 \ "movq %[arg1], %%rdi \n" \ diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index e0a6930a4029aa..05b16299588d58 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -15,7 +15,7 @@ #define JUMP_TABLE_ENTRY(key, label) \ ".pushsection __jump_table, \"aw\" \n\t" \ _ASM_ALIGN "\n\t" \ - ANNOTATE_DATA_SPECIAL \ + ANNOTATE_DATA_SPECIAL "\n" \ ".long 1b - . \n\t" \ ".long " label " - . \n\t" \ _ASM_PTR " " key " - . \n\t" \ diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index a6526c5be5ca43..4f4b5e8a157430 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -466,7 +466,7 @@ static inline void call_depth_return_thunk(void) {} */ # define CALL_NOSPEC \ ALTERNATIVE_2( \ - ANNOTATE_RETPOLINE_SAFE \ + ANNOTATE_RETPOLINE_SAFE "\n" \ "call *%[thunk_target]\n", \ " jmp 904f;\n" \ " .align 16\n" \ @@ -482,7 +482,7 @@ static inline void call_depth_return_thunk(void) {} "904: call 901b;\n", \ X86_FEATURE_RETPOLINE, \ "lfence;\n" \ - ANNOTATE_RETPOLINE_SAFE \ + ANNOTATE_RETPOLINE_SAFE "\n" \ "call *%[thunk_target]\n", \ X86_FEATURE_RETPOLINE_LFENCE) diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 37a8627d8277fb..3502939415ad04 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -249,7 +249,7 @@ extern struct paravirt_patch_template pv_ops; * don't need to bother with CFI prefixes. */ #define PARAVIRT_CALL \ - ANNOTATE_RETPOLINE_SAFE \ + ANNOTATE_RETPOLINE_SAFE "\n\t" \ "call *%[paravirt_opptr];" /* diff --git a/arch/x86/include/asm/smap.h b/arch/x86/include/asm/smap.h index 20a3baae9568d0..977bef14a0abf9 100644 --- a/arch/x86/include/asm/smap.h +++ b/arch/x86/include/asm/smap.h @@ -77,7 +77,7 @@ static __always_inline unsigned long smap_save(void) unsigned long flags; asm volatile ("# smap_save\n\t" - ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "", "pushf; pop %0; clac", X86_FEATURE_SMAP) : "=rm" (flags) : : "memory", "cc"); @@ -88,7 +88,7 @@ static __always_inline unsigned long smap_save(void) static __always_inline void smap_restore(unsigned long flags) { asm volatile ("# smap_restore\n\t" - ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "", "push %0; popf", X86_FEATURE_SMAP) : : "g" (flags) : "memory", "cc"); @@ -101,9 +101,9 @@ static __always_inline void smap_restore(unsigned long flags) ALTERNATIVE("", "stac", X86_FEATURE_SMAP) #define ASM_CLAC_UNSAFE \ - ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "clac", X86_FEATURE_SMAP) + ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "clac", X86_FEATURE_SMAP) #define ASM_STAC_UNSAFE \ - ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "stac", X86_FEATURE_SMAP) + ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "stac", X86_FEATURE_SMAP) #endif /* __ASSEMBLER__ */ diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h index 41502bd2afd646..4cd725a8fe91f9 100644 --- a/arch/x86/include/asm/static_call.h +++ b/arch/x86/include/asm/static_call.h @@ -36,7 +36,7 @@ ".align 4 \n" \ ".globl " STATIC_CALL_TRAMP_STR(name) " \n" \ STATIC_CALL_TRAMP_STR(name) ": \n" \ - ANNOTATE_NOENDBR \ + ANNOTATE_NOENDBR " \n" \ insns " \n" \ ".byte 0x0f, 0xb9, 0xcc \n" \ ".type " STATIC_CALL_TRAMP_STR(name) ", @function \n" \ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 74f4c659f9c9f3..28518371d8bf3c 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -2229,7 +2229,7 @@ asm ( " .pushsection .init.text, \"ax\", @progbits\n" " .type int3_selftest_asm, @function\n" "int3_selftest_asm:\n" - ANNOTATE_NOENDBR + ANNOTATE_NOENDBR "\n" /* * INT3 padded with NOP to CALL_INSN_SIZE. The INT3 triggers an * exception, then the int3_exception_nb notifier emulates a call to @@ -2247,7 +2247,7 @@ asm ( " .pushsection .init.text, \"ax\", @progbits\n" " .type int3_selftest_callee, @function\n" "int3_selftest_callee:\n" - ANNOTATE_NOENDBR + ANNOTATE_NOENDBR "\n" " movl $0x1234, (%" _ASM_ARG1 ")\n" ASM_RET " .size int3_selftest_callee, . - int3_selftest_callee\n" diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 32ba599a51f888..25fcde525c68c2 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c @@ -124,4 +124,7 @@ 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/kernel/rethook.c b/arch/x86/kernel/rethook.c index 8a1c0111ae7921..85e2f2d16a904a 100644 --- a/arch/x86/kernel/rethook.c +++ b/arch/x86/kernel/rethook.c @@ -25,7 +25,7 @@ asm( ".type arch_rethook_trampoline, @function\n" "arch_rethook_trampoline:\n" #ifdef CONFIG_X86_64 - ANNOTATE_NOENDBR /* This is only jumped from ret instruction */ + ANNOTATE_NOENDBR "\n" /* This is only jumped from ret instruction */ /* Push a fake return address to tell the unwinder it's a rethook. */ " pushq $arch_rethook_trampoline\n" UNWIND_HINT_FUNC diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c index 2892cdb145638a..61592e41a6b154 100644 --- a/arch/x86/kernel/static_call.c +++ b/arch/x86/kernel/static_call.c @@ -50,8 +50,8 @@ asm (".global __static_call_return\n\t" ".type __static_call_return, @function\n\t" ASM_FUNC_ALIGN "\n\t" "__static_call_return:\n\t" - ANNOTATE_NOENDBR - ANNOTATE_RETPOLINE_SAFE + ANNOTATE_NOENDBR "\n\t" + ANNOTATE_RETPOLINE_SAFE "\n\t" "ret; int3\n\t" ".size __static_call_return, . - __static_call_return \n\t"); diff --git a/arch/x86/lib/error-inject.c b/arch/x86/lib/error-inject.c index b5a6d83106bc2d..512a2538596f08 100644 --- a/arch/x86/lib/error-inject.c +++ b/arch/x86/lib/error-inject.c @@ -13,7 +13,7 @@ asm( ".globl just_return_func\n" ASM_FUNC_ALIGN "just_return_func:\n" - ANNOTATE_NOENDBR + ANNOTATE_NOENDBR "\n" ASM_RET ".size just_return_func, .-just_return_func\n" ); diff --git a/include/linux/annotate.h b/include/linux/annotate.h index 7c10d34d198cf7..2f1599c9e57323 100644 --- a/include/linux/annotate.h +++ b/include/linux/annotate.h @@ -6,41 +6,34 @@ #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" + .pushsection section, "M", @progbits, 8; \ + .long label - ., type; \ + .popsection + +#ifndef __ASSEMBLY__ #define ASM_ANNOTATE_LABEL(label, type) \ - __ASM_ANNOTATE(".discard.annotate_insn", label, type) + __stringify(__ASM_ANNOTATE(.discard.annotate_insn, label, type)) #define ASM_ANNOTATE(type) \ - "911:\n\t" \ - ASM_ANNOTATE_LABEL(911b, type) + "911: " \ + __stringify(__ASM_ANNOTATE(.discard.annotate_insn, 911b, type)) #define ASM_ANNOTATE_DATA(type) \ - "912:\n\t" \ - __ASM_ANNOTATE(".discard.annotate_data", 912b, type) + "912: " \ + __stringify(__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 +.Lhere_\@: + __ASM_ANNOTATE(.discard.annotate_insn, .Lhere_\@, \type) .endm .macro ANNOTATE_DATA type - __ANNOTATE ".discard.annotate_data", \type +.Lhere_\@: + __ASM_ANNOTATE(.discard.annotate_data, .Lhere_\@, \type) .endm #endif /* __ASSEMBLY__ */ diff --git a/include/linux/objtool.h b/include/linux/objtool.h index b18ab53561c995..9a00e701454c58 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -12,7 +12,7 @@ #define UNWIND_HINT(type, sp_reg, sp_offset, signal) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \ - ANNOTATE_DATA_SPECIAL \ + ANNOTATE_DATA_SPECIAL "\n\t" \ /* struct unwind_hint */ \ ".long 987b - .\n\t" \ ".short " __stringify(sp_offset) "\n\t" \ diff --git a/kernel/bounds.c b/kernel/bounds.c index 29b2cd00df2ccf..02b619eb610656 100644 --- a/kernel/bounds.c +++ b/kernel/bounds.c @@ -6,6 +6,7 @@ */ #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> diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index d3d00e85edf735..ef2ffb68f69d1d 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#define COMPILE_OFFSETS #include <linux/kbuild.h> #include <linux/mod_devicetable.h> diff --git a/tools/objtool/Build b/tools/objtool/Build index 9982e665d58da6..600da051af12ec 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -18,6 +18,7 @@ objtool-y += libstring.o objtool-y += libctype.o objtool-y += str_error_r.o objtool-y += librbtree.o +objtool-y += signal.o $(OUTPUT)libstring.o: ../lib/string.c FORCE $(call rule_mkdir) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 9ec0e07cce90b6..3f7999317f4dfa 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3282,18 +3282,19 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn return 0; } -static int handle_insn_ops(struct instruction *insn, - struct instruction *next_insn, - struct insn_state *state) +static int noinline handle_insn_ops(struct instruction *insn, + struct instruction *next_insn, + struct insn_state *state) { + struct insn_state prev_state __maybe_unused = *state; struct stack_op *op; - int ret; + int ret = 0; for (op = insn->stack_ops; op; op = op->next) { ret = update_cfi_state(insn, next_insn, &state->cfi, op); if (ret) - return ret; + goto done; if (!opts.uaccess || !insn->alt_group) continue; @@ -3303,7 +3304,8 @@ static int handle_insn_ops(struct instruction *insn, state->uaccess_stack = 1; } else if (state->uaccess_stack >> 31) { WARN_INSN(insn, "PUSHF stack exhausted"); - return 1; + ret = 1; + goto done; } state->uaccess_stack <<= 1; state->uaccess_stack |= state->uaccess; @@ -3319,7 +3321,10 @@ static int handle_insn_ops(struct instruction *insn, } } - return 0; +done: + TRACE_INSN_STATE(insn, &prev_state, state); + + return ret; } static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) @@ -3694,8 +3699,6 @@ static int validate_insn(struct objtool_file *file, struct symbol *func, struct instruction *prev_insn, struct instruction *next_insn, bool *dead_end) { - /* prev_state and alt_name are not used if there is no disassembly support */ - struct insn_state prev_state __maybe_unused; char *alt_name __maybe_unused = NULL; struct alternative *alt; u8 visited; @@ -3798,11 +3801,7 @@ static int validate_insn(struct objtool_file *file, struct symbol *func, if (skip_alt_group(insn)) return 0; - prev_state = *statep; - ret = handle_insn_ops(insn, next_insn, statep); - TRACE_INSN_STATE(insn, &prev_state, statep); - - if (ret) + if (handle_insn_ops(insn, next_insn, statep)) return 1; switch (insn->type) { diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h index f7051bbe0bcb26..6dc12a59ad00fb 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -41,6 +41,8 @@ struct objtool_file { char *top_level_dir(const char *file); +int init_signal_handler(void); + struct objtool_file *objtool_open_read(const char *_objname); int objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func); diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index 3c26ed561c7eff..1c3622117c33cf 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -104,11 +104,13 @@ char *top_level_dir(const char *file) return str; } - int main(int argc, const char **argv) { static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; + if (init_signal_handler()) + return -1; + /* libsubcmd init */ exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); pager_init(UNUSED); diff --git a/tools/objtool/signal.c b/tools/objtool/signal.c new file mode 100644 index 00000000000000..af5c65c0fb2d3c --- /dev/null +++ b/tools/objtool/signal.c @@ -0,0 +1,135 @@ +/* + * signal.c: Register a sigaltstack for objtool, to be able to + * run a signal handler on a separate stack even if + * the main process stack has overflown. Print out + * stack overflow errors when this happens. + */ +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <sys/resource.h> +#include <string.h> + +#include <objtool/objtool.h> +#include <objtool/warn.h> + +static unsigned long stack_limit; + +static bool is_stack_overflow(void *fault_addr) +{ + unsigned long fault = (unsigned long)fault_addr; + + /* Check if fault is in the guard page just below the limit. */ + return fault < stack_limit && fault >= stack_limit - 4096; +} + +static void signal_handler(int sig_num, siginfo_t *info, void *context) +{ + struct sigaction sa_dfl = {0}; + const char *sig_name; + char msg[256]; + int msg_len; + + switch (sig_num) { + case SIGSEGV: sig_name = "SIGSEGV"; break; + case SIGBUS: sig_name = "SIGBUS"; break; + case SIGILL: sig_name = "SIGILL"; break; + case SIGABRT: sig_name = "SIGABRT"; break; + default: sig_name = "Unknown signal"; break; + } + + if (is_stack_overflow(info->si_addr)) { + msg_len = snprintf(msg, sizeof(msg), + "%s: error: %s: objtool stack overflow!\n", + objname, sig_name); + } else { + msg_len = snprintf(msg, sizeof(msg), + "%s: error: %s: objtool crash!\n", + objname, sig_name); + } + + msg_len = write(STDERR_FILENO, msg, msg_len); + + /* Re-raise the signal to trigger the core dump */ + sa_dfl.sa_handler = SIG_DFL; + sigaction(sig_num, &sa_dfl, NULL); + raise(sig_num); +} + +static int read_stack_limit(void) +{ + unsigned long stack_start, stack_end; + struct rlimit rlim; + char line[256]; + int ret = 0; + FILE *fp; + + if (getrlimit(RLIMIT_STACK, &rlim)) { + ERROR_GLIBC("getrlimit"); + return -1; + } + + fp = fopen("/proc/self/maps", "r"); + if (!fp) { + ERROR_GLIBC("fopen"); + return -1; + } + + while (fgets(line, sizeof(line), fp)) { + if (strstr(line, "[stack]")) { + if (sscanf(line, "%lx-%lx", &stack_start, &stack_end) != 2) { + ERROR_GLIBC("sscanf"); + ret = -1; + goto done; + } + stack_limit = stack_end - rlim.rlim_cur; + goto done; + } + } + + ret = -1; + ERROR("/proc/self/maps: can't find [stack]"); + +done: + fclose(fp); + + return ret; +} + +int init_signal_handler(void) +{ + int signals[] = {SIGSEGV, SIGBUS, SIGILL, SIGABRT}; + struct sigaction sa; + stack_t ss; + + if (read_stack_limit()) + return -1; + + ss.ss_sp = malloc(SIGSTKSZ); + if (!ss.ss_sp) { + ERROR_GLIBC("malloc"); + return -1; + } + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + + if (sigaltstack(&ss, NULL) == -1) { + ERROR_GLIBC("sigaltstack"); + return -1; + } + + sa.sa_sigaction = signal_handler; + sigemptyset(&sa.sa_mask); + + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; + + for (int i = 0; i < ARRAY_SIZE(signals); i++) { + if (sigaction(signals[i], &sa, NULL) == -1) { + ERROR_GLIBC("sigaction"); + return -1; + } + } + + return 0; +} |
