sas.c 4.5 KB

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