sigaltstack.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #define _GNU_SOURCE
  3. #include <signal.h>
  4. #include <stdio.h>
  5. #include <stdbool.h>
  6. #include <string.h>
  7. #include <err.h>
  8. #include <errno.h>
  9. #include <limits.h>
  10. #include <sys/mman.h>
  11. #include <sys/auxv.h>
  12. #include <sys/prctl.h>
  13. #include <sys/resource.h>
  14. #include <setjmp.h>
  15. /* sigaltstack()-enforced minimum stack */
  16. #define ENFORCED_MINSIGSTKSZ 2048
  17. #ifndef AT_MINSIGSTKSZ
  18. # define AT_MINSIGSTKSZ 51
  19. #endif
  20. static int nerrs;
  21. static bool sigalrm_expected;
  22. static unsigned long at_minstack_size;
  23. static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
  24. int flags)
  25. {
  26. struct sigaction sa;
  27. memset(&sa, 0, sizeof(sa));
  28. sa.sa_sigaction = handler;
  29. sa.sa_flags = SA_SIGINFO | flags;
  30. sigemptyset(&sa.sa_mask);
  31. if (sigaction(sig, &sa, 0))
  32. err(1, "sigaction");
  33. }
  34. static void clearhandler(int sig)
  35. {
  36. struct sigaction sa;
  37. memset(&sa, 0, sizeof(sa));
  38. sa.sa_handler = SIG_DFL;
  39. sigemptyset(&sa.sa_mask);
  40. if (sigaction(sig, &sa, 0))
  41. err(1, "sigaction");
  42. }
  43. static int setup_altstack(void *start, unsigned long size)
  44. {
  45. stack_t ss;
  46. memset(&ss, 0, sizeof(ss));
  47. ss.ss_size = size;
  48. ss.ss_sp = start;
  49. return sigaltstack(&ss, NULL);
  50. }
  51. static jmp_buf jmpbuf;
  52. static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
  53. {
  54. if (sigalrm_expected) {
  55. printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM).");
  56. nerrs++;
  57. } else {
  58. printf("[OK]\tSIGSEGV signal delivered.\n");
  59. }
  60. siglongjmp(jmpbuf, 1);
  61. }
  62. static void sigalrm(int sig, siginfo_t *info, void *ctx_void)
  63. {
  64. if (!sigalrm_expected) {
  65. printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV).");
  66. nerrs++;
  67. } else {
  68. printf("[OK]\tSIGALRM signal delivered.\n");
  69. }
  70. }
  71. static void test_sigaltstack(void *altstack, unsigned long size)
  72. {
  73. if (setup_altstack(altstack, size))
  74. err(1, "sigaltstack()");
  75. sigalrm_expected = (size > at_minstack_size) ? true : false;
  76. sethandler(SIGSEGV, sigsegv, 0);
  77. sethandler(SIGALRM, sigalrm, SA_ONSTACK);
  78. if (!sigsetjmp(jmpbuf, 1)) {
  79. printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n",
  80. sigalrm_expected ? "" : "in");
  81. printf("\tRaise SIGALRM. %s is expected to be delivered.\n",
  82. sigalrm_expected ? "It" : "SIGSEGV");
  83. raise(SIGALRM);
  84. }
  85. clearhandler(SIGALRM);
  86. clearhandler(SIGSEGV);
  87. }
  88. int main(void)
  89. {
  90. void *altstack;
  91. at_minstack_size = getauxval(AT_MINSIGSTKSZ);
  92. altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE,
  93. MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
  94. if (altstack == MAP_FAILED)
  95. err(1, "mmap()");
  96. if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size)
  97. test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1);
  98. test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ);
  99. return nerrs == 0 ? 0 : 1;
  100. }