Skip to content

Commit 6940c7f

Browse files
test: closes #1099 jailer mount propagation by creating mounts for the guest kernel and rootfs and mounting them to the jailer root as mentioned in #1089 Signed-off-by: Anthony Corletti <[email protected]>
1 parent 3ca2fab commit 6940c7f

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ test_results/*
1515
/resources/linux
1616
/resources/x86_64
1717
/resources/aarch64
18+
.venv

tests/framework/microvm.py

+24
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import select
1919
import shutil
2020
import signal
21+
import subprocess
2122
import time
2223
import uuid
2324
from collections import namedtuple
@@ -1115,13 +1116,36 @@ def build_from_snapshot(self, snapshot: Snapshot):
11151116
vm.restore_from_snapshot(snapshot, resume=True)
11161117
return vm
11171118

1119+
def unmount(self, path: str) -> None:
1120+
"""Unmounts a path with `umount` in a subprocess"""
1121+
try:
1122+
subprocess.run(["umount", path], check=True)
1123+
except subprocess.CalledProcessError:
1124+
print(f"Failed to unmount {path}")
1125+
1126+
def get_mounts_at_path(self, path: str) -> list:
1127+
"""Get all mounts for a given path. Returns a list of mount points."""
1128+
try:
1129+
with open("/proc/mounts", "r", encoding="utf-8") as f:
1130+
return [
1131+
line.split()[1]
1132+
for line in f
1133+
if line.split()[1].startswith(os.path.abspath(path))
1134+
]
1135+
except FileNotFoundError:
1136+
return False # /proc/mounts may not exist on some systems
1137+
11181138
def kill(self):
11191139
"""Clean up all built VMs"""
11201140
for vm in self.vms:
11211141
vm.kill()
11221142
vm.jailer.cleanup()
11231143
chroot_base_with_id = vm.jailer.chroot_base_with_id()
11241144
if len(vm.jailer.jailer_id) > 0 and chroot_base_with_id.exists():
1145+
mounts = self.get_mounts_at_path(chroot_base_with_id)
1146+
if mounts:
1147+
for mounted_path in mounts:
1148+
self.unmount(mounted_path)
11251149
shutil.rmtree(chroot_base_with_id)
11261150
vm.netns.cleanup()
11271151

tests/integration_tests/security/test_jail.py

+73
Original file line numberDiff line numberDiff line change
@@ -664,3 +664,76 @@ def test_cgroupsv2_written_only_once(uvm_plain, cgroups_info):
664664
assert len(write_lines) == 1
665665
assert len(mkdir_lines) != len(cgroups), "mkdir equal to number of cgroups"
666666
assert len(mkdir_lines) == 1
667+
668+
669+
def test_mount_proagation_to_root(uvm_plain, tmp_path, guest_kernel, rootfs_rw):
670+
"""
671+
Test that the jailer mounts are propagated to the root mount namespace.
672+
673+
This is a test for
674+
https://github.com/firecracker-microvm/firecracker/pull/#1093
675+
"""
676+
677+
test_microvm = uvm_plain
678+
679+
# make a directory to hold the original content
680+
original_content_dir = tmp_path / "original"
681+
original_content_dir.mkdir(parents=True)
682+
683+
# make a directory to hold the jailed content
684+
jailed_content_dir = tmp_path / "firecracker" / "testbindmount" / "root"
685+
jailed_content_dir.mkdir(parents=True)
686+
687+
test_microvm.jailer.jailer_id = "testbindmount"
688+
test_microvm.jailer.chroot_base = tmp_path
689+
test_microvm.jailer.daemonize = True
690+
test_microvm.jailer.gid = 0
691+
test_microvm.jailer.uid = 0
692+
test_microvm.extra_args = {"seccomp-level": 0}
693+
694+
# assert that the directory was created
695+
assert jailed_content_dir.exists()
696+
697+
# Create the guest kernel and rootfs in the jailed content directory
698+
# and mount them in the jailed content directory
699+
os.system(f"cp {guest_kernel} {original_content_dir}")
700+
os.system(f"cp {rootfs_rw} {original_content_dir}")
701+
guest_kernel_mount_path = jailed_content_dir / os.path.basename(guest_kernel)
702+
rootfs_mount_path = jailed_content_dir / os.path.basename(rootfs_rw)
703+
guest_kernel_mount_path.touch()
704+
rootfs_mount_path.touch()
705+
706+
# assert that the files were created
707+
assert guest_kernel_mount_path.exists()
708+
assert rootfs_mount_path.exists()
709+
710+
# mount the rootfs
711+
subprocess.run(
712+
[
713+
"mount",
714+
"--bind",
715+
original_content_dir / os.path.basename(guest_kernel),
716+
guest_kernel_mount_path,
717+
],
718+
check=True,
719+
)
720+
subprocess.run(
721+
[
722+
"mount",
723+
"--bind",
724+
original_content_dir / os.path.basename(rootfs_rw),
725+
rootfs_mount_path,
726+
],
727+
check=True,
728+
)
729+
730+
# assert that the mounts are present
731+
assert guest_kernel_mount_path.exists()
732+
assert rootfs_mount_path.exists()
733+
734+
# run
735+
test_microvm.spawn()
736+
737+
# assert that the mounts are present
738+
assert guest_kernel_mount_path.exists()
739+
assert rootfs_mount_path.exists()

0 commit comments

Comments
 (0)