signal.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. #include <objtool/objtool.h>
  14. #include <objtool/warn.h>
  15. static unsigned long stack_limit;
  16. static bool is_stack_overflow(void *fault_addr)
  17. {
  18. unsigned long fault = (unsigned long)fault_addr;
  19. /* Check if fault is in the guard page just below the limit. */
  20. return fault < stack_limit && fault >= stack_limit - 4096;
  21. }
  22. static void signal_handler(int sig_num, siginfo_t *info, void *context)
  23. {
  24. struct sigaction sa_dfl = {0};
  25. const char *sig_name;
  26. char msg[256];
  27. int msg_len;
  28. switch (sig_num) {
  29. case SIGSEGV: sig_name = "SIGSEGV"; break;
  30. case SIGBUS: sig_name = "SIGBUS"; break;
  31. case SIGILL: sig_name = "SIGILL"; break;
  32. case SIGABRT: sig_name = "SIGABRT"; break;
  33. default: sig_name = "Unknown signal"; break;
  34. }
  35. if (is_stack_overflow(info->si_addr)) {
  36. msg_len = snprintf(msg, sizeof(msg),
  37. "%s: error: %s: objtool stack overflow!\n",
  38. objname, sig_name);
  39. } else {
  40. msg_len = snprintf(msg, sizeof(msg),
  41. "%s: error: %s: objtool crash!\n",
  42. objname, sig_name);
  43. }
  44. msg_len = write(STDERR_FILENO, msg, msg_len);
  45. /* Re-raise the signal to trigger the core dump */
  46. sa_dfl.sa_handler = SIG_DFL;
  47. sigaction(sig_num, &sa_dfl, NULL);
  48. raise(sig_num);
  49. }
  50. static int read_stack_limit(void)
  51. {
  52. unsigned long stack_start, stack_end;
  53. struct rlimit rlim;
  54. char line[256];
  55. int ret = 0;
  56. FILE *fp;
  57. if (getrlimit(RLIMIT_STACK, &rlim)) {
  58. ERROR_GLIBC("getrlimit");
  59. return -1;
  60. }
  61. fp = fopen("/proc/self/maps", "r");
  62. if (!fp) {
  63. ERROR_GLIBC("fopen");
  64. return -1;
  65. }
  66. while (fgets(line, sizeof(line), fp)) {
  67. if (strstr(line, "[stack]")) {
  68. if (sscanf(line, "%lx-%lx", &stack_start, &stack_end) != 2) {
  69. ERROR_GLIBC("sscanf");
  70. ret = -1;
  71. goto done;
  72. }
  73. stack_limit = stack_end - rlim.rlim_cur;
  74. goto done;
  75. }
  76. }
  77. ret = -1;
  78. ERROR("/proc/self/maps: can't find [stack]");
  79. done:
  80. fclose(fp);
  81. return ret;
  82. }
  83. int init_signal_handler(void)
  84. {
  85. int signals[] = {SIGSEGV, SIGBUS, SIGILL, SIGABRT};
  86. struct sigaction sa;
  87. stack_t ss;
  88. if (read_stack_limit())
  89. return -1;
  90. ss.ss_sp = malloc(SIGSTKSZ);
  91. if (!ss.ss_sp) {
  92. ERROR_GLIBC("malloc");
  93. return -1;
  94. }
  95. ss.ss_size = SIGSTKSZ;
  96. ss.ss_flags = 0;
  97. if (sigaltstack(&ss, NULL) == -1) {
  98. ERROR_GLIBC("sigaltstack");
  99. return -1;
  100. }
  101. sa.sa_sigaction = signal_handler;
  102. sigemptyset(&sa.sa_mask);
  103. sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
  104. for (int i = 0; i < ARRAY_SIZE(signals); i++) {
  105. if (sigaction(signals[i], &sa, NULL) == -1) {
  106. ERROR_GLIBC("sigaction");
  107. return -1;
  108. }
  109. }
  110. return 0;
  111. }