File Index
Files and directories
Sign in
FILE

signal.c

File preview with syntax highlighting.

linux-6.19.14/tools/objtool/signal.c 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
 17static unsigned long stack_limit;
 18
 19static 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
 27static 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
 60static 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
 94done:
 95	fclose(fp);
 96
 97	return ret;
 98}
 99
100int 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}
~/ Read-only file preview.