summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/chrootfuse2fs.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/examples/chrootfuse2fs.py b/examples/chrootfuse2fs.py
new file mode 100644
index 0000000..8864a90
--- /dev/null
+++ b/examples/chrootfuse2fs.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python3
+# 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.
+
+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.
+"""
+
+import os
+import pathlib
+import socket
+import sys
+
+if __file__.split("/")[-2:-1] == ["examples"]:
+ sys.path.insert(0, "/".join(__file__.split("/")[:-2]))
+
+import linuxnamespaces
+
+
+def main() -> None:
+ fsimage = pathlib.Path(sys.argv[2])
+ assert fsimage.exists()
+ uidmap = linuxnamespaces.IDAllocation.loadsubid("uid").allocatemap(65536)
+ gidmap = linuxnamespaces.IDAllocation.loadsubid("gid").allocatemap(65536)
+ mainpid = os.getpid()
+ mainsock, childsock = socket.socketpair()
+ @linuxnamespaces.run_in_fork
+ def setup() -> None:
+ mainsock.close()
+ linuxnamespaces.newidmaps(mainpid, [uidmap], [gidmap])
+ childsock.send(b"\0")
+ _, 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])
+ linuxnamespaces.unshare(
+ linuxnamespaces.CloneFlags.NEWUSER | linuxnamespaces.CloneFlags.NEWNS
+ )
+ setup.start()
+ mainsock.recv(1)
+ os.setreuid(0, 0)
+ os.setregid(0, 0)
+ fusefd = os.open("/dev/fuse", os.O_RDWR)
+ socket.send_fds(mainsock, [b"\0"], [fusefd])
+ mainsock.close()
+ linuxnamespaces.mount(
+ str(fsimage),
+ "/mnt",
+ "fuse.ext4",
+ 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)
+ linuxnamespaces.pivot_root(".", ".")
+ linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH)
+ os.close(fusefd)
+ os.execlp(os.environ["SHELL"], os.environ["SHELL"])
+
+
+if __name__ == "__main__":
+ main()