tsync_test.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Landlock tests - Enforcing the same restrictions across multiple threads
  4. *
  5. * Copyright © 2025 Günther Noack <gnoack3000@gmail.com>
  6. */
  7. #define _GNU_SOURCE
  8. #include <linux/landlock.h>
  9. #include <pthread.h>
  10. #include <signal.h>
  11. #include <sys/prctl.h>
  12. #include "common.h"
  13. /* create_ruleset - Create a simple ruleset FD common to all tests */
  14. static int create_ruleset(struct __test_metadata *const _metadata)
  15. {
  16. struct landlock_ruleset_attr ruleset_attr = {
  17. .handled_access_fs = (LANDLOCK_ACCESS_FS_WRITE_FILE |
  18. LANDLOCK_ACCESS_FS_TRUNCATE),
  19. };
  20. const int ruleset_fd =
  21. landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
  22. ASSERT_LE(0, ruleset_fd)
  23. {
  24. TH_LOG("landlock_create_ruleset: %s", strerror(errno));
  25. }
  26. return ruleset_fd;
  27. }
  28. TEST(single_threaded_success)
  29. {
  30. const int ruleset_fd = create_ruleset(_metadata);
  31. disable_caps(_metadata);
  32. ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
  33. ASSERT_EQ(0, landlock_restrict_self(ruleset_fd,
  34. LANDLOCK_RESTRICT_SELF_TSYNC));
  35. EXPECT_EQ(0, close(ruleset_fd));
  36. }
  37. static void store_no_new_privs(void *data)
  38. {
  39. bool *nnp = data;
  40. if (!nnp)
  41. return;
  42. *nnp = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
  43. }
  44. static void *idle(void *data)
  45. {
  46. pthread_cleanup_push(store_no_new_privs, data);
  47. while (true)
  48. sleep(1);
  49. pthread_cleanup_pop(1);
  50. }
  51. TEST(multi_threaded_success)
  52. {
  53. pthread_t t1, t2;
  54. bool no_new_privs1, no_new_privs2;
  55. const int ruleset_fd = create_ruleset(_metadata);
  56. disable_caps(_metadata);
  57. ASSERT_EQ(0, pthread_create(&t1, NULL, idle, &no_new_privs1));
  58. ASSERT_EQ(0, pthread_create(&t2, NULL, idle, &no_new_privs2));
  59. ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
  60. EXPECT_EQ(0, landlock_restrict_self(ruleset_fd,
  61. LANDLOCK_RESTRICT_SELF_TSYNC));
  62. ASSERT_EQ(0, pthread_cancel(t1));
  63. ASSERT_EQ(0, pthread_cancel(t2));
  64. ASSERT_EQ(0, pthread_join(t1, NULL));
  65. ASSERT_EQ(0, pthread_join(t2, NULL));
  66. /* The no_new_privs flag was implicitly enabled on all threads. */
  67. EXPECT_TRUE(no_new_privs1);
  68. EXPECT_TRUE(no_new_privs2);
  69. EXPECT_EQ(0, close(ruleset_fd));
  70. }
  71. TEST(multi_threaded_success_despite_diverging_domains)
  72. {
  73. pthread_t t1, t2;
  74. const int ruleset_fd = create_ruleset(_metadata);
  75. disable_caps(_metadata);
  76. ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
  77. ASSERT_EQ(0, pthread_create(&t1, NULL, idle, NULL));
  78. ASSERT_EQ(0, pthread_create(&t2, NULL, idle, NULL));
  79. /*
  80. * The main thread enforces a ruleset,
  81. * thereby bringing the threads' Landlock domains out of sync.
  82. */
  83. EXPECT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
  84. /* Still, TSYNC succeeds, bringing the threads in sync again. */
  85. EXPECT_EQ(0, landlock_restrict_self(ruleset_fd,
  86. LANDLOCK_RESTRICT_SELF_TSYNC));
  87. ASSERT_EQ(0, pthread_cancel(t1));
  88. ASSERT_EQ(0, pthread_cancel(t2));
  89. ASSERT_EQ(0, pthread_join(t1, NULL));
  90. ASSERT_EQ(0, pthread_join(t2, NULL));
  91. EXPECT_EQ(0, close(ruleset_fd));
  92. }
  93. struct thread_restrict_data {
  94. pthread_t t;
  95. int ruleset_fd;
  96. int result;
  97. };
  98. static void *thread_restrict(void *data)
  99. {
  100. struct thread_restrict_data *d = data;
  101. d->result = landlock_restrict_self(d->ruleset_fd,
  102. LANDLOCK_RESTRICT_SELF_TSYNC);
  103. return NULL;
  104. }
  105. TEST(competing_enablement)
  106. {
  107. const int ruleset_fd = create_ruleset(_metadata);
  108. struct thread_restrict_data d[] = {
  109. { .ruleset_fd = ruleset_fd },
  110. { .ruleset_fd = ruleset_fd },
  111. };
  112. disable_caps(_metadata);
  113. ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
  114. ASSERT_EQ(0, pthread_create(&d[0].t, NULL, thread_restrict, &d[0]));
  115. ASSERT_EQ(0, pthread_create(&d[1].t, NULL, thread_restrict, &d[1]));
  116. /* Wait for threads to finish. */
  117. ASSERT_EQ(0, pthread_join(d[0].t, NULL));
  118. ASSERT_EQ(0, pthread_join(d[1].t, NULL));
  119. /* Expect that both succeeded. */
  120. EXPECT_EQ(0, d[0].result);
  121. EXPECT_EQ(0, d[1].result);
  122. EXPECT_EQ(0, close(ruleset_fd));
  123. }
  124. static void signal_nop_handler(int sig)
  125. {
  126. }
  127. struct signaler_data {
  128. pthread_t target;
  129. volatile bool stop;
  130. };
  131. static void *signaler_thread(void *data)
  132. {
  133. struct signaler_data *sd = data;
  134. while (!sd->stop)
  135. pthread_kill(sd->target, SIGUSR1);
  136. return NULL;
  137. }
  138. /*
  139. * Number of idle sibling threads. This must be large enough that even on
  140. * machines with many cores, the sibling threads cannot all complete their
  141. * credential preparation in a single parallel wave, otherwise the signaler
  142. * thread has no window to interrupt wait_for_completion_interruptible().
  143. * 200 threads on a 64-core machine yields ~3 serialized waves, giving the
  144. * tight signal loop enough time to land an interruption.
  145. */
  146. #define NUM_IDLE_THREADS 200
  147. /*
  148. * Exercises the tsync interruption and cancellation paths in tsync.c.
  149. *
  150. * When a signal interrupts the calling thread while it waits for sibling
  151. * threads to finish their credential preparation
  152. * (wait_for_completion_interruptible in landlock_restrict_sibling_threads),
  153. * the kernel sets ERESTARTNOINTR, cancels queued task works that have not
  154. * started yet (cancel_tsync_works), then waits for the remaining works to
  155. * finish. On the error return, syscalls.c aborts the prepared credentials.
  156. * The kernel automatically restarts the syscall, so userspace sees success.
  157. */
  158. TEST(tsync_interrupt)
  159. {
  160. size_t i;
  161. pthread_t threads[NUM_IDLE_THREADS];
  162. pthread_t signaler;
  163. struct signaler_data sd;
  164. struct sigaction sa = {};
  165. const int ruleset_fd = create_ruleset(_metadata);
  166. disable_caps(_metadata);
  167. /* Install a no-op SIGUSR1 handler so the signal does not kill us. */
  168. sa.sa_handler = signal_nop_handler;
  169. sigemptyset(&sa.sa_mask);
  170. ASSERT_EQ(0, sigaction(SIGUSR1, &sa, NULL));
  171. ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
  172. for (i = 0; i < NUM_IDLE_THREADS; i++)
  173. ASSERT_EQ(0, pthread_create(&threads[i], NULL, idle, NULL));
  174. /*
  175. * Start a signaler thread that continuously sends SIGUSR1 to the
  176. * calling thread. This maximizes the chance of interrupting
  177. * wait_for_completion_interruptible() in the kernel's tsync path.
  178. */
  179. sd.target = pthread_self();
  180. sd.stop = false;
  181. ASSERT_EQ(0, pthread_create(&signaler, NULL, signaler_thread, &sd));
  182. /*
  183. * The syscall may be interrupted and transparently restarted by the
  184. * kernel (ERESTARTNOINTR). From userspace, it should always succeed.
  185. */
  186. EXPECT_EQ(0, landlock_restrict_self(ruleset_fd,
  187. LANDLOCK_RESTRICT_SELF_TSYNC));
  188. sd.stop = true;
  189. ASSERT_EQ(0, pthread_join(signaler, NULL));
  190. for (i = 0; i < NUM_IDLE_THREADS; i++) {
  191. ASSERT_EQ(0, pthread_cancel(threads[i]));
  192. ASSERT_EQ(0, pthread_join(threads[i], NULL));
  193. }
  194. EXPECT_EQ(0, close(ruleset_fd));
  195. }
  196. TEST_HARNESS_MAIN