clone3_set_tid.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Based on Christian Brauner's clone3() example.
  4. * These tests are assuming to be running in the host's
  5. * PID namespace.
  6. */
  7. #define _GNU_SOURCE
  8. #include <errno.h>
  9. #include <linux/types.h>
  10. #include <linux/sched.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <stdbool.h>
  14. #include <sys/syscall.h>
  15. #include <sys/types.h>
  16. #include <sys/un.h>
  17. #include <sys/wait.h>
  18. #include <unistd.h>
  19. #include <sched.h>
  20. #include "kselftest.h"
  21. #include "clone3_selftests.h"
  22. #define MAX_PID_NS_LEVEL 32
  23. static int pipe_1[2];
  24. static int pipe_2[2];
  25. static void child_exit(int ret)
  26. {
  27. fflush(stdout);
  28. fflush(stderr);
  29. _exit(ret);
  30. }
  31. static int call_clone3_set_tid(pid_t *set_tid,
  32. size_t set_tid_size,
  33. int flags,
  34. int expected_pid,
  35. bool wait_for_it)
  36. {
  37. int status;
  38. pid_t pid = -1;
  39. struct __clone_args args = {
  40. .flags = flags,
  41. .exit_signal = SIGCHLD,
  42. .set_tid = ptr_to_u64(set_tid),
  43. .set_tid_size = set_tid_size,
  44. };
  45. pid = sys_clone3(&args, sizeof(args));
  46. if (pid < 0) {
  47. ksft_print_msg("%s - Failed to create new process\n",
  48. strerror(errno));
  49. return -errno;
  50. }
  51. if (pid == 0) {
  52. int ret;
  53. char tmp = 0;
  54. int exit_code = EXIT_SUCCESS;
  55. ksft_print_msg("I am the child, my PID is %d (expected %d)\n",
  56. getpid(), set_tid[0]);
  57. if (wait_for_it) {
  58. ksft_print_msg("[%d] Child is ready and waiting\n",
  59. getpid());
  60. /* Signal the parent that the child is ready */
  61. close(pipe_1[0]);
  62. ret = write(pipe_1[1], &tmp, 1);
  63. if (ret != 1) {
  64. ksft_print_msg(
  65. "Writing to pipe returned %d", ret);
  66. exit_code = EXIT_FAILURE;
  67. }
  68. close(pipe_1[1]);
  69. close(pipe_2[1]);
  70. ret = read(pipe_2[0], &tmp, 1);
  71. if (ret != 1) {
  72. ksft_print_msg(
  73. "Reading from pipe returned %d", ret);
  74. exit_code = EXIT_FAILURE;
  75. }
  76. close(pipe_2[0]);
  77. }
  78. if (set_tid[0] != getpid())
  79. child_exit(EXIT_FAILURE);
  80. child_exit(exit_code);
  81. }
  82. if (expected_pid == 0 || expected_pid == pid) {
  83. ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
  84. getpid(), pid);
  85. } else {
  86. ksft_print_msg(
  87. "Expected child pid %d does not match actual pid %d\n",
  88. expected_pid, pid);
  89. return -1;
  90. }
  91. if (waitpid(pid, &status, 0) < 0) {
  92. ksft_print_msg("Child returned %s\n", strerror(errno));
  93. return -errno;
  94. }
  95. if (!WIFEXITED(status))
  96. return -1;
  97. return WEXITSTATUS(status);
  98. }
  99. static void test_clone3_set_tid(const char *desc,
  100. pid_t *set_tid,
  101. size_t set_tid_size,
  102. int flags,
  103. int expected,
  104. int expected_pid,
  105. bool wait_for_it)
  106. {
  107. int ret;
  108. ksft_print_msg(
  109. "[%d] Trying clone3() with CLONE_SET_TID to %d and 0x%x\n",
  110. getpid(), set_tid[0], flags);
  111. ret = call_clone3_set_tid(set_tid, set_tid_size, flags, expected_pid,
  112. wait_for_it);
  113. ksft_print_msg(
  114. "[%d] clone3() with CLONE_SET_TID %d says: %d - expected %d\n",
  115. getpid(), set_tid[0], ret, expected);
  116. ksft_test_result(ret == expected, "%s with %zu TIDs and flags 0x%x\n",
  117. desc, set_tid_size, flags);
  118. }
  119. int main(int argc, char *argv[])
  120. {
  121. FILE *f;
  122. char buf;
  123. char *line;
  124. int status;
  125. int ret = -1;
  126. size_t len = 0;
  127. int pid_max = 0;
  128. uid_t uid = getuid();
  129. char proc_path[100] = {0};
  130. pid_t pid, ns1, ns2, ns3, ns_pid;
  131. pid_t set_tid[MAX_PID_NS_LEVEL * 2];
  132. ksft_print_header();
  133. ksft_set_plan(29);
  134. test_clone3_supported();
  135. if (pipe(pipe_1) < 0 || pipe(pipe_2) < 0)
  136. ksft_exit_fail_msg("pipe() failed\n");
  137. f = fopen("/proc/sys/kernel/pid_max", "r");
  138. if (f == NULL)
  139. ksft_exit_fail_msg(
  140. "%s - Could not open /proc/sys/kernel/pid_max\n",
  141. strerror(errno));
  142. fscanf(f, "%d", &pid_max);
  143. fclose(f);
  144. ksft_print_msg("/proc/sys/kernel/pid_max %d\n", pid_max);
  145. /* Try invalid settings */
  146. memset(&set_tid, 0, sizeof(set_tid));
  147. test_clone3_set_tid("invalid size, 0 TID",
  148. set_tid, MAX_PID_NS_LEVEL + 1, 0, -EINVAL, 0, 0);
  149. test_clone3_set_tid("invalid size, 0 TID",
  150. set_tid, MAX_PID_NS_LEVEL * 2, 0, -EINVAL, 0, 0);
  151. test_clone3_set_tid("invalid size, 0 TID",
  152. set_tid, MAX_PID_NS_LEVEL * 2 + 1, 0,
  153. -EINVAL, 0, 0);
  154. test_clone3_set_tid("invalid size, 0 TID",
  155. set_tid, MAX_PID_NS_LEVEL * 42, 0, -EINVAL, 0, 0);
  156. /*
  157. * This can actually work if this test running in a MAX_PID_NS_LEVEL - 1
  158. * nested PID namespace.
  159. */
  160. test_clone3_set_tid("invalid size, 0 TID",
  161. set_tid, MAX_PID_NS_LEVEL - 1, 0, -EINVAL, 0, 0);
  162. memset(&set_tid, 0xff, sizeof(set_tid));
  163. test_clone3_set_tid("invalid size, TID all 1s",
  164. set_tid, MAX_PID_NS_LEVEL + 1, 0, -EINVAL, 0, 0);
  165. test_clone3_set_tid("invalid size, TID all 1s",
  166. set_tid, MAX_PID_NS_LEVEL * 2, 0, -EINVAL, 0, 0);
  167. test_clone3_set_tid("invalid size, TID all 1s",
  168. set_tid, MAX_PID_NS_LEVEL * 2 + 1, 0,
  169. -EINVAL, 0, 0);
  170. test_clone3_set_tid("invalid size, TID all 1s",
  171. set_tid, MAX_PID_NS_LEVEL * 42, 0, -EINVAL, 0, 0);
  172. /*
  173. * This can actually work if this test running in a MAX_PID_NS_LEVEL - 1
  174. * nested PID namespace.
  175. */
  176. test_clone3_set_tid("invalid size, TID all 1s",
  177. set_tid, MAX_PID_NS_LEVEL - 1, 0, -EINVAL, 0, 0);
  178. memset(&set_tid, 0, sizeof(set_tid));
  179. /* Try with an invalid PID */
  180. set_tid[0] = 0;
  181. test_clone3_set_tid("valid size, 0 TID",
  182. set_tid, 1, 0, -EINVAL, 0, 0);
  183. set_tid[0] = -1;
  184. test_clone3_set_tid("valid size, -1 TID",
  185. set_tid, 1, 0, -EINVAL, 0, 0);
  186. /* Claim that the set_tid array actually contains 2 elements. */
  187. test_clone3_set_tid("2 TIDs, -1 and 0",
  188. set_tid, 2, 0, -EINVAL, 0, 0);
  189. /* Try it in a new PID namespace */
  190. if (uid == 0)
  191. test_clone3_set_tid("valid size, -1 TID",
  192. set_tid, 1, CLONE_NEWPID, -EINVAL, 0, 0);
  193. else
  194. ksft_test_result_skip("Clone3() with set_tid requires root\n");
  195. /* Try with a valid PID (1) this should return -EEXIST. */
  196. set_tid[0] = 1;
  197. if (uid == 0)
  198. test_clone3_set_tid("duplicate PID 1",
  199. set_tid, 1, 0, -EEXIST, 0, 0);
  200. else
  201. ksft_test_result_skip("Clone3() with set_tid requires root\n");
  202. /* Try it in a new PID namespace */
  203. if (uid == 0)
  204. test_clone3_set_tid("duplicate PID 1",
  205. set_tid, 1, CLONE_NEWPID, 0, 0, 0);
  206. else
  207. ksft_test_result_skip("Clone3() with set_tid requires root\n");
  208. /* pid_max should fail everywhere */
  209. set_tid[0] = pid_max;
  210. test_clone3_set_tid("set TID to maximum",
  211. set_tid, 1, 0, -EINVAL, 0, 0);
  212. if (uid == 0)
  213. test_clone3_set_tid("set TID to maximum",
  214. set_tid, 1, CLONE_NEWPID, -EINVAL, 0, 0);
  215. else
  216. ksft_test_result_skip("Clone3() with set_tid requires root\n");
  217. if (uid != 0) {
  218. /*
  219. * All remaining tests require root. Tell the framework
  220. * that all those tests are skipped as non-root.
  221. */
  222. ksft_cnt.ksft_xskip += ksft_plan - ksft_test_num();
  223. goto out;
  224. }
  225. /* Find the current active PID */
  226. pid = fork();
  227. if (pid == 0) {
  228. ksft_print_msg("Child has PID %d\n", getpid());
  229. child_exit(EXIT_SUCCESS);
  230. }
  231. if (waitpid(pid, &status, 0) < 0)
  232. ksft_exit_fail_msg("Waiting for child %d failed", pid);
  233. /* After the child has finished, its PID should be free. */
  234. set_tid[0] = pid;
  235. test_clone3_set_tid("reallocate child TID",
  236. set_tid, 1, 0, 0, 0, 0);
  237. /* This should fail as there is no PID 1 in that namespace */
  238. test_clone3_set_tid("duplicate child TID",
  239. set_tid, 1, CLONE_NEWPID, -EINVAL, 0, 0);
  240. /*
  241. * Creating a process with PID 1 in the newly created most nested
  242. * PID namespace and PID 'pid' in the parent PID namespace. This
  243. * needs to work.
  244. */
  245. set_tid[0] = 1;
  246. set_tid[1] = pid;
  247. test_clone3_set_tid("create PID 1 in new NS",
  248. set_tid, 2, CLONE_NEWPID, 0, pid, 0);
  249. ksft_print_msg("unshare PID namespace\n");
  250. if (unshare(CLONE_NEWPID) == -1)
  251. ksft_exit_fail_msg("unshare(CLONE_NEWPID) failed: %s\n",
  252. strerror(errno));
  253. set_tid[0] = pid;
  254. /* This should fail as there is no PID 1 in that namespace */
  255. test_clone3_set_tid("duplicate PID 1",
  256. set_tid, 1, 0, -EINVAL, 0, 0);
  257. /* Let's create a PID 1 */
  258. ns_pid = fork();
  259. if (ns_pid == 0) {
  260. /*
  261. * This and the next test cases check that all pid-s are
  262. * released on error paths.
  263. */
  264. set_tid[0] = 43;
  265. set_tid[1] = -1;
  266. test_clone3_set_tid("check leak on invalid TID -1",
  267. set_tid, 2, 0, -EINVAL, 0, 0);
  268. set_tid[0] = 43;
  269. set_tid[1] = pid;
  270. test_clone3_set_tid("check leak on invalid specific TID",
  271. set_tid, 2, 0, 0, 43, 0);
  272. ksft_print_msg("Child in PID namespace has PID %d\n", getpid());
  273. set_tid[0] = 2;
  274. test_clone3_set_tid("create PID 2 in child NS",
  275. set_tid, 1, 0, 0, 2, 0);
  276. set_tid[0] = 1;
  277. set_tid[1] = -1;
  278. set_tid[2] = pid;
  279. /* This should fail as there is invalid PID at level '1'. */
  280. test_clone3_set_tid("fail due to invalid TID at level 1",
  281. set_tid, 3, CLONE_NEWPID, -EINVAL, 0, 0);
  282. set_tid[0] = 1;
  283. set_tid[1] = 42;
  284. set_tid[2] = pid;
  285. /*
  286. * This should fail as there are not enough active PID
  287. * namespaces. Again assuming this is running in the host's
  288. * PID namespace. Not yet nested.
  289. */
  290. test_clone3_set_tid("fail due to too few active PID NSs",
  291. set_tid, 4, CLONE_NEWPID, -EINVAL, 0, 0);
  292. /*
  293. * This should work and from the parent we should see
  294. * something like 'NSpid: pid 42 1'.
  295. */
  296. test_clone3_set_tid("verify that we have 3 PID NSs",
  297. set_tid, 3, CLONE_NEWPID, 0, 42, true);
  298. child_exit(ksft_cnt.ksft_fail);
  299. }
  300. close(pipe_1[1]);
  301. close(pipe_2[0]);
  302. while (read(pipe_1[0], &buf, 1) > 0) {
  303. ksft_print_msg("[%d] Child is ready and waiting\n", getpid());
  304. break;
  305. }
  306. snprintf(proc_path, sizeof(proc_path), "/proc/%d/status", pid);
  307. f = fopen(proc_path, "r");
  308. if (f == NULL)
  309. ksft_exit_fail_msg(
  310. "%s - Could not open %s\n",
  311. strerror(errno), proc_path);
  312. while (getline(&line, &len, f) != -1) {
  313. if (strstr(line, "NSpid")) {
  314. int i;
  315. /* Verify that all generated PIDs are as expected. */
  316. i = sscanf(line, "NSpid:\t%d\t%d\t%d",
  317. &ns3, &ns2, &ns1);
  318. if (i != 3) {
  319. ksft_print_msg(
  320. "Unexpected 'NSPid:' entry: %s",
  321. line);
  322. ns1 = ns2 = ns3 = 0;
  323. }
  324. break;
  325. }
  326. }
  327. fclose(f);
  328. free(line);
  329. close(pipe_2[0]);
  330. /* Tell the clone3()'d child to finish. */
  331. write(pipe_2[1], &buf, 1);
  332. close(pipe_2[1]);
  333. if (waitpid(ns_pid, &status, 0) < 0) {
  334. ksft_print_msg("Child returned %s\n", strerror(errno));
  335. ret = -errno;
  336. goto out;
  337. }
  338. if (!WIFEXITED(status))
  339. ksft_test_result_fail("Child error\n");
  340. ksft_cnt.ksft_pass += 6 - (ksft_cnt.ksft_fail - WEXITSTATUS(status));
  341. ksft_cnt.ksft_fail = WEXITSTATUS(status);
  342. ksft_print_msg("Expecting PIDs %d, 42, 1\n", pid);
  343. ksft_print_msg("Have PIDs in namespaces: %d, %d, %d\n", ns3, ns2, ns1);
  344. ksft_test_result(ns3 == pid && ns2 == 42 && ns1 == 1,
  345. "PIDs in all namespaces as expected\n");
  346. out:
  347. ret = 0;
  348. if (ret)
  349. ksft_exit_fail();
  350. ksft_exit_pass();
  351. }