From 345a1d1f8af18586a9efb42db86870f55fca5d4c Mon Sep 17 00:00:00 2001 From: Ivan Date: Sat, 18 Jul 2026 05:35:23 -0500 Subject: [PATCH] feat: fix _collect_read_roots to include virtual environment root for pyvenv.cfg access --- meshchatx.rsm | Bin 155754 -> 155754 bytes meshchatx/src/backend/landlock_sandbox.py | 16 +++++++++-- tests/backend/test_landlock_sandbox.py | 33 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/meshchatx.rsm b/meshchatx.rsm index e95642156029045c4b78176264ecfb4260876361..d27fa7213a751e23829ef36c8bd4c6a94cce72fe 100644 GIT binary patch delta 264 zcmV+j0r&puzzOQW2|$!|hhtaF(BoDbfuDPaY`S#A^!E3)Mi)j|QO#E7G(uw#_Z;*7 z;8h<)f(KUHVEcmhIrZD8q6$j{UIHD8EDn)C7$AxdyI+~;9fFp&+R6qnyOv+o3H(PV zHgDN;zGuJfGMlk@mvKNfHDfX~WMwfhGBG(cV>mQ7HZoyhWjQf7HaRmlHZnFhVKg*i zIb=97IbkwoH(@h5Wi~T8HDfShHD)noFlIB8L01@qXL7e^asf;=KQcErHZ*25WiV!D zW-($gG-G37VPiC8IAb(1WHLBoI5jk7VKz83W;iouGcjdlGBag2GBh-0Wo9-oHeqHp Omw~4N7Pknf0b;n&GGh_| delta 264 zcmV+j0r&puzzOQW2|!v~#5*YTc?i)(U;tdQTW`iDO?BA*rw{%3mX_=404zClaV-&$ z;4|=d;tL&H`II2jAj~g-!95r1E9KIs>j05J7$Ee$ev6K|Am>=6cy=%qg list[str]: exe_dir = _existing_dir(os.path.dirname(candidate)) if exe_dir: roots.add(exe_dir) - # Prefer the install prefix (…/cpython-…/) so bin + lib are covered. - prefix = _existing_dir(getattr(sys, "base_prefix", None) or sys.prefix) + # Venv layouts put pyvenv.cfg next to bin/, not under it. Allowing only + # …/bin leaves child interpreters unable to read pyvenv.cfg (EACCES). + venv_root = os.path.dirname(exe_dir) if exe_dir else None + if venv_root and os.path.isfile(os.path.join(venv_root, "pyvenv.cfg")): + existing_venv = _existing_dir(venv_root) + if existing_venv: + roots.add(existing_venv) + # Prefer the install prefix (…/cpython-…/) so bin + lib are covered. + for prefix_candidate in ( + getattr(sys, "base_prefix", None), + sys.prefix, + os.environ.get("VIRTUAL_ENV"), + ): + prefix = _existing_dir(prefix_candidate) if prefix: roots.add(prefix) return sorted(roots) diff --git a/tests/backend/test_landlock_sandbox.py b/tests/backend/test_landlock_sandbox.py index 63ef1e94..5e417f91 100644 --- a/tests/backend/test_landlock_sandbox.py +++ b/tests/backend/test_landlock_sandbox.py @@ -107,6 +107,39 @@ def test_collect_read_roots_includes_interpreter_prefix(): assert any( prefix == root or prefix.startswith(root.rstrip("/") + "/") for root in roots ), f"prefix {prefix!r} not covered by {roots!r}" + # Active venv root (sys.prefix) must be allowed even when base_prefix differs, + # otherwise child Python cannot read pyvenv.cfg (Docker /opt/venv + rnsh). + venv_prefix = os.path.realpath(sys.prefix) + assert any( + venv_prefix == root or venv_prefix.startswith(root.rstrip("/") + "/") + for root in roots + ), f"sys.prefix {venv_prefix!r} not covered by {roots!r}" + + +def test_collect_read_roots_includes_venv_root_for_pyvenv_cfg(tmp_path, monkeypatch): + """Landlock must allow the venv root, not only …/bin (pyvenv.cfg sibling).""" + venv = tmp_path / "opt" / "venv" + bindir = venv / "bin" + bindir.mkdir(parents=True) + (venv / "pyvenv.cfg").write_text("home = /usr\n", encoding="utf-8") + fake_python = bindir / "python" + fake_python.write_text("#!/bin/sh\n", encoding="utf-8") + + class _FakeSys: + platform = sys.platform + executable = str(fake_python) + prefix = str(venv) + base_prefix = "/usr" + path = list(sys.path) + + monkeypatch.setattr(ll, "sys", _FakeSys) + monkeypatch.setattr(ll.site, "getsitepackages", lambda: []) + monkeypatch.setattr(ll.site, "getusersitepackages", lambda: "") + monkeypatch.setenv("VIRTUAL_ENV", str(venv)) + + roots = {os.path.realpath(r) for r in ll._collect_read_roots()} + assert os.path.realpath(str(venv)) in roots + assert os.path.realpath(str(bindir)) in roots def test_handled_access_fs_for_abi_gates_new_rights():