From 8b98dc846e7bd911360820f085a1b21307b28e89 Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Sat, 24 Feb 2024 23:02:25 +0100 Subject: populate_dev: remove assumption that newdev does not shadow origdev In particular, one can now pass newdev = origdev. --- linuxnamespaces/__init__.py | 78 +++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/linuxnamespaces/__init__.py b/linuxnamespaces/__init__.py index b0e5b85..63b0d21 100644 --- a/linuxnamespaces/__init__.py +++ b/linuxnamespaces/__init__.py @@ -307,21 +307,55 @@ def populate_dev( """ origdev = AtLocation(origroot) / "dev" newdev = AtLocation(newroot) / "dev" - bind_devices = "null zero full random urandom tty".split() - if fuse: - bind_devices.append("fuse") - bind_directories = [] - mount( - "devtmpfs", - newdev, - "tmpfs", - MountFlags.NOSUID | MountFlags.NOEXEC, - "mode=0755", - ) - with _ExceptionExitCallback(umount, newdev, UmountFlags.DETACH): + directories = {"pts"} + files = set() + symlinks = {} + bind_mounts: dict[str, AtLocation] = {} + with contextlib.ExitStack() as exitstack: + for fn in "null zero full random urandom tty".split(): + files.add(fn) + bind_mounts[fn] = exitstack.enter_context( + open_tree(origdev / fn, OpenTreeFlags.OPEN_TREE_CLONE) + ) + if fuse: + files.add("fuse") + bind_mounts["fuse"] = exitstack.enter_context( + open_tree(origdev / "fuse", OpenTreeFlags.OPEN_TREE_CLONE) + ) + if pidns: + symlinks["ptmx"] = "pts/ptmx" + else: + bind_mounts["pts"] = exitstack.enter_context( + open_tree( + origdev / "pts", + OpenTreeFlags.AT_RECURSIVE | OpenTreeFlags.OPEN_TREE_CLONE, + ) + ) + files.add("ptmx") + bind_mounts["ptmx"] = exitstack.enter_context( + open_tree(origdev / "ptmx", OpenTreeFlags.OPEN_TREE_CLONE) + ) + if tun: + directories.add("net") + files.add("net/tun") + mount( + "devtmpfs", + newdev, + "tmpfs", + MountFlags.NOSUID | MountFlags.NOEXEC, + "mode=0755", + ) + exitstack.enter_context( + _ExceptionExitCallback(umount, newdev, UmountFlags.DETACH) + ) + for fn in directories: + (newdev / fn).mkdir() + (newdev / fn).chmod(0o755) + for fn in files: + (newdev / fn).mknod(stat.S_IFREG) + for fn, target in symlinks.items(): + (newdev / fn).symlink(target) if pidns: - (newdev / "pts").mkdir() - (newdev / "pts").chmod(0o755) mount( "devpts", newdev / "pts", @@ -329,20 +363,8 @@ def populate_dev( MountFlags.NOSUID | MountFlags.NOEXEC, "gid=5,mode=620,ptmxmode=666", ) - (newdev / "ptmx").symlink("pts/ptmx") - else: - bind_devices.append("ptmx") - bind_directories.append("pts") - if tun: - (newdev / "net").mkdir() - (newdev / "net").chmod(0o755) - bind_devices.append("net/tun") - for node in bind_devices: - (newdev / node).mknod(stat.S_IFREG) - bind_mount(origdev / node, newdev / node, True) - for node in bind_directories: - (newdev / node).mkdir() - bind_mount(origdev / node, newdev / node, True) + for fn, fd in bind_mounts.items(): + move_mount(fd, newdev / fn) def populate_sys( -- cgit v1.2.3