summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2025-06-01 19:48:23 +0200
committerHelmut Grohne <helmut@subdivi.de>2025-06-01 19:48:23 +0200
commit561ba14cddd2cd0b162016bb0136c6c5eae600cb (patch)
tree09af480130c6a8a5d8130841757a4262738400cb
parentca32b72b72ce36c2bb987f53056ca2616fcba216 (diff)
downloadpython-linuxnamespaces-561ba14cddd2cd0b162016bb0136c6c5eae600cb.tar.gz
idmapping functions accept a further proc arguement
This allows opening /proc as an O_PATH descriptor, then locking a process up and then still writing idmaps by accessing the now inaccessible /proc via the retained file descriptor.
-rw-r--r--linuxnamespaces/__init__.py11
-rw-r--r--linuxnamespaces/idmap.py34
2 files changed, 34 insertions, 11 deletions
diff --git a/linuxnamespaces/__init__.py b/linuxnamespaces/__init__.py
index ab06fb7..f19503a 100644
--- a/linuxnamespaces/__init__.py
+++ b/linuxnamespaces/__init__.py
@@ -409,7 +409,11 @@ def unshare_user_idmap(
def unshare_user_idmap_nohelper(
- uid: int, gid: int, flags: CloneFlags = CloneFlags.NEWUSER
+ uid: int,
+ gid: int,
+ flags: CloneFlags = CloneFlags.NEWUSER,
+ *,
+ proc: AtLocationLike | None = None,
) -> None:
"""Unshare the given namespaces (must include user) and
map the current user and group to the given uid and gid
@@ -418,8 +422,9 @@ def unshare_user_idmap_nohelper(
uidmap = IDMapping(uid, os.getuid(), 1)
gidmap = IDMapping(gid, os.getgid(), 1)
unshare(flags)
- pathlib.Path("/proc/self/setgroups").write_bytes(b"deny")
- newidmaps(-1, [uidmap], [gidmap], False)
+ proc = AtLocation("/proc" if proc is None else proc)
+ (proc / "self/setgroups").write_bytes(b"deny")
+ newidmaps(-1, [uidmap], [gidmap], False, proc=proc)
class _AsyncFilesender:
diff --git a/linuxnamespaces/idmap.py b/linuxnamespaces/idmap.py
index d75f1a9..a10ec12 100644
--- a/linuxnamespaces/idmap.py
+++ b/linuxnamespaces/idmap.py
@@ -8,10 +8,11 @@ namespace.
import bisect
import dataclasses
import os
-import pathlib
import subprocess
import typing
+from .atlocation import AtLocation, AtLocationLike
+
def subidranges(
kind: typing.Literal["uid", "gid"], login: str | None = None
@@ -174,6 +175,8 @@ def newidmap(
pid: int,
mapping: list[IDMapping],
helper: bool | None = None,
+ *,
+ proc: AtLocationLike | None = None,
) -> None:
"""Apply the given uid or gid mapping to the given process. A positive pid
identifies a process, other values identify the currently running process.
@@ -196,7 +199,8 @@ def newidmap(
argv.extend(map(str, dataclasses.astuple(idblock)))
subprocess.check_call(argv)
else:
- pathlib.Path(f"/proc/{pid}/{kind}_map").write_text(
+ proc = AtLocation("/proc" if proc is None else proc)
+ (proc / f"{pid}/{kind}_map").write_text(
"".join(
"%d %d %d\n" % dataclasses.astuple(idblock)
for idblock in mapping
@@ -205,18 +209,30 @@ def newidmap(
)
-def newuidmap(pid: int, mapping: list[IDMapping], helper: bool = True) -> None:
+def newuidmap(
+ pid: int,
+ mapping: list[IDMapping],
+ helper: bool = True,
+ *,
+ proc: AtLocationLike | None = None,
+) -> None:
"""Apply a given uid mapping to the given process. Refer to newidmap for
details.
"""
- newidmap("uid", pid, mapping, helper)
+ newidmap("uid", pid, mapping, helper, proc=proc)
-def newgidmap(pid: int, mapping: list[IDMapping], helper: bool = True) -> None:
+def newgidmap(
+ pid: int,
+ mapping: list[IDMapping],
+ helper: bool = True,
+ *,
+ proc: AtLocationLike | None = None,
+) -> None:
"""Apply a given gid mapping to the given process. Refer to newidmap for
details.
"""
- newidmap("gid", pid, mapping, helper)
+ newidmap("gid", pid, mapping, helper, proc=proc)
def newidmaps(
@@ -224,9 +240,11 @@ def newidmaps(
uidmapping: list[IDMapping],
gidmapping: list[IDMapping],
helper: bool = True,
+ *,
+ proc: AtLocationLike | None = None,
) -> None:
"""Apply a given uid and gid mapping to the given process. Refer to
newidmap for details.
"""
- newgidmap(pid, gidmapping, helper)
- newuidmap(pid, uidmapping, helper)
+ newgidmap(pid, gidmapping, helper, proc=proc)
+ newuidmap(pid, uidmapping, helper, proc=proc)