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