diff options
Diffstat (limited to 'examples')
-rwxr-xr-x | examples/chrootfuse.py (renamed from examples/chrootfuse2fs.py) | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/examples/chrootfuse2fs.py b/examples/chrootfuse.py index eaffe25..d40e1a0 100755 --- a/examples/chrootfuse2fs.py +++ b/examples/chrootfuse.py @@ -2,13 +2,15 @@ # Copyright 2024 Helmut Grohne <helmut@subdivi.de> # SPDX-License-Identifier: GPL-3 -"""Mount a given ext4 filesystem image inside a user and mount namespace using -unprivileged fuse2fs and chroot into the mouned filesystem. +"""Mount a given filesystem image inside a user and mount namespace using +an unprivileged fuse driver and chroot into the mouned filesystem. Supported +drivers are fuse2fs and squashfuse. This requires a fuse package with support for /dev/fd/N. Either with fuse2 via -https://bugs.debian.org/1055222 or when e2fsprogs has been ported to fuse3. +https://bugs.debian.org/1055222 or fuse3. On Debian, squashfuse uses fuse3. """ +import argparse import os import pathlib import socket @@ -21,8 +23,16 @@ import linuxnamespaces def main() -> None: - fsimage = pathlib.Path(sys.argv[1]) - assert fsimage.exists() + parser = argparse.ArgumentParser() + parser.add_argument("--fstype", choices=["ext4", "squashfs"]) + parser.add_argument("fsimage", type=pathlib.Path) + args = parser.parse_args() + assert args.fsimage.exists() + if args.fstype is None: + args.fstype = args.fsimage.suffix.removeprefix(".") + if args.fstype not in ("ext4", "squashfs"): + print("Cannot determine filesystem type for image.") + sys.exit(1) uidmap = linuxnamespaces.IDAllocation.loadsubid("uid").allocatemap(65536) gidmap = linuxnamespaces.IDAllocation.loadsubid("gid").allocatemap(65536) mainpid = os.getpid() @@ -35,7 +45,11 @@ def main() -> None: _, fds, _, _ = socket.recv_fds(childsock, 1, 1, 0) childsock.close() os.set_inheritable(fds[0], True) - os.execlp("fuse2fs", "fuse2fs", str(fsimage), "/dev/fd/%d" % fds[0]) + driver = { + "ext4": "fuse2fs", + "squashfs": "squashfuse", + }[args.fstype] + os.execlp(driver, driver, str(args.fsimage), "/dev/fd/%d" % fds[0]) linuxnamespaces.unshare( linuxnamespaces.CloneFlags.NEWUSER | linuxnamespaces.CloneFlags.NEWNS ) @@ -46,17 +60,36 @@ def main() -> None: fusefd = os.open("/dev/fuse", os.O_RDWR) socket.send_fds(mainsock, [b"\0"], [fusefd]) mainsock.close() + readonly = { + "ext4": False, + "squashfs": True, + }[args.fstype] linuxnamespaces.mount( - str(fsimage), + str(args.fsimage), "/mnt", - "fuse.ext4", - linuxnamespaces.MountFlags.NONE, + "fuse." + args.fstype, + linuxnamespaces.MountFlags.RDONLY + if readonly + else linuxnamespaces.MountFlags.NONE, "fd=%d,rootmode=040755,user_id=0,group_id=0,allow_other" % fusefd, ) os.chdir("/mnt") linuxnamespaces.bind_mount("/proc", "proc", recursive=True) linuxnamespaces.bind_mount("/sys", "sys", recursive=True) linuxnamespaces.populate_dev("/", ".", pidns=False, tun=False) + if readonly: + linuxnamespaces.mount( + "tmpfs", "tmp", "tmpfs", linuxnamespaces.MountFlags.NODEV + ) + linuxnamespaces.mount( + "tmpfs", + "run", + "tmpfs", + linuxnamespaces.MountFlags.NODEV + | linuxnamespaces.MountFlags.NOSUID + | linuxnamespaces.MountFlags.NOEXEC, + "mode=0755", + ) linuxnamespaces.pivot_root(".", ".") linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH) os.close(fusefd) |