summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rwxr-xr-xexamples/chroottar.py63
1 files changed, 56 insertions, 7 deletions
diff --git a/examples/chroottar.py b/examples/chroottar.py
index ec76813..1fb07be 100755
--- a/examples/chroottar.py
+++ b/examples/chroottar.py
@@ -35,6 +35,17 @@ def main() -> None:
help="save and replace the tarball at the end of the session",
)
parser.add_argument(
+ "--same-uid",
+ action="store_true",
+ help="map the current user to itself in the namespace",
+ )
+ parser.add_argument(
+ "--bind",
+ action="append",
+ help="bind mount the given location after extraction",
+ default=[],
+ )
+ parser.add_argument(
"basetar",
type=pathlib.Path,
action="store",
@@ -47,8 +58,43 @@ def main() -> None:
)
args = parser.parse_args()
assert args.basetar.exists()
- uidmap = linuxnamespaces.IDAllocation.loadsubid("uid").allocatemap(65536)
- gidmap = linuxnamespaces.IDAllocation.loadsubid("gid").allocatemap(65536)
+ myuid = os.getuid()
+ mygid = os.getgid()
+ uidrange = linuxnamespaces.IDAllocation.loadsubid("uid").allocatemap(65536)
+ gidrange = linuxnamespaces.IDAllocation.loadsubid("gid").allocatemap(65536)
+ if args.same_uid:
+ uidmaps = [
+ uidrange[:myuid],
+ linuxnamespaces.IDMapping(uidrange.innerstart + myuid, myuid, 1),
+ uidrange[myuid + 1:],
+ ]
+ gidmaps = [
+ gidrange[:mygid],
+ linuxnamespaces.IDMapping(gidrange.innerstart + mygid, mygid, 1),
+ gidrange[mygid + 1:],
+ ]
+ else:
+ uidmaps = [uidrange]
+ gidmaps = [gidrange]
+ bindmounts = []
+ for conf in args.bind:
+ confparts = conf.split(":")
+ if not os.path.exists(confparts[0]):
+ raise ValueError(
+ f"cannot bind mount {confparts[0]}: does not exist"
+ )
+ if len(confparts) > 2:
+ raise ValueError(f"bind mount {conf} not understood")
+ if len(confparts) < 2:
+ confparts.append(confparts[0])
+ bindmounts.append(
+ (
+ os.path.abspath(confparts[0]),
+ os.path.normpath(
+ os.path.join("/", confparts[1])
+ ).removeprefix("/"),
+ ),
+ )
with tempfile.TemporaryDirectory() as tdir:
parentsock, childsock = socket.socketpair()
pid = os.fork()
@@ -84,6 +130,9 @@ def main() -> None:
linuxnamespaces.bind_mount("/proc", "proc", recursive=True)
linuxnamespaces.bind_mount("/sys", "sys", recursive=True)
linuxnamespaces.populate_dev("/", ".", pts="host", tun=False)
+ for source, target in bindmounts:
+ os.makedirs(target, exist_ok=True)
+ linuxnamespaces.bind_mount(source, target, recursive=True)
linuxnamespaces.pivot_root(".", ".")
linuxnamespaces.umount(".", linuxnamespaces.UmountFlags.DETACH)
if args.command:
@@ -94,14 +143,14 @@ def main() -> None:
childsock.close()
comptype = parentsock.recv(10).split(b"\0", 1)[0].decode("ascii")
- linuxnamespaces.newidmaps(pid, [uidmap], [gidmap])
+ linuxnamespaces.newidmaps(pid, uidmaps, gidmaps)
# We still had to be in the initial namespace to call newidmaps and
# now we transition to a namespace that can access both the container
# and the files of the invoking user.
- linuxnamespaces.unshare_user_idmap(
- [uidmap, linuxnamespaces.IDMapping(65536, os.getuid(), 1)],
- [gidmap, linuxnamespaces.IDMapping(65536, os.getgid(), 1)],
- )
+ if not args.same_uid:
+ uidmaps.append(linuxnamespaces.IDMapping(65536, myuid, 1))
+ gidmaps.append(linuxnamespaces.IDMapping(65536, mygid, 1))
+ linuxnamespaces.unshare_user_idmap(uidmaps, gidmaps)
os.chown(tdir, 0, 0)
os.chmod(tdir, 0o755)
parentsock.send(b"\0")