Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'objtool-urgent-2025-12-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool fixes from Ingo Molnar:
"Address various objtool scalability bugs/inefficiencies exposed by
allmodconfig builds, plus improve the quality of alternatives
instructions generated code and disassembly"

* tag 'objtool-urgent-2025-12-06' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
objtool: Simplify .annotate_insn code generation output some more
objtool: Add more robust signal error handling, detect and warn about stack overflows
objtool: Remove newlines and tabs from annotation macros
objtool: Consolidate annotation macros
x86/asm: Remove ANNOTATE_DATA_SPECIAL usage
x86/alternative: Remove ANNOTATE_DATA_SPECIAL usage
objtool: Fix stack overflow in validate_branch()

+214 -72
-1
arch/um/include/asm/Kbuild
··· 5 5 generic-y += dma-mapping.h 6 6 generic-y += emergency-restart.h 7 7 generic-y += exec.h 8 - generic-y += extable.h 9 8 generic-y += ftrace.h 10 9 generic-y += hw_irq.h 11 10 generic-y += irq_regs.h
+4
arch/um/kernel/asm-offsets.c
··· 9 9 #include <linux/fs.h> 10 10 #include <asm/mman.h> 11 11 #include <asm/seccomp.h> 12 + #include <asm/extable.h> 12 13 13 14 /* workaround for a warning with -Wmissing-prototypes */ 14 15 void foo(void); ··· 43 42 DEFINE(HOSTFS_ATTR_CTIME, ATTR_CTIME); 44 43 DEFINE(HOSTFS_ATTR_ATIME_SET, ATTR_ATIME_SET); 45 44 DEFINE(HOSTFS_ATTR_MTIME_SET, ATTR_MTIME_SET); 45 + 46 + DEFINE(ALT_INSTR_SIZE, sizeof(struct alt_instr)); 47 + DEFINE(EXTABLE_SIZE, sizeof(struct exception_table_entry)); 46 48 }
+4 -5
arch/x86/include/asm/alternative.h
··· 197 197 "773:\n" 198 198 199 199 #define ALTINSTR_ENTRY(ft_flags) \ 200 - ".pushsection .altinstructions,\"a\"\n" \ 201 - ANNOTATE_DATA_SPECIAL \ 200 + ".pushsection .altinstructions, \"aM\", @progbits, " \ 201 + __stringify(ALT_INSTR_SIZE) "\n" \ 202 202 " .long 771b - .\n" /* label */ \ 203 203 " .long 774f - .\n" /* new instruction */ \ 204 204 " .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \ ··· 208 208 209 209 #define ALTINSTR_REPLACEMENT(newinstr) /* replacement */ \ 210 210 ".pushsection .altinstr_replacement, \"ax\"\n" \ 211 - ANNOTATE_DATA_SPECIAL \ 211 + ANNOTATE_DATA_SPECIAL "\n" \ 212 212 "# ALT: replacement\n" \ 213 213 "774:\n\t" newinstr "\n775:\n" \ 214 214 ".popsection\n" ··· 339 339 * instruction. See apply_alternatives(). 340 340 */ 341 341 .macro altinstr_entry orig alt ft_flags orig_len alt_len 342 - ANNOTATE_DATA_SPECIAL 343 342 .long \orig - . 344 343 .long \alt - . 345 344 .4byte \ft_flags ··· 362 363 741: \ 363 364 .skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;\ 364 365 742: \ 365 - .pushsection .altinstructions,"a" ; \ 366 + .pushsection .altinstructions, "aM", @progbits, ALT_INSTR_SIZE ;\ 366 367 altinstr_entry 740b,743f,flag,742b-740b,744f-743f ; \ 367 368 .popsection ; \ 368 369 .pushsection .altinstr_replacement,"ax" ; \
+14 -11
arch/x86/include/asm/asm.h
··· 126 126 127 127 #ifdef __KERNEL__ 128 128 129 + #ifndef COMPILE_OFFSETS 130 + #include <asm/asm-offsets.h> 131 + #endif 132 + 129 133 # include <asm/extable_fixup_types.h> 130 134 131 135 /* Exception table entry */ 132 136 #ifdef __ASSEMBLER__ 133 137 134 - # define _ASM_EXTABLE_TYPE(from, to, type) \ 135 - .pushsection "__ex_table","a" ; \ 136 - .balign 4 ; \ 137 - ANNOTATE_DATA_SPECIAL ; \ 138 - .long (from) - . ; \ 139 - .long (to) - . ; \ 140 - .long type ; \ 138 + # define _ASM_EXTABLE_TYPE(from, to, type) \ 139 + .pushsection "__ex_table", "aM", @progbits, EXTABLE_SIZE ; \ 140 + .balign 4 ; \ 141 + .long (from) - . ; \ 142 + .long (to) - . ; \ 143 + .long type ; \ 141 144 .popsection 142 145 143 146 # ifdef CONFIG_KPROBES ··· 183 180 ".purgem extable_type_reg\n" 184 181 185 182 # define _ASM_EXTABLE_TYPE(from, to, type) \ 186 - " .pushsection \"__ex_table\",\"a\"\n" \ 183 + " .pushsection __ex_table, \"aM\", @progbits, " \ 184 + __stringify(EXTABLE_SIZE) "\n" \ 187 185 " .balign 4\n" \ 188 - ANNOTATE_DATA_SPECIAL \ 189 186 " .long (" #from ") - .\n" \ 190 187 " .long (" #to ") - .\n" \ 191 188 " .long " __stringify(type) " \n" \ 192 189 " .popsection\n" 193 190 194 191 # define _ASM_EXTABLE_TYPE_REG(from, to, type, reg) \ 195 - " .pushsection \"__ex_table\",\"a\"\n" \ 192 + " .pushsection __ex_table, \"aM\", @progbits, " \ 193 + __stringify(EXTABLE_SIZE) "\n" \ 196 194 " .balign 4\n" \ 197 - ANNOTATE_DATA_SPECIAL \ 198 195 " .long (" #from ") - .\n" \ 199 196 " .long (" #to ") - .\n" \ 200 197 DEFINE_EXTABLE_TYPE_REG \
+1 -1
arch/x86/include/asm/bug.h
··· 70 70 71 71 #define _BUG_FLAGS_ASM(format, file, line, flags, size, extra) \ 72 72 ".pushsection __bug_table,\"aw\"\n\t" \ 73 - ANNOTATE_DATA_SPECIAL \ 73 + ANNOTATE_DATA_SPECIAL "\n\t" \ 74 74 "2:\n\t" \ 75 75 __BUG_ENTRY(format, file, line, flags) \ 76 76 "\t.org 2b + " size "\n" \
+1 -1
arch/x86/include/asm/cpufeature.h
··· 101 101 asm goto(ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]") 102 102 ".pushsection .altinstr_aux,\"ax\"\n" 103 103 "6:\n" 104 - ANNOTATE_DATA_SPECIAL 104 + ANNOTATE_DATA_SPECIAL "\n" 105 105 " testb %[bitnum], %a[cap_byte]\n" 106 106 " jnz %l[t_yes]\n" 107 107 " jmp %l[t_no]\n"
+1 -1
arch/x86/include/asm/irq_stack.h
··· 101 101 102 102 #define ASM_CALL_ARG0 \ 103 103 "1: call %c[__func] \n" \ 104 - ANNOTATE_REACHABLE(1b) 104 + ANNOTATE_REACHABLE(1b) " \n" 105 105 106 106 #define ASM_CALL_ARG1 \ 107 107 "movq %[arg1], %%rdi \n" \
+1 -1
arch/x86/include/asm/jump_label.h
··· 15 15 #define JUMP_TABLE_ENTRY(key, label) \ 16 16 ".pushsection __jump_table, \"aw\" \n\t" \ 17 17 _ASM_ALIGN "\n\t" \ 18 - ANNOTATE_DATA_SPECIAL \ 18 + ANNOTATE_DATA_SPECIAL "\n" \ 19 19 ".long 1b - . \n\t" \ 20 20 ".long " label " - . \n\t" \ 21 21 _ASM_PTR " " key " - . \n\t" \
+2 -2
arch/x86/include/asm/nospec-branch.h
··· 466 466 */ 467 467 # define CALL_NOSPEC \ 468 468 ALTERNATIVE_2( \ 469 - ANNOTATE_RETPOLINE_SAFE \ 469 + ANNOTATE_RETPOLINE_SAFE "\n" \ 470 470 "call *%[thunk_target]\n", \ 471 471 " jmp 904f;\n" \ 472 472 " .align 16\n" \ ··· 482 482 "904: call 901b;\n", \ 483 483 X86_FEATURE_RETPOLINE, \ 484 484 "lfence;\n" \ 485 - ANNOTATE_RETPOLINE_SAFE \ 485 + ANNOTATE_RETPOLINE_SAFE "\n" \ 486 486 "call *%[thunk_target]\n", \ 487 487 X86_FEATURE_RETPOLINE_LFENCE) 488 488
+1 -1
arch/x86/include/asm/paravirt_types.h
··· 249 249 * don't need to bother with CFI prefixes. 250 250 */ 251 251 #define PARAVIRT_CALL \ 252 - ANNOTATE_RETPOLINE_SAFE \ 252 + ANNOTATE_RETPOLINE_SAFE "\n\t" \ 253 253 "call *%[paravirt_opptr];" 254 254 255 255 /*
+4 -4
arch/x86/include/asm/smap.h
··· 77 77 unsigned long flags; 78 78 79 79 asm volatile ("# smap_save\n\t" 80 - ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE 80 + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "\n\t" 81 81 "", "pushf; pop %0; clac", 82 82 X86_FEATURE_SMAP) 83 83 : "=rm" (flags) : : "memory", "cc"); ··· 88 88 static __always_inline void smap_restore(unsigned long flags) 89 89 { 90 90 asm volatile ("# smap_restore\n\t" 91 - ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE 91 + ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "\n\t" 92 92 "", "push %0; popf", 93 93 X86_FEATURE_SMAP) 94 94 : : "g" (flags) : "memory", "cc"); ··· 101 101 ALTERNATIVE("", "stac", X86_FEATURE_SMAP) 102 102 103 103 #define ASM_CLAC_UNSAFE \ 104 - ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "clac", X86_FEATURE_SMAP) 104 + ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "clac", X86_FEATURE_SMAP) 105 105 #define ASM_STAC_UNSAFE \ 106 - ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "stac", X86_FEATURE_SMAP) 106 + ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "\n\t" "stac", X86_FEATURE_SMAP) 107 107 108 108 #endif /* __ASSEMBLER__ */ 109 109
+1 -1
arch/x86/include/asm/static_call.h
··· 36 36 ".align 4 \n" \ 37 37 ".globl " STATIC_CALL_TRAMP_STR(name) " \n" \ 38 38 STATIC_CALL_TRAMP_STR(name) ": \n" \ 39 - ANNOTATE_NOENDBR \ 39 + ANNOTATE_NOENDBR " \n" \ 40 40 insns " \n" \ 41 41 ".byte 0x0f, 0xb9, 0xcc \n" \ 42 42 ".type " STATIC_CALL_TRAMP_STR(name) ", @function \n" \
+2 -2
arch/x86/kernel/alternative.c
··· 2229 2229 " .pushsection .init.text, \"ax\", @progbits\n" 2230 2230 " .type int3_selftest_asm, @function\n" 2231 2231 "int3_selftest_asm:\n" 2232 - ANNOTATE_NOENDBR 2232 + ANNOTATE_NOENDBR "\n" 2233 2233 /* 2234 2234 * INT3 padded with NOP to CALL_INSN_SIZE. The INT3 triggers an 2235 2235 * exception, then the int3_exception_nb notifier emulates a call to ··· 2247 2247 " .pushsection .init.text, \"ax\", @progbits\n" 2248 2248 " .type int3_selftest_callee, @function\n" 2249 2249 "int3_selftest_callee:\n" 2250 - ANNOTATE_NOENDBR 2250 + ANNOTATE_NOENDBR "\n" 2251 2251 " movl $0x1234, (%" _ASM_ARG1 ")\n" 2252 2252 ASM_RET 2253 2253 " .size int3_selftest_callee, . - int3_selftest_callee\n"
+3
arch/x86/kernel/asm-offsets.c
··· 124 124 OFFSET(ARIA_CTX_rounds, aria_ctx, rounds); 125 125 #endif 126 126 127 + BLANK(); 128 + DEFINE(ALT_INSTR_SIZE, sizeof(struct alt_instr)); 129 + DEFINE(EXTABLE_SIZE, sizeof(struct exception_table_entry)); 127 130 }
+1 -1
arch/x86/kernel/rethook.c
··· 25 25 ".type arch_rethook_trampoline, @function\n" 26 26 "arch_rethook_trampoline:\n" 27 27 #ifdef CONFIG_X86_64 28 - ANNOTATE_NOENDBR /* This is only jumped from ret instruction */ 28 + ANNOTATE_NOENDBR "\n" /* This is only jumped from ret instruction */ 29 29 /* Push a fake return address to tell the unwinder it's a rethook. */ 30 30 " pushq $arch_rethook_trampoline\n" 31 31 UNWIND_HINT_FUNC
+2 -2
arch/x86/kernel/static_call.c
··· 50 50 ".type __static_call_return, @function\n\t" 51 51 ASM_FUNC_ALIGN "\n\t" 52 52 "__static_call_return:\n\t" 53 - ANNOTATE_NOENDBR 54 - ANNOTATE_RETPOLINE_SAFE 53 + ANNOTATE_NOENDBR "\n\t" 54 + ANNOTATE_RETPOLINE_SAFE "\n\t" 55 55 "ret; int3\n\t" 56 56 ".size __static_call_return, . - __static_call_return \n\t"); 57 57
+1 -1
arch/x86/lib/error-inject.c
··· 13 13 ".globl just_return_func\n" 14 14 ASM_FUNC_ALIGN 15 15 "just_return_func:\n" 16 - ANNOTATE_NOENDBR 16 + ANNOTATE_NOENDBR "\n" 17 17 ASM_RET 18 18 ".size just_return_func, .-just_return_func\n" 19 19 );
+14 -21
include/linux/annotate.h
··· 6 6 7 7 #ifdef CONFIG_OBJTOOL 8 8 9 + #define __ASM_ANNOTATE(section, label, type) \ 10 + .pushsection section, "M", @progbits, 8; \ 11 + .long label - ., type; \ 12 + .popsection 13 + 9 14 #ifndef __ASSEMBLY__ 10 15 11 - #define __ASM_ANNOTATE(section, label, type) \ 12 - ".pushsection " section ",\"M\", @progbits, 8\n\t" \ 13 - ".long " __stringify(label) " - .\n\t" \ 14 - ".long " __stringify(type) "\n\t" \ 15 - ".popsection\n\t" 16 - 17 16 #define ASM_ANNOTATE_LABEL(label, type) \ 18 - __ASM_ANNOTATE(".discard.annotate_insn", label, type) 17 + __stringify(__ASM_ANNOTATE(.discard.annotate_insn, label, type)) 19 18 20 19 #define ASM_ANNOTATE(type) \ 21 - "911:\n\t" \ 22 - ASM_ANNOTATE_LABEL(911b, type) 20 + "911: " \ 21 + __stringify(__ASM_ANNOTATE(.discard.annotate_insn, 911b, type)) 23 22 24 23 #define ASM_ANNOTATE_DATA(type) \ 25 - "912:\n\t" \ 26 - __ASM_ANNOTATE(".discard.annotate_data", 912b, type) 24 + "912: " \ 25 + __stringify(__ASM_ANNOTATE(.discard.annotate_data, 912b, type)) 27 26 28 27 #else /* __ASSEMBLY__ */ 29 28 30 - .macro __ANNOTATE section, type 31 - .Lhere_\@: 32 - .pushsection \section, "M", @progbits, 8 33 - .long .Lhere_\@ - . 34 - .long \type 35 - .popsection 36 - .endm 37 - 38 29 .macro ANNOTATE type 39 - __ANNOTATE ".discard.annotate_insn", \type 30 + .Lhere_\@: 31 + __ASM_ANNOTATE(.discard.annotate_insn, .Lhere_\@, \type) 40 32 .endm 41 33 42 34 .macro ANNOTATE_DATA type 43 - __ANNOTATE ".discard.annotate_data", \type 35 + .Lhere_\@: 36 + __ASM_ANNOTATE(.discard.annotate_data, .Lhere_\@, \type) 44 37 .endm 45 38 46 39 #endif /* __ASSEMBLY__ */
+1 -1
include/linux/objtool.h
··· 12 12 #define UNWIND_HINT(type, sp_reg, sp_offset, signal) \ 13 13 "987: \n\t" \ 14 14 ".pushsection .discard.unwind_hints\n\t" \ 15 - ANNOTATE_DATA_SPECIAL \ 15 + ANNOTATE_DATA_SPECIAL "\n\t" \ 16 16 /* struct unwind_hint */ \ 17 17 ".long 987b - .\n\t" \ 18 18 ".short " __stringify(sp_offset) "\n\t" \
+1
kernel/bounds.c
··· 6 6 */ 7 7 8 8 #define __GENERATING_BOUNDS_H 9 + #define COMPILE_OFFSETS 9 10 /* Include headers that define the enum constants of interest */ 10 11 #include <linux/page-flags.h> 11 12 #include <linux/mmzone.h>
+1
scripts/mod/devicetable-offsets.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 + #define COMPILE_OFFSETS 2 3 #include <linux/kbuild.h> 3 4 #include <linux/mod_devicetable.h> 4 5
+1
tools/objtool/Build
··· 18 18 objtool-y += libctype.o 19 19 objtool-y += str_error_r.o 20 20 objtool-y += librbtree.o 21 + objtool-y += signal.o 21 22 22 23 $(OUTPUT)libstring.o: ../lib/string.c FORCE 23 24 $(call rule_mkdir)
+13 -14
tools/objtool/check.c
··· 3282 3282 return 0; 3283 3283 } 3284 3284 3285 - static int handle_insn_ops(struct instruction *insn, 3286 - struct instruction *next_insn, 3287 - struct insn_state *state) 3285 + static int noinline handle_insn_ops(struct instruction *insn, 3286 + struct instruction *next_insn, 3287 + struct insn_state *state) 3288 3288 { 3289 + struct insn_state prev_state __maybe_unused = *state; 3289 3290 struct stack_op *op; 3290 - int ret; 3291 + int ret = 0; 3291 3292 3292 3293 for (op = insn->stack_ops; op; op = op->next) { 3293 3294 3294 3295 ret = update_cfi_state(insn, next_insn, &state->cfi, op); 3295 3296 if (ret) 3296 - return ret; 3297 + goto done; 3297 3298 3298 3299 if (!opts.uaccess || !insn->alt_group) 3299 3300 continue; ··· 3304 3303 state->uaccess_stack = 1; 3305 3304 } else if (state->uaccess_stack >> 31) { 3306 3305 WARN_INSN(insn, "PUSHF stack exhausted"); 3307 - return 1; 3306 + ret = 1; 3307 + goto done; 3308 3308 } 3309 3309 state->uaccess_stack <<= 1; 3310 3310 state->uaccess_stack |= state->uaccess; ··· 3321 3319 } 3322 3320 } 3323 3321 3324 - return 0; 3322 + done: 3323 + TRACE_INSN_STATE(insn, &prev_state, state); 3324 + 3325 + return ret; 3325 3326 } 3326 3327 3327 3328 static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) ··· 3699 3694 struct instruction *prev_insn, struct instruction *next_insn, 3700 3695 bool *dead_end) 3701 3696 { 3702 - /* prev_state and alt_name are not used if there is no disassembly support */ 3703 - struct insn_state prev_state __maybe_unused; 3704 3697 char *alt_name __maybe_unused = NULL; 3705 3698 struct alternative *alt; 3706 3699 u8 visited; ··· 3801 3798 if (skip_alt_group(insn)) 3802 3799 return 0; 3803 3800 3804 - prev_state = *statep; 3805 - ret = handle_insn_ops(insn, next_insn, statep); 3806 - TRACE_INSN_STATE(insn, &prev_state, statep); 3807 - 3808 - if (ret) 3801 + if (handle_insn_ops(insn, next_insn, statep)) 3809 3802 return 1; 3810 3803 3811 3804 switch (insn->type) {
+2
tools/objtool/include/objtool/objtool.h
··· 41 41 42 42 char *top_level_dir(const char *file); 43 43 44 + int init_signal_handler(void); 45 + 44 46 struct objtool_file *objtool_open_read(const char *_objname); 45 47 46 48 int objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func);
+3 -1
tools/objtool/objtool.c
··· 104 104 return str; 105 105 } 106 106 107 - 108 107 int main(int argc, const char **argv) 109 108 { 110 109 static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 110 + 111 + if (init_signal_handler()) 112 + return -1; 111 113 112 114 /* libsubcmd init */ 113 115 exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED);
+135
tools/objtool/signal.c
··· 1 + /* 2 + * signal.c: Register a sigaltstack for objtool, to be able to 3 + * run a signal handler on a separate stack even if 4 + * the main process stack has overflown. Print out 5 + * stack overflow errors when this happens. 6 + */ 7 + #include <stdio.h> 8 + #include <stdlib.h> 9 + #include <signal.h> 10 + #include <unistd.h> 11 + #include <sys/resource.h> 12 + #include <string.h> 13 + 14 + #include <objtool/objtool.h> 15 + #include <objtool/warn.h> 16 + 17 + static unsigned long stack_limit; 18 + 19 + static bool is_stack_overflow(void *fault_addr) 20 + { 21 + unsigned long fault = (unsigned long)fault_addr; 22 + 23 + /* Check if fault is in the guard page just below the limit. */ 24 + return fault < stack_limit && fault >= stack_limit - 4096; 25 + } 26 + 27 + static void signal_handler(int sig_num, siginfo_t *info, void *context) 28 + { 29 + struct sigaction sa_dfl = {0}; 30 + const char *sig_name; 31 + char msg[256]; 32 + int msg_len; 33 + 34 + switch (sig_num) { 35 + case SIGSEGV: sig_name = "SIGSEGV"; break; 36 + case SIGBUS: sig_name = "SIGBUS"; break; 37 + case SIGILL: sig_name = "SIGILL"; break; 38 + case SIGABRT: sig_name = "SIGABRT"; break; 39 + default: sig_name = "Unknown signal"; break; 40 + } 41 + 42 + if (is_stack_overflow(info->si_addr)) { 43 + msg_len = snprintf(msg, sizeof(msg), 44 + "%s: error: %s: objtool stack overflow!\n", 45 + objname, sig_name); 46 + } else { 47 + msg_len = snprintf(msg, sizeof(msg), 48 + "%s: error: %s: objtool crash!\n", 49 + objname, sig_name); 50 + } 51 + 52 + msg_len = write(STDERR_FILENO, msg, msg_len); 53 + 54 + /* Re-raise the signal to trigger the core dump */ 55 + sa_dfl.sa_handler = SIG_DFL; 56 + sigaction(sig_num, &sa_dfl, NULL); 57 + raise(sig_num); 58 + } 59 + 60 + static int read_stack_limit(void) 61 + { 62 + unsigned long stack_start, stack_end; 63 + struct rlimit rlim; 64 + char line[256]; 65 + int ret = 0; 66 + FILE *fp; 67 + 68 + if (getrlimit(RLIMIT_STACK, &rlim)) { 69 + ERROR_GLIBC("getrlimit"); 70 + return -1; 71 + } 72 + 73 + fp = fopen("/proc/self/maps", "r"); 74 + if (!fp) { 75 + ERROR_GLIBC("fopen"); 76 + return -1; 77 + } 78 + 79 + while (fgets(line, sizeof(line), fp)) { 80 + if (strstr(line, "[stack]")) { 81 + if (sscanf(line, "%lx-%lx", &stack_start, &stack_end) != 2) { 82 + ERROR_GLIBC("sscanf"); 83 + ret = -1; 84 + goto done; 85 + } 86 + stack_limit = stack_end - rlim.rlim_cur; 87 + goto done; 88 + } 89 + } 90 + 91 + ret = -1; 92 + ERROR("/proc/self/maps: can't find [stack]"); 93 + 94 + done: 95 + fclose(fp); 96 + 97 + return ret; 98 + } 99 + 100 + int init_signal_handler(void) 101 + { 102 + int signals[] = {SIGSEGV, SIGBUS, SIGILL, SIGABRT}; 103 + struct sigaction sa; 104 + stack_t ss; 105 + 106 + if (read_stack_limit()) 107 + return -1; 108 + 109 + ss.ss_sp = malloc(SIGSTKSZ); 110 + if (!ss.ss_sp) { 111 + ERROR_GLIBC("malloc"); 112 + return -1; 113 + } 114 + ss.ss_size = SIGSTKSZ; 115 + ss.ss_flags = 0; 116 + 117 + if (sigaltstack(&ss, NULL) == -1) { 118 + ERROR_GLIBC("sigaltstack"); 119 + return -1; 120 + } 121 + 122 + sa.sa_sigaction = signal_handler; 123 + sigemptyset(&sa.sa_mask); 124 + 125 + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; 126 + 127 + for (int i = 0; i < ARRAY_SIZE(signals); i++) { 128 + if (sigaction(signals[i], &sa, NULL) == -1) { 129 + ERROR_GLIBC("sigaction"); 130 + return -1; 131 + } 132 + } 133 + 134 + return 0; 135 + }