sas.c 4.1 KB

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