clone3.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Based on Christian Brauner's clone3() example */
  3. #define _GNU_SOURCE
  4. #include <errno.h>
  5. #include <inttypes.h>
  6. #include <linux/types.h>
  7. #include <linux/sched.h>
  8. #include <stdbool.h>
  9. #include <stdint.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <sys/syscall.h>
  13. #include <sys/types.h>
  14. #include <sys/un.h>
  15. #include <sys/wait.h>
  16. #include <unistd.h>
  17. #include <sched.h>
  18. #include "kselftest.h"
  19. #include "clone3_selftests.h"
  20. enum test_mode {
  21. CLONE3_ARGS_NO_TEST,
  22. CLONE3_ARGS_ALL_0,
  23. CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
  24. CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
  25. CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
  26. CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
  27. };
  28. static int call_clone3(uint64_t flags, size_t size, enum test_mode test_mode)
  29. {
  30. struct __clone_args args = {
  31. .flags = flags,
  32. .exit_signal = SIGCHLD,
  33. };
  34. struct clone_args_extended {
  35. struct __clone_args args;
  36. __aligned_u64 excess_space[2];
  37. } args_ext;
  38. pid_t pid = -1;
  39. int status;
  40. memset(&args_ext, 0, sizeof(args_ext));
  41. if (size > sizeof(struct __clone_args))
  42. args_ext.excess_space[1] = 1;
  43. if (size == 0)
  44. size = sizeof(struct __clone_args);
  45. switch (test_mode) {
  46. case CLONE3_ARGS_NO_TEST:
  47. /*
  48. * Uses default 'flags' and 'SIGCHLD'
  49. * assignment.
  50. */
  51. break;
  52. case CLONE3_ARGS_ALL_0:
  53. args.flags = 0;
  54. args.exit_signal = 0;
  55. break;
  56. case CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG:
  57. args.exit_signal = 0xbadc0ded00000000ULL;
  58. break;
  59. case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG:
  60. args.exit_signal = 0x0000000080000000ULL;
  61. break;
  62. case CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG:
  63. args.exit_signal = 0x0000000000000100ULL;
  64. break;
  65. case CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG:
  66. args.exit_signal = 0x00000000000000f0ULL;
  67. break;
  68. }
  69. memcpy(&args_ext.args, &args, sizeof(struct __clone_args));
  70. pid = sys_clone3((struct __clone_args *)&args_ext, size);
  71. if (pid < 0) {
  72. ksft_print_msg("%s - Failed to create new process\n",
  73. strerror(errno));
  74. return -errno;
  75. }
  76. if (pid == 0) {
  77. ksft_print_msg("I am the child, my PID is %d\n", getpid());
  78. _exit(EXIT_SUCCESS);
  79. }
  80. ksft_print_msg("I am the parent (%d). My child's pid is %d\n",
  81. getpid(), pid);
  82. if (waitpid(-1, &status, __WALL) < 0) {
  83. ksft_print_msg("waitpid() returned %s\n", strerror(errno));
  84. return -errno;
  85. }
  86. if (!WIFEXITED(status)) {
  87. ksft_print_msg("Child did not exit normally, status 0x%x\n",
  88. status);
  89. return EXIT_FAILURE;
  90. }
  91. if (WEXITSTATUS(status))
  92. return WEXITSTATUS(status);
  93. return 0;
  94. }
  95. static bool test_clone3(uint64_t flags, size_t size, int expected,
  96. enum test_mode test_mode)
  97. {
  98. int ret;
  99. ksft_print_msg(
  100. "[%d] Trying clone3() with flags %#" PRIx64 " (size %zu)\n",
  101. getpid(), flags, size);
  102. ret = call_clone3(flags, size, test_mode);
  103. ksft_print_msg("[%d] clone3() with flags says: %d expected %d\n",
  104. getpid(), ret, expected);
  105. if (ret != expected) {
  106. ksft_print_msg(
  107. "[%d] Result (%d) is different than expected (%d)\n",
  108. getpid(), ret, expected);
  109. return false;
  110. }
  111. return true;
  112. }
  113. typedef bool (*filter_function)(void);
  114. typedef size_t (*size_function)(void);
  115. static bool not_root(void)
  116. {
  117. if (getuid() != 0) {
  118. ksft_print_msg("Not running as root\n");
  119. return true;
  120. }
  121. return false;
  122. }
  123. static bool no_timenamespace(void)
  124. {
  125. if (not_root())
  126. return true;
  127. if (!access("/proc/self/ns/time", F_OK))
  128. return false;
  129. ksft_print_msg("Time namespaces are not supported\n");
  130. return true;
  131. }
  132. static size_t page_size_plus_8(void)
  133. {
  134. return getpagesize() + 8;
  135. }
  136. struct test {
  137. const char *name;
  138. uint64_t flags;
  139. size_t size;
  140. size_function size_function;
  141. int expected;
  142. enum test_mode test_mode;
  143. filter_function filter;
  144. };
  145. static const struct test tests[] = {
  146. {
  147. .name = "simple clone3()",
  148. .flags = 0,
  149. .size = 0,
  150. .expected = 0,
  151. .test_mode = CLONE3_ARGS_NO_TEST,
  152. },
  153. {
  154. .name = "clone3() in a new PID_NS",
  155. .flags = CLONE_NEWPID,
  156. .size = 0,
  157. .expected = 0,
  158. .test_mode = CLONE3_ARGS_NO_TEST,
  159. .filter = not_root,
  160. },
  161. {
  162. .name = "CLONE_ARGS_SIZE_VER0",
  163. .flags = 0,
  164. .size = CLONE_ARGS_SIZE_VER0,
  165. .expected = 0,
  166. .test_mode = CLONE3_ARGS_NO_TEST,
  167. },
  168. {
  169. .name = "CLONE_ARGS_SIZE_VER0 - 8",
  170. .flags = 0,
  171. .size = CLONE_ARGS_SIZE_VER0 - 8,
  172. .expected = -EINVAL,
  173. .test_mode = CLONE3_ARGS_NO_TEST,
  174. },
  175. {
  176. .name = "sizeof(struct clone_args) + 8",
  177. .flags = 0,
  178. .size = sizeof(struct __clone_args) + 8,
  179. .expected = 0,
  180. .test_mode = CLONE3_ARGS_NO_TEST,
  181. },
  182. {
  183. .name = "exit_signal with highest 32 bits non-zero",
  184. .flags = 0,
  185. .size = 0,
  186. .expected = -EINVAL,
  187. .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_BIG,
  188. },
  189. {
  190. .name = "negative 32-bit exit_signal",
  191. .flags = 0,
  192. .size = 0,
  193. .expected = -EINVAL,
  194. .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NEG,
  195. },
  196. {
  197. .name = "exit_signal not fitting into CSIGNAL mask",
  198. .flags = 0,
  199. .size = 0,
  200. .expected = -EINVAL,
  201. .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_CSIG,
  202. },
  203. {
  204. .name = "NSIG < exit_signal < CSIG",
  205. .flags = 0,
  206. .size = 0,
  207. .expected = -EINVAL,
  208. .test_mode = CLONE3_ARGS_INVAL_EXIT_SIGNAL_NSIG,
  209. },
  210. {
  211. .name = "Arguments sizeof(struct clone_args) + 8",
  212. .flags = 0,
  213. .size = sizeof(struct __clone_args) + 8,
  214. .expected = 0,
  215. .test_mode = CLONE3_ARGS_ALL_0,
  216. },
  217. {
  218. .name = "Arguments sizeof(struct clone_args) + 16",
  219. .flags = 0,
  220. .size = sizeof(struct __clone_args) + 16,
  221. .expected = -E2BIG,
  222. .test_mode = CLONE3_ARGS_ALL_0,
  223. },
  224. {
  225. .name = "Arguments sizeof(struct clone_arg) * 2",
  226. .flags = 0,
  227. .size = sizeof(struct __clone_args) + 16,
  228. .expected = -E2BIG,
  229. .test_mode = CLONE3_ARGS_ALL_0,
  230. },
  231. {
  232. .name = "Arguments > page size",
  233. .flags = 0,
  234. .size_function = page_size_plus_8,
  235. .expected = -E2BIG,
  236. .test_mode = CLONE3_ARGS_NO_TEST,
  237. },
  238. {
  239. .name = "CLONE_ARGS_SIZE_VER0 in a new PID NS",
  240. .flags = CLONE_NEWPID,
  241. .size = CLONE_ARGS_SIZE_VER0,
  242. .expected = 0,
  243. .test_mode = CLONE3_ARGS_NO_TEST,
  244. .filter = not_root,
  245. },
  246. {
  247. .name = "CLONE_ARGS_SIZE_VER0 - 8 in a new PID NS",
  248. .flags = CLONE_NEWPID,
  249. .size = CLONE_ARGS_SIZE_VER0 - 8,
  250. .expected = -EINVAL,
  251. .test_mode = CLONE3_ARGS_NO_TEST,
  252. },
  253. {
  254. .name = "sizeof(struct clone_args) + 8 in a new PID NS",
  255. .flags = CLONE_NEWPID,
  256. .size = sizeof(struct __clone_args) + 8,
  257. .expected = 0,
  258. .test_mode = CLONE3_ARGS_NO_TEST,
  259. .filter = not_root,
  260. },
  261. {
  262. .name = "Arguments > page size in a new PID NS",
  263. .flags = CLONE_NEWPID,
  264. .size_function = page_size_plus_8,
  265. .expected = -E2BIG,
  266. .test_mode = CLONE3_ARGS_NO_TEST,
  267. },
  268. {
  269. .name = "New time NS",
  270. .flags = CLONE_NEWTIME,
  271. .size = 0,
  272. .expected = 0,
  273. .test_mode = CLONE3_ARGS_NO_TEST,
  274. .filter = no_timenamespace,
  275. },
  276. {
  277. .name = "exit signal (SIGCHLD) in flags",
  278. .flags = SIGCHLD,
  279. .size = 0,
  280. .expected = -EINVAL,
  281. .test_mode = CLONE3_ARGS_NO_TEST,
  282. },
  283. };
  284. int main(int argc, char *argv[])
  285. {
  286. size_t size;
  287. int i;
  288. ksft_print_header();
  289. ksft_set_plan(ARRAY_SIZE(tests));
  290. test_clone3_supported();
  291. for (i = 0; i < ARRAY_SIZE(tests); i++) {
  292. if (tests[i].filter && tests[i].filter()) {
  293. ksft_test_result_skip("%s\n", tests[i].name);
  294. continue;
  295. }
  296. if (tests[i].size_function)
  297. size = tests[i].size_function();
  298. else
  299. size = tests[i].size;
  300. ksft_print_msg("Running test '%s'\n", tests[i].name);
  301. ksft_test_result(test_clone3(tests[i].flags, size,
  302. tests[i].expected,
  303. tests[i].test_mode),
  304. "%s\n", tests[i].name);
  305. }
  306. ksft_finished();
  307. }