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

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Add more robust signal error handling, detect and warn about stack overflows

When the kernel build fails due to an objtool segfault, the error
message is a bit obtuse and confusing:

make[5]: *** [scripts/Makefile.build:503: drivers/scsi/qla2xxx/qla2xxx.o] Error 139
^^^^^^^^^
make[5]: *** Deleting file 'drivers/scsi/qla2xxx/qla2xxx.o'
make[4]: *** [scripts/Makefile.build:556: drivers/scsi/qla2xxx] Error 2
make[3]: *** [scripts/Makefile.build:556: drivers/scsi] Error 2
make[2]: *** [scripts/Makefile.build:556: drivers] Error 2
make[1]: *** [/home/jpoimboe/git/linux/Makefile:2013: .] Error 2
make: *** [Makefile:248: __sub-make] Error 2

Add a signal handler to objtool which prints an error message like if
the local stack has overflown (for which there's a chance as objtool
makes heavy use of recursion):

drivers/scsi/qla2xxx/qla2xxx.o: error: SIGSEGV: objtool stack overflow!

or:

drivers/scsi/qla2xxx/qla2xxx.o: error: SIGSEGV: objtool crash!

Also, re-raise the signal so the core dump still gets triggered.

[ mingo: Applied a build fix, added more comments and prettified the code. ]

Suggested-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Alexandre Chartre <alexandre.chartre@oracle.com>
Cc: David Laight <david.laight.linux@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://patch.msgid.link/mi4tihk4dbncn7belrhp6ooudhpw4vdggerktu5333w3gqf3uf@vqlhc3y667mg

authored by

Josh Poimboeuf and committed by
Ingo Molnar
799647dd ed3bf863

+141 -1
+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)
+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 + }