mangle_uc_sigmask.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2024 ARM Ltd.
  4. *
  5. * Author: Dev Jain <dev.jain@arm.com>
  6. *
  7. * Test describing a clear distinction between signal states - delivered and
  8. * blocked, and their relation with ucontext.
  9. *
  10. * A process can request blocking of a signal by masking it into its set of
  11. * blocked signals; such a signal, when sent to the process by the kernel,
  12. * will get blocked by the process and it may later unblock it and take an
  13. * action. At that point, the signal will be delivered.
  14. *
  15. * We test the following functionalities of the kernel:
  16. *
  17. * ucontext_t describes the interrupted context of the thread; this implies
  18. * that, in case of registering a handler and catching the corresponding
  19. * signal, that state is before what was jumping into the handler.
  20. *
  21. * The thread's mask of blocked signals can be permanently changed, i.e, not
  22. * just during the execution of the handler, by mangling with uc_sigmask
  23. * from inside the handler.
  24. *
  25. * Assume that we block the set of signals, S1, by sigaction(), and say, the
  26. * signal for which the handler was installed, is S2. When S2 is sent to the
  27. * program, it will be considered "delivered", since we will act on the
  28. * signal and jump to the handler. Any instances of S1 or S2 raised, while the
  29. * program is executing inside the handler, will be blocked; they will be
  30. * delivered immediately upon termination of the handler.
  31. *
  32. * For standard signals (also see real-time signals in the man page), multiple
  33. * blocked instances of the same signal are not queued; such a signal will
  34. * be delivered just once.
  35. */
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <signal.h>
  39. #include <ucontext.h>
  40. #include "kselftest.h"
  41. void handler_verify_ucontext(int signo, siginfo_t *info, void *uc)
  42. {
  43. int ret;
  44. /* Kernel dumps ucontext with USR2 blocked */
  45. ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGUSR2);
  46. ksft_test_result(ret == 1, "USR2 blocked in ucontext\n");
  47. /*
  48. * USR2 is blocked; can be delivered neither here, nor after
  49. * exit from handler
  50. */
  51. if (raise(SIGUSR2))
  52. ksft_exit_fail_perror("raise");
  53. }
  54. void handler_segv(int signo, siginfo_t *info, void *uc)
  55. {
  56. /*
  57. * Three cases possible:
  58. * 1. Program already terminated due to segmentation fault.
  59. * 2. SEGV was blocked even after returning from handler_usr.
  60. * 3. SEGV was delivered on returning from handler_usr.
  61. * The last option must happen.
  62. */
  63. ksft_test_result_pass("SEGV delivered\n");
  64. }
  65. static int cnt;
  66. void handler_usr(int signo, siginfo_t *info, void *uc)
  67. {
  68. int ret;
  69. /*
  70. * Break out of infinite recursion caused by raise(SIGUSR1) invoked
  71. * from inside the handler
  72. */
  73. ++cnt;
  74. if (cnt > 1)
  75. return;
  76. /* SEGV blocked during handler execution, delivered on return */
  77. if (raise(SIGSEGV))
  78. ksft_exit_fail_perror("raise");
  79. ksft_print_msg("SEGV bypassed successfully\n");
  80. /*
  81. * Signal responsible for handler invocation is blocked by default;
  82. * delivered on return, leading to recursion
  83. */
  84. if (raise(SIGUSR1))
  85. ksft_exit_fail_perror("raise");
  86. ksft_test_result(cnt == 1,
  87. "USR1 is blocked, cannot invoke handler right now\n");
  88. /* Raise USR1 again; only one instance must be delivered upon exit */
  89. if (raise(SIGUSR1))
  90. ksft_exit_fail_perror("raise");
  91. /* SEGV has been blocked in sa_mask, but ucontext is empty */
  92. ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGSEGV);
  93. ksft_test_result(ret == 0, "SEGV not blocked in ucontext\n");
  94. /* USR1 has been blocked, but ucontext is empty */
  95. ret = sigismember(&(((ucontext_t *)uc)->uc_sigmask), SIGUSR1);
  96. ksft_test_result(ret == 0, "USR1 not blocked in ucontext\n");
  97. /*
  98. * Mangle ucontext; this will be copied back into &current->blocked
  99. * on return from the handler.
  100. */
  101. if (sigaddset(&((ucontext_t *)uc)->uc_sigmask, SIGUSR2))
  102. ksft_exit_fail_perror("sigaddset");
  103. }
  104. int main(int argc, char *argv[])
  105. {
  106. struct sigaction act, act2;
  107. sigset_t set, oldset;
  108. ksft_print_header();
  109. ksft_set_plan(7);
  110. act.sa_flags = SA_SIGINFO;
  111. act.sa_sigaction = &handler_usr;
  112. /* Add SEGV to blocked mask */
  113. if (sigemptyset(&act.sa_mask) || sigaddset(&act.sa_mask, SIGSEGV)
  114. || (sigismember(&act.sa_mask, SIGSEGV) != 1))
  115. ksft_exit_fail_msg("Cannot add SEGV to blocked mask\n");
  116. if (sigaction(SIGUSR1, &act, NULL))
  117. ksft_exit_fail_perror("Cannot install handler");
  118. act2.sa_flags = SA_SIGINFO;
  119. act2.sa_sigaction = &handler_segv;
  120. if (sigaction(SIGSEGV, &act2, NULL))
  121. ksft_exit_fail_perror("Cannot install handler");
  122. /* Invoke handler */
  123. if (raise(SIGUSR1))
  124. ksft_exit_fail_perror("raise");
  125. /* USR1 must not be queued */
  126. ksft_test_result(cnt == 2, "handler invoked only twice\n");
  127. /* Mangled ucontext implies USR2 is blocked for current thread */
  128. if (raise(SIGUSR2))
  129. ksft_exit_fail_perror("raise");
  130. ksft_print_msg("USR2 bypassed successfully\n");
  131. act.sa_sigaction = &handler_verify_ucontext;
  132. if (sigaction(SIGUSR1, &act, NULL))
  133. ksft_exit_fail_perror("Cannot install handler");
  134. if (raise(SIGUSR1))
  135. ksft_exit_fail_perror("raise");
  136. /*
  137. * Raising USR2 in handler_verify_ucontext is redundant since it
  138. * is blocked
  139. */
  140. ksft_print_msg("USR2 still blocked on return from handler\n");
  141. /* Confirm USR2 blockage by sigprocmask() too */
  142. if (sigemptyset(&set))
  143. ksft_exit_fail_perror("sigemptyset");
  144. if (sigprocmask(SIG_BLOCK, &set, &oldset))
  145. ksft_exit_fail_perror("sigprocmask");
  146. ksft_test_result(sigismember(&oldset, SIGUSR2) == 1,
  147. "USR2 present in &current->blocked\n");
  148. ksft_finished();
  149. }