mount-util: simplify mount_switch_root() a bit

There's no need to fchdir() out of the rootfs and back into it around
the umount2(), hence don't.

This brings the logic closer to what the pivot_root() man page suggests.

While we are at it, always operate based on fds, once we opened the
original dir, and pass the path string along only for generating
messages (i.e. as "decoration").

Add tests for both code paths: the pivot_root() one and the MS_MOUNT.
This commit is contained in:
Lennart Poettering
2023-05-03 20:52:19 +01:00
committed by Luca Boccassi
parent 64ff6ad494
commit ea0f3289a2
3 changed files with 80 additions and 37 deletions
+43
View File
@@ -16,6 +16,7 @@
#include "namespace-util.h"
#include "path-util.h"
#include "process-util.h"
#include "random-util.h"
#include "rm-rf.h"
#include "stat-util.h"
#include "string-util.h"
@@ -388,6 +389,48 @@ TEST(make_mount_point_inode) {
assert_se(!(S_IXOTH & st.st_mode));
}
TEST(make_mount_switch_root) {
_cleanup_(rm_rf_physical_and_freep) char *t = NULL;
_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;
}
assert_se(mkdtemp_malloc(NULL, &t) >= 0);
assert_se(asprintf(&s, "%s/somerandomname%" PRIu64, t, random_u64()) >= 0);
assert_se(s);
assert_se(touch(s) >= 0);
for (int force_ms_move = 0; force_ms_move < 2; force_ms_move++) {
r = safe_fork("(switch-root",
FORK_RESET_SIGNALS |
FORK_CLOSE_ALL_FDS |
FORK_DEATHSIG |
FORK_WAIT |
FORK_REOPEN_LOG |
FORK_LOG |
FORK_NEW_MOUNTNS |
FORK_MOUNTNS_SLAVE,
NULL);
assert_se(r >= 0);
if (r == 0) {
assert_se(make_mount_point(t) >= 0);
assert_se(mount_switch_root_full(t, /* mount_propagation_flag= */ 0, force_ms_move) >= 0);
assert_se(access(ASSERT_PTR(strrchr(s, '/')), F_OK) >= 0); /* absolute */
assert_se(access(ASSERT_PTR(strrchr(s, '/')) + 1, F_OK) >= 0); /* relative */
assert_se(access(s, F_OK) < 0 && errno == ENOENT); /* doesn't exist in our new environment */
_exit(EXIT_SUCCESS);
}
}
}
static int intro(void) {
/* Create a dummy network interface for testing remount_sysfs(). */
(void) system("ip link add dummy-test-mnt type dummy");