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 } 136