sas.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Stas Sergeev <stsp@users.sourceforge.net>
  4. *
  5. * test sigaltstack(SS_ONSTACK | SS_AUTODISARM)
  6. * If that succeeds, then swapcontext() can be used inside sighandler safely.
  7. *
  8. */
  9. #define _GNU_SOURCE
  10. #include <signal.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <sys/mman.h>
  14. #include <ucontext.h>
  15. #include <alloca.h>
  16. #include <string.h>
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <sys/auxv.h>
  20. #include "../kselftest.h"
  21. #include "current_stack_pointer.h"
  22. #ifndef SS_AUTODISARM
  23. #define SS_AUTODISARM (1U << 31)
  24. #endif
  25. #ifndef AT_MINSIGSTKSZ
  26. #define AT_MINSIGSTKSZ 51
  27. #endif
  28. static unsigned int stack_size;
  29. static void *sstack, *ustack;
  30. static ucontext_t uc, sc;
  31. static const char *msg = "[OK]\tStack preserved";
  32. static const char *msg2 = "[FAIL]\tStack corrupted";
  33. struct stk_data {
  34. char msg[128];
  35. int flag;
  36. };
  37. void my_usr1(int sig, siginfo_t *si, void *u)
  38. {
  39. char *aa;
  40. int err;
  41. stack_t stk;
  42. struct stk_data *p;
  43. if (sp < (unsigned long)sstack ||
  44. sp >= (unsigned long)sstack + stack_size) {
  45. ksft_exit_fail_msg("SP is not on sigaltstack\n");
  46. }
  47. /* put some data on stack. other sighandler will try to overwrite it */
  48. aa = alloca(1024);
  49. assert(aa);
  50. p = (struct stk_data *)(aa + 512);
  51. strcpy(p->msg, msg);
  52. p->flag = 1;
  53. ksft_print_msg("[RUN]\tsignal USR1\n");
  54. err = sigaltstack(NULL, &stk);
  55. if (err) {
  56. ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
  57. exit(EXIT_FAILURE);
  58. }
  59. if (stk.ss_flags != SS_DISABLE)
  60. ksft_test_result_fail("tss_flags=%x, should be SS_DISABLE\n",
  61. stk.ss_flags);
  62. else
  63. ksft_test_result_pass(
  64. "sigaltstack is disabled in sighandler\n");
  65. swapcontext(&sc, &uc);
  66. ksft_print_msg("%s\n", p->msg);
  67. if (!p->flag) {
  68. ksft_exit_fail_msg("[RUN]\tAborting\n");
  69. exit(EXIT_FAILURE);
  70. }
  71. }
  72. void my_usr2(int sig, siginfo_t *si, void *u)
  73. {
  74. char *aa;
  75. struct stk_data *p;
  76. ksft_print_msg("[RUN]\tsignal USR2\n");
  77. aa = alloca(1024);
  78. /* dont run valgrind on this */
  79. /* try to find the data stored by previous sighandler */
  80. p = memmem(aa, 1024, msg, strlen(msg));
  81. if (p) {
  82. ksft_test_result_fail("sigaltstack re-used\n");
  83. /* corrupt the data */
  84. strcpy(p->msg, msg2);
  85. /* tell other sighandler that his data is corrupted */
  86. p->flag = 0;
  87. }
  88. }
  89. static void switch_fn(void)
  90. {
  91. ksft_print_msg("[RUN]\tswitched to user ctx\n");
  92. raise(SIGUSR2);
  93. setcontext(&sc);
  94. }
  95. int main(void)
  96. {
  97. struct sigaction act;
  98. stack_t stk;
  99. int err;
  100. /* Make sure more than the required minimum. */
  101. stack_size = getauxval(AT_MINSIGSTKSZ) + SIGSTKSZ;
  102. ksft_print_msg("[NOTE]\tthe stack size is %u\n", stack_size);
  103. ksft_print_header();
  104. ksft_set_plan(3);
  105. sigemptyset(&act.sa_mask);
  106. act.sa_flags = SA_ONSTACK | SA_SIGINFO;
  107. act.sa_sigaction = my_usr1;
  108. sigaction(SIGUSR1, &act, NULL);
  109. act.sa_sigaction = my_usr2;
  110. sigaction(SIGUSR2, &act, NULL);
  111. sstack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
  112. MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
  113. if (sstack == MAP_FAILED) {
  114. ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));
  115. return EXIT_FAILURE;
  116. }
  117. err = sigaltstack(NULL, &stk);
  118. if (err) {
  119. ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
  120. exit(EXIT_FAILURE);
  121. }
  122. if (stk.ss_flags == SS_DISABLE) {
  123. ksft_test_result_pass(
  124. "Initial sigaltstack state was SS_DISABLE\n");
  125. } else {
  126. ksft_exit_fail_msg("Initial sigaltstack state was %x; "
  127. "should have been SS_DISABLE\n", stk.ss_flags);
  128. return EXIT_FAILURE;
  129. }
  130. stk.ss_sp = sstack;
  131. stk.ss_size = stack_size;
  132. stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;
  133. err = sigaltstack(&stk, NULL);
  134. if (err) {
  135. if (errno == EINVAL) {
  136. ksft_test_result_skip(
  137. "[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
  138. /*
  139. * If test cases for the !SS_AUTODISARM variant were
  140. * added, we could still run them. We don't have any
  141. * test cases like that yet, so just exit and report
  142. * success.
  143. */
  144. return 0;
  145. } else {
  146. ksft_exit_fail_msg(
  147. "sigaltstack(SS_ONSTACK | SS_AUTODISARM) %s\n",
  148. strerror(errno));
  149. return EXIT_FAILURE;
  150. }
  151. }
  152. ustack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
  153. MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
  154. if (ustack == MAP_FAILED) {
  155. ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));
  156. return EXIT_FAILURE;
  157. }
  158. getcontext(&uc);
  159. uc.uc_link = NULL;
  160. uc.uc_stack.ss_sp = ustack;
  161. uc.uc_stack.ss_size = stack_size;
  162. makecontext(&uc, switch_fn, 0);
  163. raise(SIGUSR1);
  164. err = sigaltstack(NULL, &stk);
  165. if (err) {
  166. ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
  167. exit(EXIT_FAILURE);
  168. }
  169. if (stk.ss_flags != SS_AUTODISARM) {
  170. ksft_exit_fail_msg("ss_flags=%x, should be SS_AUTODISARM\n",
  171. stk.ss_flags);
  172. exit(EXIT_FAILURE);
  173. }
  174. ksft_test_result_pass(
  175. "sigaltstack is still SS_AUTODISARM after signal\n");
  176. ksft_exit_pass();
  177. return 0;
  178. }