pidfd_fdinfo_test.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <assert.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <linux/types.h>
  7. #include <sched.h>
  8. #include <signal.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <syscall.h>
  13. #include <sys/wait.h>
  14. #include <sys/mman.h>
  15. #include <sys/mount.h>
  16. #include "pidfd.h"
  17. #include "kselftest.h"
  18. struct error {
  19. int code;
  20. char msg[512];
  21. };
  22. static int error_set(struct error *err, int code, const char *fmt, ...)
  23. {
  24. va_list args;
  25. int r;
  26. if (code == PIDFD_PASS || !err || err->code != PIDFD_PASS)
  27. return code;
  28. err->code = code;
  29. va_start(args, fmt);
  30. r = vsnprintf(err->msg, sizeof(err->msg), fmt, args);
  31. assert((size_t)r < sizeof(err->msg));
  32. va_end(args);
  33. return code;
  34. }
  35. static void error_report(struct error *err, const char *test_name)
  36. {
  37. switch (err->code) {
  38. case PIDFD_ERROR:
  39. ksft_exit_fail_msg("%s test: Fatal: %s\n", test_name, err->msg);
  40. break;
  41. case PIDFD_FAIL:
  42. /* will be: not ok %d # error %s test: %s */
  43. ksft_test_result_error("%s test: %s\n", test_name, err->msg);
  44. break;
  45. case PIDFD_SKIP:
  46. /* will be: not ok %d # SKIP %s test: %s */
  47. ksft_test_result_skip("%s test: %s\n", test_name, err->msg);
  48. break;
  49. case PIDFD_XFAIL:
  50. ksft_test_result_pass("%s test: Expected failure: %s\n",
  51. test_name, err->msg);
  52. break;
  53. case PIDFD_PASS:
  54. ksft_test_result_pass("%s test: Passed\n", test_name);
  55. break;
  56. default:
  57. ksft_exit_fail_msg("%s test: Unknown code: %d %s\n",
  58. test_name, err->code, err->msg);
  59. break;
  60. }
  61. }
  62. static inline int error_check(struct error *err, const char *test_name)
  63. {
  64. /* In case of error we bail out and terminate the test program */
  65. if (err->code == PIDFD_ERROR)
  66. error_report(err, test_name);
  67. return err->code;
  68. }
  69. #define CHILD_STACK_SIZE 8192
  70. struct child {
  71. char *stack;
  72. pid_t pid;
  73. int fd;
  74. };
  75. static struct child clone_newns(int (*fn)(void *), void *args,
  76. struct error *err)
  77. {
  78. static int flags = CLONE_PIDFD | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
  79. struct child ret;
  80. if (!(flags & CLONE_NEWUSER) && geteuid() != 0)
  81. flags |= CLONE_NEWUSER;
  82. ret.stack = mmap(NULL, CHILD_STACK_SIZE, PROT_READ | PROT_WRITE,
  83. MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
  84. if (ret.stack == MAP_FAILED) {
  85. error_set(err, -1, "mmap of stack failed (errno %d)", errno);
  86. return ret;
  87. }
  88. #ifdef __ia64__
  89. ret.pid = __clone2(fn, ret.stack, CHILD_STACK_SIZE, flags, args, &ret.fd);
  90. #else
  91. ret.pid = clone(fn, ret.stack + CHILD_STACK_SIZE, flags, args, &ret.fd);
  92. #endif
  93. if (ret.pid < 0) {
  94. error_set(err, PIDFD_ERROR, "clone failed (ret %d, errno %d)",
  95. ret.fd, errno);
  96. return ret;
  97. }
  98. ksft_print_msg("New child: %d, fd: %d\n", ret.pid, ret.fd);
  99. return ret;
  100. }
  101. static inline void child_close(struct child *child)
  102. {
  103. close(child->fd);
  104. }
  105. static inline int child_join(struct child *child, struct error *err)
  106. {
  107. int r;
  108. r = wait_for_pid(child->pid);
  109. if (r < 0)
  110. error_set(err, PIDFD_ERROR, "waitpid failed (ret %d, errno %d)",
  111. r, errno);
  112. else if (r > 0)
  113. error_set(err, r, "child %d reported: %d", child->pid, r);
  114. if (munmap(child->stack, CHILD_STACK_SIZE)) {
  115. error_set(err, -1, "munmap of child stack failed (errno %d)", errno);
  116. r = -1;
  117. }
  118. ksft_print_msg("waitpid WEXITSTATUS=%d\n", r);
  119. return r;
  120. }
  121. static inline int child_join_close(struct child *child, struct error *err)
  122. {
  123. child_close(child);
  124. return child_join(child, err);
  125. }
  126. static inline void trim_newline(char *str)
  127. {
  128. char *pos = strrchr(str, '\n');
  129. if (pos)
  130. *pos = '\0';
  131. }
  132. static int verify_fdinfo(int pidfd, struct error *err, const char *prefix,
  133. size_t prefix_len, const char *expect, ...)
  134. {
  135. char buffer[512] = {0, };
  136. char path[512] = {0, };
  137. va_list args;
  138. FILE *f;
  139. char *line = NULL;
  140. size_t n = 0;
  141. int found = 0;
  142. int r;
  143. va_start(args, expect);
  144. r = vsnprintf(buffer, sizeof(buffer), expect, args);
  145. assert((size_t)r < sizeof(buffer));
  146. va_end(args);
  147. snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd);
  148. f = fopen(path, "re");
  149. if (!f)
  150. return error_set(err, PIDFD_ERROR, "fdinfo open failed for %d",
  151. pidfd);
  152. while (getline(&line, &n, f) != -1) {
  153. char *val;
  154. if (strncmp(line, prefix, prefix_len))
  155. continue;
  156. found = 1;
  157. val = line + prefix_len;
  158. r = strcmp(val, buffer);
  159. if (r != 0) {
  160. trim_newline(line);
  161. trim_newline(buffer);
  162. error_set(err, PIDFD_FAIL, "%s '%s' != '%s'",
  163. prefix, val, buffer);
  164. }
  165. break;
  166. }
  167. free(line);
  168. fclose(f);
  169. if (found == 0)
  170. return error_set(err, PIDFD_FAIL, "%s not found for fd %d",
  171. prefix, pidfd);
  172. return PIDFD_PASS;
  173. }
  174. static int child_fdinfo_nspid_test(void *args)
  175. {
  176. struct error err;
  177. int pidfd;
  178. int r;
  179. /* if we got no fd for the sibling, we are done */
  180. if (!args)
  181. return PIDFD_PASS;
  182. /* verify that we can not resolve the pidfd for a process
  183. * in a sibling pid namespace, i.e. a pid namespace it is
  184. * not in our or a descended namespace
  185. */
  186. r = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
  187. if (r < 0) {
  188. ksft_print_msg("Failed to remount / private\n");
  189. return PIDFD_ERROR;
  190. }
  191. (void)umount2("/proc", MNT_DETACH);
  192. r = mount("proc", "/proc", "proc", 0, NULL);
  193. if (r < 0) {
  194. ksft_print_msg("Failed to remount /proc\n");
  195. return PIDFD_ERROR;
  196. }
  197. pidfd = *(int *)args;
  198. r = verify_fdinfo(pidfd, &err, "NSpid:", 6, "\t0\n");
  199. if (r != PIDFD_PASS)
  200. ksft_print_msg("NSpid fdinfo check failed: %s\n", err.msg);
  201. return r;
  202. }
  203. static void test_pidfd_fdinfo_nspid(void)
  204. {
  205. struct child a, b;
  206. struct error err = {0, };
  207. const char *test_name = "pidfd check for NSpid in fdinfo";
  208. /* Create a new child in a new pid and mount namespace */
  209. a = clone_newns(child_fdinfo_nspid_test, NULL, &err);
  210. error_check(&err, test_name);
  211. /* Pass the pidfd representing the first child to the
  212. * second child, which will be in a sibling pid namespace,
  213. * which means that the fdinfo NSpid entry for the pidfd
  214. * should only contain '0'.
  215. */
  216. b = clone_newns(child_fdinfo_nspid_test, &a.fd, &err);
  217. error_check(&err, test_name);
  218. /* The children will have pid 1 in the new pid namespace,
  219. * so the line must be 'NSPid:\t<pid>\t1'.
  220. */
  221. verify_fdinfo(a.fd, &err, "NSpid:", 6, "\t%d\t%d\n", a.pid, 1);
  222. verify_fdinfo(b.fd, &err, "NSpid:", 6, "\t%d\t%d\n", b.pid, 1);
  223. /* wait for the process, check the exit status and set
  224. * 'err' accordingly, if it is not already set.
  225. */
  226. child_join_close(&a, &err);
  227. child_join_close(&b, &err);
  228. error_report(&err, test_name);
  229. }
  230. static void test_pidfd_dead_fdinfo(void)
  231. {
  232. struct child a;
  233. struct error err = {0, };
  234. const char *test_name = "pidfd check fdinfo for dead process";
  235. /* Create a new child in a new pid and mount namespace */
  236. a = clone_newns(child_fdinfo_nspid_test, NULL, &err);
  237. error_check(&err, test_name);
  238. child_join(&a, &err);
  239. verify_fdinfo(a.fd, &err, "Pid:", 4, "\t-1\n");
  240. verify_fdinfo(a.fd, &err, "NSpid:", 6, "\t-1\n");
  241. child_close(&a);
  242. error_report(&err, test_name);
  243. }
  244. int main(int argc, char **argv)
  245. {
  246. ksft_print_header();
  247. ksft_set_plan(2);
  248. test_pidfd_fdinfo_nspid();
  249. test_pidfd_dead_fdinfo();
  250. ksft_exit_pass();
  251. }