Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/objtool/signal.c
38179 views
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
137