1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <sys/eventfd.h>
8 #include "alloc-util.h"
9 #include "data-fd-util.h"
14 #include "memory-util.h"
15 #include "missing_syscall.h"
17 #include "mount-util.h"
18 #include "namespace-util.h"
19 #include "path-util.h"
20 #include "process-util.h"
21 #include "random-util.h"
22 #include "rlimit-util.h"
24 #include "seccomp-util.h"
25 #include "serialize.h"
26 #include "stat-util.h"
27 #include "string-util.h"
29 #include "tmpfile-util.h"
33 _cleanup_(unlink_tempfilep
) char name0
[] = "/tmp/test-close-many.XXXXXX";
34 _cleanup_(unlink_tempfilep
) char name1
[] = "/tmp/test-close-many.XXXXXX";
35 _cleanup_(unlink_tempfilep
) char name2
[] = "/tmp/test-close-many.XXXXXX";
37 fds
[0] = mkostemp_safe(name0
);
38 fds
[1] = mkostemp_safe(name1
);
39 fds
[2] = mkostemp_safe(name2
);
43 assert_se(fcntl(fds
[0], F_GETFD
) == -1);
44 assert_se(fcntl(fds
[1], F_GETFD
) == -1);
45 assert_se(fcntl(fds
[2], F_GETFD
) >= 0);
51 _cleanup_(unlink_tempfilep
) char name
[] = "/tmp/test-test-close_nointr.XXXXXX";
54 fd
= mkostemp_safe(name
);
56 assert_se(close_nointr(fd
) >= 0);
57 assert_se(close_nointr(fd
) < 0);
61 _cleanup_close_pair_
int p
[2];
62 _cleanup_close_
int a
, b
, c
;
64 assert_se(pipe2(p
, O_CLOEXEC
) >= 0);
65 assert_se((a
= fcntl(p
[0], F_DUPFD
, 3)) >= 0);
66 assert_se((b
= open("/dev/null", O_RDONLY
|O_CLOEXEC
)) >= 0);
67 assert_se((c
= fcntl(a
, F_DUPFD
, 3)) >= 0);
69 assert_se(same_fd(p
[0], p
[0]) > 0);
70 assert_se(same_fd(p
[1], p
[1]) > 0);
71 assert_se(same_fd(a
, a
) > 0);
72 assert_se(same_fd(b
, b
) > 0);
74 assert_se(same_fd(a
, p
[0]) > 0);
75 assert_se(same_fd(p
[0], a
) > 0);
76 assert_se(same_fd(c
, p
[0]) > 0);
77 assert_se(same_fd(p
[0], c
) > 0);
78 assert_se(same_fd(a
, c
) > 0);
79 assert_se(same_fd(c
, a
) > 0);
81 assert_se(same_fd(p
[0], p
[1]) == 0);
82 assert_se(same_fd(p
[1], p
[0]) == 0);
83 assert_se(same_fd(p
[0], b
) == 0);
84 assert_se(same_fd(b
, p
[0]) == 0);
85 assert_se(same_fd(p
[1], a
) == 0);
86 assert_se(same_fd(a
, p
[1]) == 0);
87 assert_se(same_fd(p
[1], b
) == 0);
88 assert_se(same_fd(b
, p
[1]) == 0);
90 assert_se(same_fd(a
, b
) == 0);
91 assert_se(same_fd(b
, a
) == 0);
94 TEST(open_serialization_fd
) {
95 _cleanup_close_
int fd
= -EBADF
;
97 fd
= open_serialization_fd("test");
100 assert_se(write(fd
, "test\n", 5) == 5);
103 TEST(open_serialization_file
) {
104 _cleanup_fclose_
FILE *f
= NULL
;
107 r
= open_serialization_file("test", &f
);
111 assert_se(fwrite("test\n", 1, 5, f
) == 5);
114 TEST(fd_move_above_stdio
) {
115 int original_stdin
, new_fd
;
117 original_stdin
= fcntl(0, F_DUPFD
, 3);
118 assert_se(original_stdin
>= 3);
119 assert_se(close_nointr(0) != EBADF
);
121 new_fd
= open("/dev/null", O_RDONLY
);
122 assert_se(new_fd
== 0);
124 new_fd
= fd_move_above_stdio(new_fd
);
125 assert_se(new_fd
>= 3);
127 assert_se(dup(original_stdin
) == 0);
128 assert_se(close_nointr(original_stdin
) != EBADF
);
129 assert_se(close_nointr(new_fd
) != EBADF
);
132 TEST(rearrange_stdio
) {
136 r
= safe_fork("rearrange", FORK_WAIT
|FORK_LOG
, &pid
);
140 _cleanup_free_
char *path
= NULL
;
141 int pipe_read_fd
, pair
[2];
146 safe_close(STDERR_FILENO
); /* Let's close an fd < 2, to make it more interesting */
148 assert_se(rearrange_stdio(-EBADF
, -EBADF
, -EBADF
) >= 0);
149 /* Reconfigure logging after rearranging stdout/stderr, so we still log to somewhere if the
150 * following tests fail, making it slightly less annoying to debug */
151 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
);
154 assert_se(fd_get_path(STDIN_FILENO
, &path
) >= 0);
155 assert_se(path_equal(path
, "/dev/null"));
158 assert_se(fd_get_path(STDOUT_FILENO
, &path
) >= 0);
159 assert_se(path_equal(path
, "/dev/null"));
162 assert_se(fd_get_path(STDOUT_FILENO
, &path
) >= 0);
163 assert_se(path_equal(path
, "/dev/null"));
166 safe_close(STDIN_FILENO
);
167 safe_close(STDOUT_FILENO
);
168 safe_close(STDERR_FILENO
);
170 assert_se(pipe(pair
) >= 0);
171 assert_se(pair
[0] == 0);
172 assert_se(pair
[1] == 1);
173 pipe_read_fd
= fd_move_above_stdio(0);
174 assert_se(pipe_read_fd
>= 3);
176 assert_se(open("/dev/full", O_WRONLY
|O_CLOEXEC
) == 0);
177 assert_se(acquire_data_fd("foobar") == 2);
179 assert_se(rearrange_stdio(2, 0, 1) >= 0);
181 assert_se(write(1, "x", 1) < 0 && errno
== ENOSPC
);
182 assert_se(write(2, "z", 1) == 1);
183 assert_se(read(pipe_read_fd
, buffer
, sizeof(buffer
)) == 1);
184 assert_se(buffer
[0] == 'z');
185 assert_se(read(0, buffer
, sizeof(buffer
)) == 6);
186 assert_se(memcmp(buffer
, "foobar", 6) == 0);
188 assert_se(rearrange_stdio(-EBADF
, 1, 2) >= 0);
189 assert_se(write(1, "a", 1) < 0 && errno
== ENOSPC
);
190 assert_se(write(2, "y", 1) == 1);
191 assert_se(read(pipe_read_fd
, buffer
, sizeof(buffer
)) == 1);
192 assert_se(buffer
[0] == 'y');
194 assert_se(fd_get_path(0, &path
) >= 0);
195 assert_se(path_equal(path
, "/dev/null"));
203 log_info("nr-open: %i", read_nr_open());
206 static size_t validate_fds(
213 /* Validates that fds in the specified array are one of the following three:
215 * 1. < 0 (test is skipped) or
216 * 2. opened (if 'opened' param is true) or
217 * 3. closed (if 'opened' param is false)
220 for (size_t i
= 0; i
< n_fds
; i
++) {
225 assert_se(fcntl(fds
[i
], F_GETFD
) >= 0);
227 assert_se(fcntl(fds
[i
], F_GETFD
) < 0 && errno
== EBADF
);
232 return c
; /* Return number of fds >= 0 in the array */
235 static void test_close_all_fds_inner(void) {
236 _cleanup_free_
int *fds
= NULL
, *keep
= NULL
;
237 size_t n_fds
, n_keep
;
240 log_info("/* %s */", __func__
);
242 rlimit_nofile_bump(-1);
244 max_fd
= get_max_fd();
245 assert_se(max_fd
> 10);
248 /* If the worst fallback is activated we need to iterate through all possible fds, hence,
249 * let's lower the limit a small bit, so that we don't run for too long. Yes, this undoes the
250 * rlimit_nofile_bump() call above partially. */
252 (void) setrlimit_closest(RLIMIT_NOFILE
, &(struct rlimit
) { 7000, 7000 });
256 /* Try to use 5000 fds, but when we can't bump the rlimit to make that happen use the whole limit minus 10 */
257 n_fds
= MIN(((size_t) max_fd
& ~1U) - 10U, 5000U);
258 assert_se((n_fds
& 1U) == 0U); /* make sure even number of fds */
260 /* Allocate the determined number of fds, always two at a time */
261 assert_se(fds
= new(int, n_fds
));
262 for (size_t i
= 0; i
< n_fds
; i
+= 2)
263 assert_se(pipe2(fds
+ i
, O_CLOEXEC
) >= 0);
265 /* Validate this worked */
266 assert_se(validate_fds(true, fds
, n_fds
) == n_fds
);
268 /* Randomized number of fds to keep, but at most every second */
269 n_keep
= (random_u64() % (n_fds
/ 2));
271 /* Now randomly select a number of fds from the array above to keep */
272 assert_se(keep
= new(int, n_keep
));
273 for (size_t k
= 0; k
< n_keep
; k
++) {
277 p
= random_u64() % n_fds
;
279 keep
[k
] = TAKE_FD(fds
[p
]);
285 /* Check that all fds from both arrays are still open, and test how many in each are >= 0 */
286 assert_se(validate_fds(true, fds
, n_fds
) == n_fds
- n_keep
);
287 assert_se(validate_fds(true, keep
, n_keep
) == n_keep
);
289 /* Close logging fd first, so that we don't confuse it by closing its fd */
291 log_set_open_when_needed(true);
294 /* Close all but the ones to keep */
295 assert_se(close_all_fds(keep
, n_keep
) >= 0);
297 assert_se(validate_fds(false, fds
, n_fds
) == n_fds
- n_keep
);
298 assert_se(validate_fds(true, keep
, n_keep
) == n_keep
);
300 /* Close everything else too! */
301 assert_se(close_all_fds(NULL
, 0) >= 0);
303 assert_se(validate_fds(false, fds
, n_fds
) == n_fds
- n_keep
);
304 assert_se(validate_fds(false, keep
, n_keep
) == n_keep
);
306 log_set_open_when_needed(false);
310 static int seccomp_prohibit_close_range(void) {
311 #if HAVE_SECCOMP && defined(__SNR_close_range)
312 _cleanup_(seccomp_releasep
) scmp_filter_ctx seccomp
= NULL
;
315 r
= seccomp_init_for_arch(&seccomp
, SCMP_ARCH_NATIVE
, SCMP_ACT_ALLOW
);
317 return log_warning_errno(r
, "Failed to acquire seccomp context, ignoring: %m");
319 r
= seccomp_rule_add_exact(
321 SCMP_ACT_ERRNO(EPERM
),
322 SCMP_SYS(close_range
),
325 return log_warning_errno(r
, "Failed to add close_range() rule, ignoring: %m");
327 r
= seccomp_load(seccomp
);
329 return log_warning_errno(r
, "Failed to apply close_range() restrictions, ignoring: %m");
333 return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Seccomp support or close_range() syscall definition not available.");
337 TEST(close_all_fds
) {
340 /* Runs the test four times. Once as is. Once with close_range() syscall blocked via seccomp, once
341 * with /proc/ overmounted, and once with the combination of both. This should trigger all fallbacks
342 * in the close_range_all() function. */
344 r
= safe_fork("(caf-plain)", FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_WAIT
, NULL
);
346 test_close_all_fds_inner();
352 return (void) log_tests_skipped("Lacking privileges for test with close_range() blocked and /proc/ overmounted");
354 r
= safe_fork("(caf-noproc)", FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_WAIT
|FORK_NEW_MOUNTNS
|FORK_MOUNTNS_SLAVE
, NULL
);
356 r
= mount_nofollow_verbose(LOG_WARNING
, "tmpfs", "/proc", "tmpfs", 0, NULL
);
358 log_notice("Overmounting /proc/ didn't work, skipping close_all_fds() with masked /proc/.");
360 test_close_all_fds_inner();
365 if (!is_seccomp_available())
366 return (void) log_tests_skipped("Seccomp not available");
368 r
= safe_fork("(caf-seccomp)", FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_WAIT
, NULL
);
370 r
= seccomp_prohibit_close_range();
372 log_notice("Applying seccomp filter didn't work, skipping close_all_fds() test with masked close_range().");
374 test_close_all_fds_inner();
380 r
= safe_fork("(caf-scnp)", FORK_CLOSE_ALL_FDS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_WAIT
|FORK_NEW_MOUNTNS
|FORK_MOUNTNS_SLAVE
, NULL
);
382 r
= seccomp_prohibit_close_range();
384 log_notice("Applying seccomp filter didn't work, skipping close_all_fds() test with masked close_range().");
386 r
= mount_nofollow_verbose(LOG_WARNING
, "tmpfs", "/proc", "tmpfs", 0, NULL
);
388 log_notice("Overmounting /proc/ didn't work, skipping close_all_fds() with masked /proc/.");
390 test_close_all_fds_inner();
393 test_close_all_fds_inner();
399 TEST(format_proc_fd_path
) {
400 ASSERT_STREQ(FORMAT_PROC_FD_PATH(0), "/proc/self/fd/0");
401 ASSERT_STREQ(FORMAT_PROC_FD_PATH(1), "/proc/self/fd/1");
402 ASSERT_STREQ(FORMAT_PROC_FD_PATH(2), "/proc/self/fd/2");
403 ASSERT_STREQ(FORMAT_PROC_FD_PATH(3), "/proc/self/fd/3");
404 ASSERT_STREQ(FORMAT_PROC_FD_PATH(2147483647), "/proc/self/fd/2147483647");
408 _cleanup_close_
int fd1
= -EBADF
, fd2
= -EBADF
;
409 struct stat st1
, st2
;
412 /* Test this with a directory */
413 fd1
= open("/proc", O_DIRECTORY
|O_PATH
|O_CLOEXEC
);
416 ASSERT_OK_ERRNO(fstat(fd1
, &st1
));
417 assert_se(S_ISDIR(st1
.st_mode
));
419 fl
= fcntl(fd1
, F_GETFL
);
421 assert_se(FLAGS_SET(fl
, O_DIRECTORY
));
422 assert_se(FLAGS_SET(fl
, O_PATH
));
424 /* fd_reopen() with O_NOFOLLOW will systematically fail, since it is implemented via a symlink in /proc/self/fd/ */
425 assert_se(fd_reopen(fd1
, O_RDONLY
|O_CLOEXEC
|O_NOFOLLOW
) == -ELOOP
);
426 assert_se(fd_reopen(fd1
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
) == -ELOOP
);
428 fd2
= fd_reopen(fd1
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
); /* drop the O_PATH */
431 ASSERT_OK_ERRNO(fstat(fd2
, &st2
));
432 assert_se(S_ISDIR(st2
.st_mode
));
433 assert_se(stat_inode_same(&st1
, &st2
));
435 fl
= fcntl(fd2
, F_GETFL
);
437 assert_se(FLAGS_SET(fl
, O_DIRECTORY
));
438 assert_se(!FLAGS_SET(fl
, O_PATH
));
442 fd1
= fd_reopen(fd2
, O_DIRECTORY
|O_PATH
|O_CLOEXEC
); /* reacquire the O_PATH */
445 ASSERT_OK_ERRNO(fstat(fd1
, &st1
));
446 assert_se(S_ISDIR(st1
.st_mode
));
447 assert_se(stat_inode_same(&st1
, &st2
));
449 fl
= fcntl(fd1
, F_GETFL
);
451 assert_se(FLAGS_SET(fl
, O_DIRECTORY
));
452 assert_se(FLAGS_SET(fl
, O_PATH
));
456 /* And now, test this with a file. */
457 fd1
= open("/proc/version", O_PATH
|O_CLOEXEC
);
460 ASSERT_OK_ERRNO(fstat(fd1
, &st1
));
461 assert_se(S_ISREG(st1
.st_mode
));
463 fl
= fcntl(fd1
, F_GETFL
);
465 assert_se(!FLAGS_SET(fl
, O_DIRECTORY
));
466 assert_se(FLAGS_SET(fl
, O_PATH
));
468 assert_se(fd_reopen(fd1
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
) == -ENOTDIR
);
469 fd2
= fd_reopen(fd1
, O_RDONLY
|O_CLOEXEC
); /* drop the O_PATH */
472 ASSERT_OK_ERRNO(fstat(fd2
, &st2
));
473 assert_se(S_ISREG(st2
.st_mode
));
474 assert_se(stat_inode_same(&st1
, &st2
));
476 fl
= fcntl(fd2
, F_GETFL
);
478 assert_se(!FLAGS_SET(fl
, O_DIRECTORY
));
479 assert_se(!FLAGS_SET(fl
, O_PATH
));
483 assert_se(fd_reopen(fd2
, O_DIRECTORY
|O_PATH
|O_CLOEXEC
) == -ENOTDIR
);
484 fd1
= fd_reopen(fd2
, O_PATH
|O_CLOEXEC
); /* reacquire the O_PATH */
487 ASSERT_OK_ERRNO(fstat(fd1
, &st1
));
488 assert_se(S_ISREG(st1
.st_mode
));
489 assert_se(stat_inode_same(&st1
, &st2
));
491 fl
= fcntl(fd1
, F_GETFL
);
493 assert_se(!FLAGS_SET(fl
, O_DIRECTORY
));
494 assert_se(FLAGS_SET(fl
, O_PATH
));
496 /* Also check the right error is generated if the fd is already closed */
498 assert_se(fd_reopen(fd1
, O_RDONLY
|O_CLOEXEC
) == -EBADF
);
501 /* Validate what happens if we reopen a symlink */
502 fd1
= open("/proc/self", O_PATH
|O_CLOEXEC
|O_NOFOLLOW
);
504 ASSERT_OK_ERRNO(fstat(fd1
, &st1
));
505 assert_se(S_ISLNK(st1
.st_mode
));
507 fd2
= fd_reopen(fd1
, O_PATH
|O_CLOEXEC
);
509 ASSERT_OK_ERRNO(fstat(fd2
, &st2
));
510 assert_se(S_ISLNK(st2
.st_mode
));
511 assert_se(stat_inode_same(&st1
, &st2
));
512 fd2
= safe_close(fd2
);
514 /* So here's the thing: if we have an O_PATH fd to a symlink, we *cannot* convert it to a regular fd
515 * with that. i.e. you cannot have the VFS follow a symlink pinned via an O_PATH fd. */
516 assert_se(fd_reopen(fd1
, O_RDONLY
|O_CLOEXEC
) == -ELOOP
);
519 TEST(fd_reopen_condition
) {
520 _cleanup_close_
int fd1
= -EBADF
, fd3
= -EBADF
;
523 /* Open without O_PATH */
524 fd1
= open("/usr/", O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
527 fl
= fcntl(fd1
, F_GETFL
);
528 assert_se(FLAGS_SET(fl
, O_DIRECTORY
));
529 assert_se(!FLAGS_SET(fl
, O_PATH
));
531 fd2
= fd_reopen_condition(fd1
, O_DIRECTORY
, O_DIRECTORY
|O_PATH
, &fd3
);
532 assert_se(fd2
== fd1
);
535 /* Switch on O_PATH */
536 fd2
= fd_reopen_condition(fd1
, O_DIRECTORY
|O_PATH
, O_DIRECTORY
|O_PATH
, &fd3
);
537 assert_se(fd2
!= fd1
);
538 assert_se(fd3
== fd2
);
540 fl
= fcntl(fd2
, F_GETFL
);
541 assert_se(FLAGS_SET(fl
, O_DIRECTORY
));
542 assert_se(FLAGS_SET(fl
, O_PATH
));
544 close_and_replace(fd1
, fd3
);
546 fd2
= fd_reopen_condition(fd1
, O_DIRECTORY
|O_PATH
, O_DIRECTORY
|O_PATH
, &fd3
);
547 assert_se(fd2
== fd1
);
550 /* Switch off O_PATH again */
551 fd2
= fd_reopen_condition(fd1
, O_DIRECTORY
, O_DIRECTORY
|O_PATH
, &fd3
);
552 assert_se(fd2
!= fd1
);
553 assert_se(fd3
== fd2
);
555 fl
= fcntl(fd2
, F_GETFL
);
556 assert_se(FLAGS_SET(fl
, O_DIRECTORY
));
557 assert_se(!FLAGS_SET(fl
, O_PATH
));
559 close_and_replace(fd1
, fd3
);
561 fd2
= fd_reopen_condition(fd1
, O_DIRECTORY
, O_DIRECTORY
|O_PATH
, &fd3
);
562 assert_se(fd2
== fd1
);
567 _cleanup_close_
int fd1
= -EBADF
, fd2
= -EBADF
;
568 int array
[2] = EBADF_PAIR
, i
= 0;
570 assert_se(fd1
== -EBADF
);
571 assert_se(fd2
== -EBADF
);
573 fd1
= eventfd(0, EFD_CLOEXEC
);
577 assert_se(fd1
== -EBADF
);
580 assert_se(array
[0] == -EBADF
);
581 assert_se(array
[1] == -EBADF
);
583 array
[0] = TAKE_FD(fd2
);
584 assert_se(fd1
== -EBADF
);
585 assert_se(fd2
== -EBADF
);
586 assert_se(array
[0] >= 0);
587 assert_se(array
[1] == -EBADF
);
589 array
[1] = TAKE_FD(array
[i
]);
590 assert_se(array
[0] == -EBADF
);
591 assert_se(array
[1] >= 0);
594 array
[0] = TAKE_FD(*(array
+ i
));
595 assert_se(array
[0] >= 0);
596 assert_se(array
[1] == -EBADF
);
599 fd1
= TAKE_FD(array
[i
]);
601 assert_se(array
[0] == -EBADF
);
602 assert_se(array
[1] == -EBADF
);
605 TEST(dir_fd_is_root
) {
606 _cleanup_close_
int fd
= -EBADF
;
609 assert_se(dir_fd_is_root_or_cwd(AT_FDCWD
) > 0);
611 assert_se((fd
= open("/", O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
)) >= 0);
612 assert_se(dir_fd_is_root(fd
) > 0);
613 assert_se(dir_fd_is_root_or_cwd(fd
) > 0);
617 assert_se((fd
= open("/usr", O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
)) >= 0);
618 assert_se(dir_fd_is_root(fd
) == 0);
619 assert_se(dir_fd_is_root_or_cwd(fd
) == 0);
621 r
= detach_mount_namespace();
623 return (void) log_tests_skipped_errno(r
, "Failed to detach mount namespace");
625 _cleanup_(rm_rf_physical_and_freep
) char *tmp
= NULL
;
626 _cleanup_free_
char *x
= NULL
, *y
= NULL
;
628 assert_se(mkdtemp_malloc("/tmp/test-mkdir-XXXXXX", &tmp
) >= 0);
629 assert_se(x
= path_join(tmp
, "x"));
630 assert_se(y
= path_join(tmp
, "x/y"));
631 assert_se(mkdir_p(y
, 0755) >= 0);
632 assert_se(mount_nofollow_verbose(LOG_DEBUG
, x
, y
, NULL
, MS_BIND
, NULL
) >= 0);
636 assert_se((fd
= open(tmp
, O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
)) >= 0);
637 assert_se(dir_fd_is_root(fd
) == 0);
638 assert_se(dir_fd_is_root_or_cwd(fd
) == 0);
642 assert_se((fd
= open(x
, O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
)) >= 0);
643 assert_se(dir_fd_is_root(fd
) == 0);
644 assert_se(dir_fd_is_root_or_cwd(fd
) == 0);
648 assert_se((fd
= open(y
, O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
)) >= 0);
649 assert_se(dir_fd_is_root(fd
) == 0);
650 assert_se(dir_fd_is_root_or_cwd(fd
) == 0);
653 TEST(fds_are_same_mount
) {
654 _cleanup_close_
int fd1
= -EBADF
, fd2
= -EBADF
, fd3
= -EBADF
, fd4
= -EBADF
;
656 fd1
= open("/sys", O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
);
657 fd2
= open("/proc", O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
);
658 fd3
= open("/proc", O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
);
659 fd4
= open("/", O_CLOEXEC
|O_PATH
|O_DIRECTORY
|O_NOFOLLOW
);
661 if (fd1
< 0 || fd2
< 0 || fd3
< 0 || fd4
< 0)
662 return (void) log_tests_skipped_errno(errno
, "Failed to open /sys or /proc or /");
664 if (fds_are_same_mount(fd1
, fd4
) > 0 && fds_are_same_mount(fd2
, fd4
) > 0)
665 return (void) log_tests_skipped("Cannot test fds_are_same_mount() as /sys and /proc are not mounted");
667 assert_se(fds_are_same_mount(fd1
, fd2
) == 0);
668 assert_se(fds_are_same_mount(fd2
, fd3
) > 0);
672 _cleanup_(rm_rf_physical_and_freep
) char *t
= NULL
;
673 _cleanup_close_
int tfd
= -EBADF
, fd
= -EBADF
;
674 _cleanup_free_
char *p
= NULL
, *q
= NULL
, *saved_cwd
= NULL
;
676 tfd
= mkdtemp_open(NULL
, O_PATH
, &t
);
678 assert_se(fd_get_path(tfd
, &p
) >= 0);
683 assert_se(safe_getcwd(&saved_cwd
) >= 0);
684 assert_se(chdir(t
) >= 0);
686 assert_se(fd_get_path(AT_FDCWD
, &p
) >= 0);
691 assert_se(q
= path_join(t
, "regular"));
692 assert_se(touch(q
) >= 0);
693 assert_se(mkdirat_parents(tfd
, "subdir/symlink", 0755) >= 0);
694 assert_se(symlinkat("../regular", tfd
, "subdir/symlink") >= 0);
695 assert_se(symlinkat("subdir", tfd
, "symdir") >= 0);
697 fd
= openat(tfd
, "regular", O_CLOEXEC
|O_PATH
);
699 assert_se(fd_get_path(fd
, &p
) >= 0);
705 fd
= openat(AT_FDCWD
, "regular", O_CLOEXEC
|O_PATH
);
707 assert_se(fd_get_path(fd
, &p
) >= 0);
713 fd
= openat(tfd
, "subdir/symlink", O_CLOEXEC
|O_PATH
);
715 assert_se(fd_verify_regular(fd
) >= 0);
716 assert_se(fd_get_path(fd
, &p
) >= 0);
722 fd
= openat(AT_FDCWD
, "subdir/symlink", O_CLOEXEC
|O_PATH
);
724 assert_se(fd_verify_regular(fd
) >= 0);
725 assert_se(fd_get_path(fd
, &p
) >= 0);
731 fd
= openat(tfd
, "symdir//./symlink", O_CLOEXEC
|O_PATH
);
733 assert_se(fd_verify_regular(fd
) >= 0);
734 assert_se(fd_get_path(fd
, &p
) >= 0);
740 fd
= openat(AT_FDCWD
, "symdir//./symlink", O_CLOEXEC
|O_PATH
);
742 assert_se(fd_verify_regular(fd
) >= 0);
743 assert_se(fd_get_path(fd
, &p
) >= 0);
750 assert_se(q
= path_join(t
, "subdir/symlink"));
751 fd
= openat(tfd
, "subdir/symlink", O_CLOEXEC
|O_PATH
|O_NOFOLLOW
);
753 assert_se(fd_verify_regular(fd
) == -ELOOP
);
754 assert_se(fd_get_path(fd
, &p
) >= 0);
760 fd
= openat(AT_FDCWD
, "subdir/symlink", O_CLOEXEC
|O_PATH
|O_NOFOLLOW
);
762 assert_se(fd_verify_regular(fd
) == -ELOOP
);
763 assert_se(fd_get_path(fd
, &p
) >= 0);
769 fd
= openat(tfd
, "symdir//./symlink", O_CLOEXEC
|O_PATH
|O_NOFOLLOW
);
771 assert_se(fd_verify_regular(fd
) == -ELOOP
);
772 assert_se(fd_get_path(fd
, &p
) >= 0);
778 fd
= openat(AT_FDCWD
, "symdir//./symlink", O_CLOEXEC
|O_PATH
|O_NOFOLLOW
);
780 assert_se(fd_verify_regular(fd
) == -ELOOP
);
781 assert_se(fd_get_path(fd
, &p
) >= 0);
784 assert_se(chdir(saved_cwd
) >= 0);
787 DEFINE_TEST_MAIN(LOG_DEBUG
);