test-mount-util: several cleanups

- use safe_fork() with common flags,
- introduce macro for checking privilege.
This commit is contained in:
Yu Watanabe
2025-09-17 22:20:42 +09:00
parent aa5aac9e40
commit 2ff79a81a8
+94 -162
View File
@@ -24,6 +24,20 @@
#include "tests.h"
#include "tmpfile-util.h"
#define FORK_COMMON_FLAGS \
(FORK_CLOSE_ALL_FDS | \
FORK_RESET_SIGNALS | \
FORK_DEATHSIG_SIGTERM | \
FORK_LOG | \
FORK_REOPEN_LOG | \
FORK_WAIT | \
FORK_NEW_MOUNTNS | \
FORK_MOUNTNS_SLAVE)
#define CHECK_PRIV \
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) \
return (void) log_tests_skipped("Not privileged");
TEST(mount_option_mangle) {
char *opts = NULL;
unsigned long f;
@@ -132,11 +146,9 @@ TEST(mount_flags_to_string) {
TEST(bind_remount_recursive) {
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
_cleanup_free_ char *subdir = NULL;
int r;
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
(void) log_tests_skipped("not running privileged");
return;
}
CHECK_PRIV;
assert_se(mkdtemp_malloc("/tmp/XXXXXX", &tmp) >= 0);
subdir = path_join(tmp, "subdir");
@@ -144,15 +156,9 @@ TEST(bind_remount_recursive) {
assert_se(mkdir(subdir, 0755) >= 0);
FOREACH_STRING(p, "/usr", "/sys", "/", tmp) {
pid_t pid;
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
ASSERT_OK(r = safe_fork("(bind-remount-recursive)", FORK_COMMON_FLAGS, NULL));
if (r == 0) { /* child */
struct statvfs svfs;
/* child */
assert_se(detach_mount_namespace() >= 0);
/* Check that the subdir is writable (it must be because it's in /tmp) */
assert_se(statvfs(subdir, &svfs) >= 0);
@@ -178,29 +184,18 @@ TEST(bind_remount_recursive) {
_exit(EXIT_SUCCESS);
}
assert_se(wait_for_terminate_and_check("test-remount-rec", pid, WAIT_LOG) == EXIT_SUCCESS);
}
}
TEST(bind_remount_one) {
pid_t pid;
int r;
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
(void) log_tests_skipped("not running privileged");
return;
}
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
/* child */
CHECK_PRIV;
ASSERT_OK(r = safe_fork("(remount-one-with-mountinfo)", FORK_COMMON_FLAGS, NULL));
if (r == 0) { /* child */
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
assert_se(detach_mount_namespace() >= 0);
assert_se(fopen_unlocked("/proc/self/mountinfo", "re", &proc_self_mountinfo) >= 0);
assert_se(bind_remount_one_with_mountinfo("/run", MS_RDONLY, MS_RDONLY, proc_self_mountinfo) >= 0);
@@ -212,16 +207,8 @@ TEST(bind_remount_one) {
_exit(EXIT_SUCCESS);
}
assert_se(wait_for_terminate_and_check("test-remount-one-with-mountinfo", pid, WAIT_LOG) == EXIT_SUCCESS);
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
/* child */
assert_se(detach_mount_namespace() >= 0);
ASSERT_OK(r = safe_fork("(remount-one)", FORK_COMMON_FLAGS, NULL));
if (r == 0) { /* child */
assert_se(bind_remount_one("/run", MS_RDONLY, MS_RDONLY) >= 0);
assert_se(bind_remount_one("/run", MS_NOEXEC, MS_RDONLY|MS_NOEXEC) >= 0);
assert_se(bind_remount_one("/proc/idontexist", MS_RDONLY, MS_RDONLY) == -ENOENT);
@@ -230,8 +217,6 @@ TEST(bind_remount_one) {
_exit(EXIT_SUCCESS);
}
assert_se(wait_for_terminate_and_check("test-remount-one", pid, WAIT_LOG) == EXIT_SUCCESS);
}
TEST(make_mount_point_inode) {
@@ -283,10 +268,7 @@ TEST(make_mount_switch_root) {
_cleanup_free_ char *s = NULL;
int r;
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
(void) log_tests_skipped("not running privileged");
return;
}
CHECK_PRIV;
assert_se(mkdtemp_malloc(NULL, &t) >= 0);
@@ -305,18 +287,7 @@ TEST(make_mount_switch_root) {
};
FOREACH_ELEMENT(i, table) {
r = safe_fork("(switch-root)",
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG_SIGTERM |
FORK_WAIT |
FORK_REOPEN_LOG |
FORK_LOG |
FORK_NEW_MOUNTNS |
FORK_MOUNTNS_SLAVE,
NULL);
assert_se(r >= 0);
ASSERT_OK(r = safe_fork("(switch-root)", FORK_COMMON_FLAGS, NULL));
if (r == 0) {
assert_se(make_mount_point(i->path) >= 0);
assert_se(mount_switch_root_full(i->path, /* mount_propagation_flag= */ 0, i->force_ms_move) >= 0);
@@ -357,23 +328,10 @@ TEST(umount_recursive) {
int r;
CHECK_PRIV;
FOREACH_ELEMENT(t, test_table) {
r = safe_fork("(umount-rec)",
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG_SIGTERM |
FORK_WAIT |
FORK_REOPEN_LOG |
FORK_LOG |
FORK_NEW_MOUNTNS |
FORK_MOUNTNS_SLAVE,
NULL);
if (ERRNO_IS_NEG_PRIVILEGE(r))
return (void) log_notice("Skipping umount_recursive() test, lacking privileges");
assert_se(r >= 0);
ASSERT_OK(r = safe_fork("(umount-rec)", FORK_COMMON_FLAGS, NULL));
if (r == 0) { /* child */
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
@@ -422,10 +380,7 @@ TEST(fd_make_mount_point) {
_cleanup_free_ char *s = NULL;
int r;
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
(void) log_tests_skipped("not running privileged");
return;
}
CHECK_PRIV;
assert_se(mkdtemp_malloc(NULL, &t) >= 0);
@@ -433,18 +388,7 @@ TEST(fd_make_mount_point) {
assert_se(s);
assert_se(mkdir(s, 0700) >= 0);
r = safe_fork("(make_mount-point)",
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG_SIGTERM |
FORK_WAIT |
FORK_REOPEN_LOG |
FORK_LOG |
FORK_NEW_MOUNTNS |
FORK_MOUNTNS_SLAVE,
NULL);
assert_se(r >= 0);
ASSERT_OK(r = safe_fork("(make-mount-point)", FORK_COMMON_FLAGS, NULL));
if (r == 0) {
_cleanup_close_ int fd = -EBADF, fd2 = -EBADF;
@@ -468,72 +412,78 @@ TEST(fd_make_mount_point) {
TEST(bind_mount_submounts) {
_cleanup_(rmdir_and_freep) char *a = NULL, *b = NULL;
_cleanup_free_ char *x = NULL;
int r;
CHECK_PRIV;
assert_se(mkdtemp_malloc(NULL, &a) >= 0);
r = mount_nofollow_verbose(LOG_INFO, "tmpfs", a, "tmpfs", 0, NULL);
if (ERRNO_IS_NEG_PRIVILEGE(r))
return (void) log_tests_skipped("Skipping bind_mount_submounts() test, lacking privileges");
assert_se(r >= 0);
assert_se(x = path_join(a, "foo"));
assert_se(touch(x) >= 0);
free(x);
assert_se(x = path_join(a, "x"));
assert_se(mkdir(x, 0755) >= 0);
assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", x, "tmpfs", 0, NULL) >= 0);
free(x);
assert_se(x = path_join(a, "x/xx"));
assert_se(touch(x) >= 0);
free(x);
assert_se(x = path_join(a, "y"));
assert_se(mkdir(x, 0755) >= 0);
assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", x, "tmpfs", 0, NULL) >= 0);
free(x);
assert_se(x = path_join(a, "y/yy"));
assert_se(touch(x) >= 0);
free(x);
assert_se(mkdtemp_malloc(NULL, &b) >= 0);
assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", b, "tmpfs", 0, NULL) >= 0);
assert_se(x = path_join(b, "x"));
assert_se(mkdir(x, 0755) >= 0);
free(x);
ASSERT_OK(r = safe_fork("(bind-mount-submounts)", FORK_COMMON_FLAGS, NULL));
if (r == 0) {
char *x;
assert_se(x = path_join(b, "y"));
assert_se(mkdir(x, 0755) >= 0);
free(x);
ASSERT_OK(mount_nofollow_verbose(LOG_INFO, "tmpfs", a, "tmpfs", 0, NULL));
assert_se(bind_mount_submounts(a, b) >= 0);
assert_se(x = path_join(a, "foo"));
assert_se(touch(x) >= 0);
free(x);
assert_se(x = path_join(b, "foo"));
assert_se(access(x, F_OK) < 0 && errno == ENOENT);
free(x);
assert_se(x = path_join(a, "x"));
assert_se(mkdir(x, 0755) >= 0);
assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", x, "tmpfs", 0, NULL) >= 0);
free(x);
assert_se(x = path_join(b, "x/xx"));
assert_se(access(x, F_OK) >= 0);
free(x);
assert_se(x = path_join(a, "x/xx"));
assert_se(touch(x) >= 0);
free(x);
assert_se(x = path_join(b, "y/yy"));
assert_se(access(x, F_OK) >= 0);
free(x);
assert_se(x = path_join(a, "y"));
assert_se(mkdir(x, 0755) >= 0);
assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", x, "tmpfs", 0, NULL) >= 0);
free(x);
assert_se(x = path_join(b, "x"));
assert_se(path_is_mount_point(x) > 0);
free(x);
assert_se(x = path_join(a, "y/yy"));
assert_se(touch(x) >= 0);
free(x);
assert_se(x = path_join(b, "y"));
assert_se(path_is_mount_point(x) > 0);
assert_se(mount_nofollow_verbose(LOG_INFO, "tmpfs", b, "tmpfs", 0, NULL) >= 0);
assert_se(umount_recursive(a, 0) >= 0);
assert_se(umount_recursive(b, 0) >= 0);
assert_se(x = path_join(b, "x"));
assert_se(mkdir(x, 0755) >= 0);
free(x);
assert_se(x = path_join(b, "y"));
assert_se(mkdir(x, 0755) >= 0);
free(x);
assert_se(bind_mount_submounts(a, b) >= 0);
assert_se(x = path_join(b, "foo"));
assert_se(access(x, F_OK) < 0 && errno == ENOENT);
free(x);
assert_se(x = path_join(b, "x/xx"));
assert_se(access(x, F_OK) >= 0);
free(x);
assert_se(x = path_join(b, "y/yy"));
assert_se(access(x, F_OK) >= 0);
free(x);
assert_se(x = path_join(b, "x"));
assert_se(path_is_mount_point(x) > 0);
free(x);
assert_se(x = path_join(b, "y"));
assert_se(path_is_mount_point(x) > 0);
free(x);
assert_se(umount_recursive(a, 0) >= 0);
assert_se(umount_recursive(b, 0) >= 0);
_exit(EXIT_SUCCESS);
}
}
TEST(path_is_network_fs_harder) {
@@ -553,26 +503,12 @@ TEST(path_is_network_fs_harder) {
log_debug("path_is_network_fs_harder_at(root, %s) → %i: %s", q, r, r < 0 ? STRERROR(r) : yes_no(r));
}
if (geteuid() != 0 || have_effective_cap(CAP_SYS_ADMIN) <= 0) {
(void) log_tests_skipped("not running privileged");
return;
}
CHECK_PRIV;
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
assert_se(mkdtemp_malloc("/tmp/test-mount-util.path_is_network_fs_harder.XXXXXXX", &t) >= 0);
r = safe_fork("(make_mount-point)",
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG_SIGTERM |
FORK_WAIT |
FORK_REOPEN_LOG |
FORK_LOG |
FORK_NEW_MOUNTNS |
FORK_MOUNTNS_SLAVE,
NULL);
ASSERT_OK(r);
ASSERT_OK(r = safe_fork("(path-is-network-fs-harder)", FORK_COMMON_FLAGS, NULL));
if (r == 0) {
ASSERT_OK(mount_nofollow_verbose(LOG_INFO, "tmpfs", t, "tmpfs", 0, NULL));
ASSERT_OK_ZERO(path_is_network_fs_harder(t));
@@ -587,7 +523,7 @@ TEST(path_is_network_fs_harder) {
}
TEST(umountat) {
int r;
CHECK_PRIV;
_cleanup_(rm_rf_physical_and_freep) char *p = NULL;
_cleanup_close_ int dfd = mkdtemp_open(NULL, O_CLOEXEC, &p);
@@ -597,11 +533,7 @@ TEST(umountat) {
_cleanup_free_ char *q = ASSERT_PTR(path_join(p, "foo"));
r = mount_nofollow_verbose(LOG_ERR, "tmpfs", q, "tmpfs", 0, NULL);
if (ERRNO_IS_NEG_PRIVILEGE(r))
return (void) log_tests_skipped("not running privileged");
ASSERT_OK(r);
ASSERT_OK(mount_nofollow_verbose(LOG_ERR, "tmpfs", q, "tmpfs", 0, NULL));
ASSERT_OK(umountat_detach_verbose(LOG_ERR, dfd, "foo"));
ASSERT_ERROR(umountat_detach_verbose(LOG_ERR, dfd, "foo"), EINVAL);
}