pidfd_file_handle_test.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <limits.h>
  6. #include <linux/types.h>
  7. #include <poll.h>
  8. #include <sched.h>
  9. #include <signal.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <syscall.h>
  14. #include <sys/prctl.h>
  15. #include <sys/wait.h>
  16. #include <unistd.h>
  17. #include <sys/socket.h>
  18. #include <linux/kcmp.h>
  19. #include <sys/stat.h>
  20. #include "pidfd.h"
  21. #include "kselftest_harness.h"
  22. FIXTURE(file_handle)
  23. {
  24. pid_t pid;
  25. int pidfd;
  26. pid_t child_pid1;
  27. int child_pidfd1;
  28. pid_t child_pid2;
  29. int child_pidfd2;
  30. pid_t child_pid3;
  31. int child_pidfd3;
  32. };
  33. FIXTURE_SETUP(file_handle)
  34. {
  35. int ret;
  36. int ipc_sockets[2];
  37. char c;
  38. self->pid = getpid();
  39. self->pidfd = sys_pidfd_open(self->pid, 0);
  40. ASSERT_GE(self->pidfd, 0);
  41. ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
  42. EXPECT_EQ(ret, 0);
  43. self->child_pid1 = create_child(&self->child_pidfd1, CLONE_NEWUSER);
  44. EXPECT_GE(self->child_pid1, 0);
  45. if (self->child_pid1 == 0) {
  46. close(ipc_sockets[0]);
  47. if (write_nointr(ipc_sockets[1], "1", 1) < 0)
  48. _exit(EXIT_FAILURE);
  49. close(ipc_sockets[1]);
  50. pause();
  51. _exit(EXIT_SUCCESS);
  52. }
  53. close(ipc_sockets[1]);
  54. ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
  55. close(ipc_sockets[0]);
  56. ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
  57. EXPECT_EQ(ret, 0);
  58. self->child_pid2 = create_child(&self->child_pidfd2, CLONE_NEWUSER | CLONE_NEWPID);
  59. EXPECT_GE(self->child_pid2, 0);
  60. if (self->child_pid2 == 0) {
  61. close(ipc_sockets[0]);
  62. if (write_nointr(ipc_sockets[1], "1", 1) < 0)
  63. _exit(EXIT_FAILURE);
  64. close(ipc_sockets[1]);
  65. pause();
  66. _exit(EXIT_SUCCESS);
  67. }
  68. close(ipc_sockets[1]);
  69. ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
  70. close(ipc_sockets[0]);
  71. ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
  72. EXPECT_EQ(ret, 0);
  73. self->child_pid3 = create_child(&self->child_pidfd3, CLONE_NEWUSER | CLONE_NEWPID);
  74. EXPECT_GE(self->child_pid3, 0);
  75. if (self->child_pid3 == 0) {
  76. close(ipc_sockets[0]);
  77. if (write_nointr(ipc_sockets[1], "1", 1) < 0)
  78. _exit(EXIT_FAILURE);
  79. close(ipc_sockets[1]);
  80. pause();
  81. _exit(EXIT_SUCCESS);
  82. }
  83. close(ipc_sockets[1]);
  84. ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
  85. close(ipc_sockets[0]);
  86. }
  87. FIXTURE_TEARDOWN(file_handle)
  88. {
  89. EXPECT_EQ(close(self->pidfd), 0);
  90. EXPECT_EQ(sys_pidfd_send_signal(self->child_pidfd1, SIGKILL, NULL, 0), 0);
  91. if (self->child_pidfd1 >= 0)
  92. EXPECT_EQ(0, close(self->child_pidfd1));
  93. EXPECT_EQ(sys_waitid(P_PID, self->child_pid1, NULL, WEXITED), 0);
  94. EXPECT_EQ(sys_pidfd_send_signal(self->child_pidfd2, SIGKILL, NULL, 0), 0);
  95. if (self->child_pidfd2 >= 0)
  96. EXPECT_EQ(0, close(self->child_pidfd2));
  97. EXPECT_EQ(sys_waitid(P_PID, self->child_pid2, NULL, WEXITED), 0);
  98. if (self->child_pidfd3 >= 0) {
  99. EXPECT_EQ(sys_pidfd_send_signal(self->child_pidfd3, SIGKILL, NULL, 0), 0);
  100. EXPECT_EQ(0, close(self->child_pidfd3));
  101. EXPECT_EQ(sys_waitid(P_PID, self->child_pid3, NULL, WEXITED), 0);
  102. }
  103. }
  104. /*
  105. * Test that we can decode a pidfs file handle in the same pid
  106. * namespace.
  107. */
  108. TEST_F(file_handle, file_handle_same_pidns)
  109. {
  110. int mnt_id;
  111. struct file_handle *fh;
  112. int pidfd = -EBADF;
  113. struct stat st1, st2;
  114. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  115. ASSERT_NE(fh, NULL);
  116. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  117. fh->handle_bytes = MAX_HANDLE_SZ;
  118. ASSERT_EQ(name_to_handle_at(self->child_pidfd1, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  119. ASSERT_EQ(fstat(self->child_pidfd1, &st1), 0);
  120. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  121. ASSERT_GE(pidfd, 0);
  122. ASSERT_EQ(fstat(pidfd, &st2), 0);
  123. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  124. ASSERT_EQ(close(pidfd), 0);
  125. pidfd = open_by_handle_at(self->pidfd, fh, O_CLOEXEC);
  126. ASSERT_GE(pidfd, 0);
  127. ASSERT_EQ(fstat(pidfd, &st2), 0);
  128. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  129. ASSERT_EQ(close(pidfd), 0);
  130. pidfd = open_by_handle_at(self->pidfd, fh, O_NONBLOCK);
  131. ASSERT_GE(pidfd, 0);
  132. ASSERT_EQ(fstat(pidfd, &st2), 0);
  133. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  134. ASSERT_EQ(close(pidfd), 0);
  135. free(fh);
  136. }
  137. /*
  138. * Test that we can decode a pidfs file handle from a child pid
  139. * namespace.
  140. */
  141. TEST_F(file_handle, file_handle_child_pidns)
  142. {
  143. int mnt_id;
  144. struct file_handle *fh;
  145. int pidfd = -EBADF;
  146. struct stat st1, st2;
  147. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  148. ASSERT_NE(fh, NULL);
  149. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  150. fh->handle_bytes = MAX_HANDLE_SZ;
  151. ASSERT_EQ(name_to_handle_at(self->child_pidfd2, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  152. ASSERT_EQ(fstat(self->child_pidfd2, &st1), 0);
  153. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  154. ASSERT_GE(pidfd, 0);
  155. ASSERT_EQ(fstat(pidfd, &st2), 0);
  156. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  157. ASSERT_EQ(close(pidfd), 0);
  158. pidfd = open_by_handle_at(self->pidfd, fh, O_CLOEXEC);
  159. ASSERT_GE(pidfd, 0);
  160. ASSERT_EQ(fstat(pidfd, &st2), 0);
  161. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  162. ASSERT_EQ(close(pidfd), 0);
  163. pidfd = open_by_handle_at(self->pidfd, fh, O_NONBLOCK);
  164. ASSERT_GE(pidfd, 0);
  165. ASSERT_EQ(fstat(pidfd, &st2), 0);
  166. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  167. ASSERT_EQ(close(pidfd), 0);
  168. free(fh);
  169. }
  170. /*
  171. * Test that we fail to decode a pidfs file handle from an ancestor
  172. * child pid namespace.
  173. */
  174. TEST_F(file_handle, file_handle_foreign_pidns)
  175. {
  176. int mnt_id;
  177. struct file_handle *fh;
  178. pid_t pid;
  179. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  180. ASSERT_NE(fh, NULL);
  181. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  182. fh->handle_bytes = MAX_HANDLE_SZ;
  183. ASSERT_EQ(name_to_handle_at(self->pidfd, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  184. ASSERT_EQ(setns(self->child_pidfd2, CLONE_NEWUSER | CLONE_NEWPID), 0);
  185. pid = fork();
  186. ASSERT_GE(pid, 0);
  187. if (pid == 0) {
  188. int pidfd = open_by_handle_at(self->pidfd, fh, 0);
  189. if (pidfd >= 0) {
  190. TH_LOG("Managed to open pidfd outside of the caller's pid namespace hierarchy");
  191. _exit(1);
  192. }
  193. _exit(0);
  194. }
  195. ASSERT_EQ(wait_for_pid(pid), 0);
  196. free(fh);
  197. }
  198. /*
  199. * Test that we can decode a pidfs file handle of a process that has
  200. * exited but not been reaped.
  201. */
  202. TEST_F(file_handle, pid_has_exited)
  203. {
  204. int mnt_id, pidfd, child_pidfd3;
  205. struct file_handle *fh;
  206. struct stat st1, st2;
  207. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  208. ASSERT_NE(fh, NULL);
  209. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  210. fh->handle_bytes = MAX_HANDLE_SZ;
  211. ASSERT_EQ(name_to_handle_at(self->child_pidfd3, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  212. ASSERT_EQ(fstat(self->child_pidfd3, &st1), 0);
  213. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  214. ASSERT_GE(pidfd, 0);
  215. ASSERT_EQ(fstat(pidfd, &st2), 0);
  216. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  217. ASSERT_EQ(close(pidfd), 0);
  218. child_pidfd3 = self->child_pidfd3;
  219. self->child_pidfd3 = -EBADF;
  220. EXPECT_EQ(sys_pidfd_send_signal(child_pidfd3, SIGKILL, NULL, 0), 0);
  221. EXPECT_EQ(close(child_pidfd3), 0);
  222. EXPECT_EQ(sys_waitid(P_PID, self->child_pid3, NULL, WEXITED | WNOWAIT), 0);
  223. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  224. ASSERT_GE(pidfd, 0);
  225. EXPECT_EQ(sys_waitid(P_PID, self->child_pid3, NULL, WEXITED), 0);
  226. }
  227. /*
  228. * Test that we fail to decode a pidfs file handle of a process that has
  229. * already been reaped.
  230. */
  231. TEST_F(file_handle, pid_has_been_reaped)
  232. {
  233. int mnt_id, pidfd, child_pidfd3;
  234. struct file_handle *fh;
  235. struct stat st1, st2;
  236. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  237. ASSERT_NE(fh, NULL);
  238. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  239. fh->handle_bytes = MAX_HANDLE_SZ;
  240. ASSERT_EQ(name_to_handle_at(self->child_pidfd3, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  241. ASSERT_EQ(fstat(self->child_pidfd3, &st1), 0);
  242. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  243. ASSERT_GE(pidfd, 0);
  244. ASSERT_EQ(fstat(pidfd, &st2), 0);
  245. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  246. ASSERT_EQ(close(pidfd), 0);
  247. child_pidfd3 = self->child_pidfd3;
  248. self->child_pidfd3 = -EBADF;
  249. EXPECT_EQ(sys_pidfd_send_signal(child_pidfd3, SIGKILL, NULL, 0), 0);
  250. EXPECT_EQ(close(child_pidfd3), 0);
  251. EXPECT_EQ(sys_waitid(P_PID, self->child_pid3, NULL, WEXITED), 0);
  252. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  253. ASSERT_LT(pidfd, 0);
  254. }
  255. /*
  256. * Test valid flags to open a pidfd file handle. Note, that
  257. * PIDFD_NONBLOCK is defined as O_NONBLOCK and O_NONBLOCK is an alias to
  258. * O_NDELAY. Also note that PIDFD_THREAD is an alias for O_EXCL.
  259. */
  260. TEST_F(file_handle, open_by_handle_at_valid_flags)
  261. {
  262. int mnt_id;
  263. struct file_handle *fh;
  264. int pidfd = -EBADF;
  265. struct stat st1, st2;
  266. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  267. ASSERT_NE(fh, NULL);
  268. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  269. fh->handle_bytes = MAX_HANDLE_SZ;
  270. ASSERT_EQ(name_to_handle_at(self->child_pidfd2, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  271. ASSERT_EQ(fstat(self->child_pidfd2, &st1), 0);
  272. pidfd = open_by_handle_at(self->pidfd, fh,
  273. O_RDONLY |
  274. O_WRONLY |
  275. O_RDWR |
  276. O_NONBLOCK |
  277. O_NDELAY |
  278. O_CLOEXEC |
  279. O_EXCL);
  280. ASSERT_GE(pidfd, 0);
  281. ASSERT_EQ(fstat(pidfd, &st2), 0);
  282. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  283. ASSERT_EQ(close(pidfd), 0);
  284. }
  285. /*
  286. * Test that invalid flags passed to open a pidfd file handle are
  287. * rejected.
  288. */
  289. TEST_F(file_handle, open_by_handle_at_invalid_flags)
  290. {
  291. int mnt_id;
  292. struct file_handle *fh;
  293. int pidfd = -EBADF;
  294. static const struct invalid_pidfs_file_handle_flags {
  295. int oflag;
  296. const char *oflag_name;
  297. } invalid_pidfs_file_handle_flags[] = {
  298. { FASYNC, "FASYNC" },
  299. { O_CREAT, "O_CREAT" },
  300. { O_NOCTTY, "O_NOCTTY" },
  301. { O_CREAT, "O_CREAT" },
  302. { O_TRUNC, "O_TRUNC" },
  303. { O_APPEND, "O_APPEND" },
  304. { O_SYNC, "O_SYNC" },
  305. { O_DSYNC, "O_DSYNC" },
  306. { O_DIRECT, "O_DIRECT" },
  307. { O_DIRECTORY, "O_DIRECTORY" },
  308. { O_NOFOLLOW, "O_NOFOLLOW" },
  309. { O_NOATIME, "O_NOATIME" },
  310. { O_PATH, "O_PATH" },
  311. { O_TMPFILE, "O_TMPFILE" },
  312. /*
  313. * O_LARGEFILE is added implicitly by
  314. * open_by_handle_at() so pidfs simply masks it off.
  315. */
  316. };
  317. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  318. ASSERT_NE(fh, NULL);
  319. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  320. fh->handle_bytes = MAX_HANDLE_SZ;
  321. ASSERT_EQ(name_to_handle_at(self->child_pidfd2, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  322. for (int i = 0; i < ARRAY_SIZE(invalid_pidfs_file_handle_flags); i++) {
  323. pidfd = open_by_handle_at(self->pidfd, fh, invalid_pidfs_file_handle_flags[i].oflag);
  324. ASSERT_LT(pidfd, 0) {
  325. TH_LOG("open_by_handle_at() succeeded with invalid flags: %s", invalid_pidfs_file_handle_flags[i].oflag_name);
  326. }
  327. }
  328. }
  329. /* Test that lookup fails. */
  330. TEST_F(file_handle, lookup_must_fail)
  331. {
  332. int mnt_id;
  333. struct file_handle *fh;
  334. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  335. ASSERT_NE(fh, NULL);
  336. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  337. fh->handle_bytes = MAX_HANDLE_SZ;
  338. ASSERT_NE(name_to_handle_at(self->child_pidfd2, "lookup-is-not-possible-with-pidfs", fh, &mnt_id, AT_EMPTY_PATH), 0);
  339. ASSERT_EQ(errno, ENOTDIR);
  340. ASSERT_NE(name_to_handle_at(self->child_pidfd2, "lookup-is-not-possible-with-pidfs", fh, &mnt_id, 0), 0);
  341. ASSERT_EQ(errno, ENOTDIR);
  342. }
  343. #ifndef AT_HANDLE_CONNECTABLE
  344. #define AT_HANDLE_CONNECTABLE 0x002
  345. #endif
  346. /*
  347. * Test that AT_HANDLE_CONNECTABLE is rejected. Connectable file handles
  348. * don't make sense for pidfs. Note that currently AT_HANDLE_CONNECTABLE
  349. * is rejected because it is incompatible with AT_EMPTY_PATH which is
  350. * required with pidfds as we don't support lookup.
  351. */
  352. TEST_F(file_handle, invalid_name_to_handle_at_flags)
  353. {
  354. int mnt_id;
  355. struct file_handle *fh;
  356. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  357. ASSERT_NE(fh, NULL);
  358. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  359. fh->handle_bytes = MAX_HANDLE_SZ;
  360. ASSERT_NE(name_to_handle_at(self->child_pidfd2, "", fh, &mnt_id, AT_EMPTY_PATH | AT_HANDLE_CONNECTABLE), 0);
  361. }
  362. #ifndef AT_HANDLE_FID
  363. #define AT_HANDLE_FID 0x200
  364. #endif
  365. /*
  366. * Test that a request with AT_HANDLE_FID always leads to decodable file
  367. * handle as pidfs always provides export operations.
  368. */
  369. TEST_F(file_handle, valid_name_to_handle_at_flags)
  370. {
  371. int mnt_id, pidfd;
  372. struct file_handle *fh;
  373. struct stat st1, st2;
  374. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  375. ASSERT_NE(fh, NULL);
  376. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  377. fh->handle_bytes = MAX_HANDLE_SZ;
  378. ASSERT_EQ(name_to_handle_at(self->child_pidfd2, "", fh, &mnt_id, AT_EMPTY_PATH | AT_HANDLE_FID), 0);
  379. ASSERT_EQ(fstat(self->child_pidfd2, &st1), 0);
  380. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  381. ASSERT_GE(pidfd, 0);
  382. ASSERT_EQ(fstat(pidfd, &st2), 0);
  383. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  384. ASSERT_EQ(close(pidfd), 0);
  385. }
  386. /*
  387. * That we decode a file handle without having to pass a pidfd.
  388. */
  389. TEST_F(file_handle, decode_purely_based_on_file_handle)
  390. {
  391. int mnt_id;
  392. struct file_handle *fh;
  393. int pidfd = -EBADF;
  394. struct stat st1, st2;
  395. fh = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
  396. ASSERT_NE(fh, NULL);
  397. memset(fh, 0, sizeof(struct file_handle) + MAX_HANDLE_SZ);
  398. fh->handle_bytes = MAX_HANDLE_SZ;
  399. ASSERT_EQ(name_to_handle_at(self->child_pidfd1, "", fh, &mnt_id, AT_EMPTY_PATH), 0);
  400. ASSERT_EQ(fstat(self->child_pidfd1, &st1), 0);
  401. pidfd = open_by_handle_at(FD_PIDFS_ROOT, fh, 0);
  402. ASSERT_GE(pidfd, 0);
  403. ASSERT_EQ(fstat(pidfd, &st2), 0);
  404. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  405. ASSERT_EQ(close(pidfd), 0);
  406. pidfd = open_by_handle_at(FD_PIDFS_ROOT, fh, O_CLOEXEC);
  407. ASSERT_GE(pidfd, 0);
  408. ASSERT_EQ(fstat(pidfd, &st2), 0);
  409. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  410. ASSERT_EQ(close(pidfd), 0);
  411. pidfd = open_by_handle_at(FD_PIDFS_ROOT, fh, O_NONBLOCK);
  412. ASSERT_GE(pidfd, 0);
  413. ASSERT_EQ(fstat(pidfd, &st2), 0);
  414. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  415. ASSERT_EQ(close(pidfd), 0);
  416. pidfd = open_by_handle_at(self->pidfd, fh, 0);
  417. ASSERT_GE(pidfd, 0);
  418. ASSERT_EQ(fstat(pidfd, &st2), 0);
  419. ASSERT_TRUE(st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
  420. ASSERT_EQ(close(pidfd), 0);
  421. pidfd = open_by_handle_at(-EBADF, fh, 0);
  422. ASSERT_LT(pidfd, 0);
  423. pidfd = open_by_handle_at(AT_FDCWD, fh, 0);
  424. ASSERT_LT(pidfd, 0);
  425. free(fh);
  426. }
  427. TEST_HARNESS_MAIN