mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 11:56:58 +00:00
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()
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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" ; \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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];"
|
||||
|
||||
/*
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
|
||||
@@ -6,41 +6,34 @@
|
||||
|
||||
#ifdef CONFIG_OBJTOOL
|
||||
|
||||
#define __ASM_ANNOTATE(section, label, type) \
|
||||
.pushsection section, "M", @progbits, 8; \
|
||||
.long label - ., type; \
|
||||
.popsection
|
||||
|
||||
#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)
|
||||
__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__ */
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define COMPILE_OFFSETS
|
||||
#include <linux/kbuild.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
135
tools/objtool/signal.c
Normal file
135
tools/objtool/signal.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user