Skip to content

Commit 64a2e0e

Browse files
committed
linux: Update rootfsfd when rootfs is replaced
When a mount operation replaces the container's root filesystem ("/"), the existing `rootfsfd` becomes stale. This file descriptor would still point to the old, now overmounted root, potentially causing subsequent filesystem operations within the container setup to fail or target the incorrect filesystem. Closes: #1752 Signed-off-by: Giuseppe Scrivano <[email protected]>
1 parent 7de03e6 commit 64a2e0e

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

src/libcrun/linux.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,17 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd,
12271227
if (UNLIKELY (fd < 0))
12281228
return fd;
12291229

1230+
/* We are replacing the rootfs, reopen it. */
1231+
if (is_empty_string (target))
1232+
{
1233+
int tmp = dup (fd);
1234+
if (UNLIKELY (tmp < 0))
1235+
return crun_make_error (err, errno, "dup");
1236+
1237+
TEMP_FAILURE_RETRY (close (get_private_data (container)->rootfsfd));
1238+
get_private_data (container)->rootfsfd = tmp;
1239+
}
1240+
12301241
#ifdef HAVE_FGETXATTR
12311242
if (label_how == LABEL_XATTR)
12321243
{

tests/test_mounts.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,33 @@ def prepare_rootfs(rootfs):
115115
return 0
116116
return -1
117117

118+
def test_mount_bind_to_rootfs():
119+
conf = base_config()
120+
conf['process']['args'] = ['/init', 'true']
121+
add_all_namespaces(conf)
122+
tmpdir = tempfile.mkdtemp()
123+
shutil.copy(get_init_path(), tmpdir)
124+
125+
mounts = [
126+
{"destination": "/", "type": "bind", "source": tmpdir, "options": ["bind"]},
127+
]
128+
conf['mounts'] = mounts + conf['mounts']
129+
_, _ = run_and_get_output(conf, hide_stderr=True)
130+
return 0
131+
132+
def test_mount_tmpfs_to_rootfs():
133+
conf = base_config()
134+
conf['process']['args'] = ['/init', 'true']
135+
add_all_namespaces(conf)
136+
tmpdir = tempfile.mkdtemp()
137+
138+
mounts = [
139+
{"destination": "/", "type": "tmpfs", "source": "tmpfs", "options": ["tmpcopyup"]},
140+
]
141+
conf['mounts'] = mounts + conf['mounts']
142+
_, _ = run_and_get_output(conf, hide_stderr=True)
143+
return 0
144+
118145
def test_ro_cgroup():
119146
for cgroupns in [True, False]:
120147
for netns in [True, False]:
@@ -693,6 +720,8 @@ def test_mount_help():
693720
"mount-unix-socket" : test_mount_unix_socket,
694721
"mount-symlink-not-existing" : test_mount_symlink_not_existing,
695722
"mount-dev" : test_mount_dev,
723+
"mount-bind-to-rootfs": test_mount_bind_to_rootfs,
724+
"mount-tmpfs-to-rootfs": test_mount_tmpfs_to_rootfs,
696725
"mount-nodev" : test_mount_nodev,
697726
"mount-path-with-multiple-slashes" : test_mount_path_with_multiple_slashes,
698727
"mount-userns-bind-mount" : test_userns_bind_mount,

0 commit comments

Comments
 (0)