Skip to content

Commit b2e16f8

Browse files
committed
fix(container): preserve submount propagation across pivot_root
In do_pivot_root, the post-pivot call do_propagation_mount(old_root, MS_REC | MS_PRIVATE) used old_root.current_path() (a readlink of /proc/self/fd/<old_root>) as the mount target. old_root is opened on the host root mount *before* pivot_root(".", "."); after the pivot that readlink resolves to "/" (i.e. the *new* root X), not to the old root. The recursive MS_PRIVATE therefore landed on X and its entire subtree, clobbering the propagation type that /run/media, /sys, etc. had just inherited from their host sources during do_mounts. Root cause: pivot_root(".", ".") makes the new rootfs X the namespace root and parks the old root at the cwd. A subsequent readlink of the pre-pivot old_root fd returns "/" because the detached old root mount is reported through the new root, so the MS_REC|MS_PRIVATE recursively re-privatized X's subtree instead of the old root's. Fix: drop the fd-based target and use the cwd literal "." — fchdir(old_root) has just set cwd to the old root, so "." unambiguously refers to it. The recursive private now only touches the old root's subtree (host-side mounts), leaving the new root and its inherited-slave submounts untouched. Also open new_root with O_PATH instead of O_RDONLY: fchdir accepts O_PATH descriptors since Linux 3.5 and pivot_root(".", ".") operates on the cwd, so a read-write descriptor is unnecessary. Signed-off-by: Yuming He <ComixHe1895@outlook.com>
1 parent 27f6e97 commit b2e16f8

1 file changed

Lines changed: 7 additions & 3 deletions

File tree

src/linyaps_box/container.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,7 +1467,7 @@ void do_pivot_root(const linyaps_box::container &container, const std::filesyste
14671467
LINYAPS_BOX_DEBUG() << "start pivot root";
14681468
LINYAPS_BOX_DEBUG() << linyaps_box::utils::inspect_fds();
14691469
auto old_root = linyaps_box::utils::open("/", O_DIRECTORY | O_PATH | O_CLOEXEC);
1470-
auto new_root = linyaps_box::utils::open(rootfs.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC);
1470+
auto new_root = linyaps_box::utils::open(rootfs.c_str(), O_DIRECTORY | O_PATH | O_CLOEXEC);
14711471

14721472
auto old_root_stat = linyaps_box::utils::statfs(old_root);
14731473
LINYAPS_BOX_DEBUG() << "Pivot root old root: " << dump_mount_flags(old_root_stat.f_flags);
@@ -1492,8 +1492,12 @@ void do_pivot_root(const linyaps_box::container &container, const std::filesyste
14921492
throw std::system_error(errno, std::system_category(), "fchdir");
14931493
}
14941494

1495-
// make sure that umount event couldn't propagate to host
1496-
do_propagation_mount(old_root, MS_REC | MS_PRIVATE);
1495+
// make sure that umount event couldn't propagate to host.
1496+
// target the old root via cwd "." (set by fchdir(old_root) above); do NOT use
1497+
// old_root.current_path(); after pivot_root(".", ".") the old_root fd's readlink
1498+
// resolves to "/" (= new root X), which would recursively privatize X and all
1499+
// submounts (e.g. /run/media, /sys), overriding their inherited propagation.
1500+
syscall_mount(nullptr, ".", nullptr, MS_REC | MS_PRIVATE, nullptr);
14971501

14981502
// umount old root
14991503
ret = umount2(".", MNT_DETACH);

0 commit comments

Comments
 (0)