Skip to content

Commit 79d7303

Browse files
authored
Allow trusted Nix store CLI paths (#992)
1 parent 02c1646 commit 79d7303

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

launcher/cli-launch-path.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@ def validate_parent_chain(path: Path, subject: str) -> None:
6767
f"{subject} ancestor {parent} is owned by untrusted uid {metadata.st_uid}"
6868
)
6969
writable = metadata.st_mode & 0o022
70-
root_owned_sticky = (
71-
metadata.st_uid == 0
72-
and metadata.st_mode & stat.S_ISVTX
73-
and metadata.st_mode & 0o002
74-
)
70+
root_owned_sticky = metadata.st_uid == 0 and metadata.st_mode & stat.S_ISVTX
7571
if writable and not root_owned_sticky:
7672
raise TrustError(
7773
f"{subject} ancestor {parent} is group/world-writable and therefore untrusted"

tests/scripts_smoke.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6716,7 +6716,10 @@ SCRIPT
67166716
import importlib.util
67176717
import os
67186718
import pathlib
6719+
import stat
67196720
import sys
6721+
from types import SimpleNamespace
6722+
from unittest import mock
67206723

67216724
spec = importlib.util.spec_from_file_location("cli_launch_path", pathlib.Path(sys.argv[1]))
67226725
module = importlib.util.module_from_spec(spec)
@@ -6727,6 +6730,31 @@ untrusted_uid = 2 if euid == 1 else 1
67276730
assert module.trusted_owner(euid)
67286731
assert module.trusted_owner(0)
67296732
assert not module.trusted_owner(untrusted_uid)
6733+
6734+
trusted_ancestors = {
6735+
pathlib.Path("/"): SimpleNamespace(st_mode=stat.S_IFDIR | 0o755, st_uid=0),
6736+
pathlib.Path("/nix"): SimpleNamespace(st_mode=stat.S_IFDIR | 0o755, st_uid=0),
6737+
pathlib.Path("/nix/store"): SimpleNamespace(st_mode=stat.S_IFDIR | stat.S_ISVTX | 0o775, st_uid=0),
6738+
pathlib.Path("/nix/store/example"): SimpleNamespace(st_mode=stat.S_IFDIR | 0o555, st_uid=0),
6739+
pathlib.Path("/nix/store/example/bin"): SimpleNamespace(st_mode=stat.S_IFDIR | 0o555, st_uid=0),
6740+
}
6741+
with mock.patch.object(pathlib.Path, "lstat", autospec=True, side_effect=trusted_ancestors.__getitem__):
6742+
module.validate_parent_chain(
6743+
pathlib.Path("/nix/store/example/bin/codex"),
6744+
"Selected Codex CLI target",
6745+
)
6746+
6747+
trusted_ancestors[pathlib.Path("/nix/store")].st_mode = stat.S_IFDIR | 0o775
6748+
with mock.patch.object(pathlib.Path, "lstat", autospec=True, side_effect=trusted_ancestors.__getitem__):
6749+
try:
6750+
module.validate_parent_chain(
6751+
pathlib.Path("/nix/store/example/bin/codex"),
6752+
"Selected Codex CLI target",
6753+
)
6754+
except module.TrustError:
6755+
pass
6756+
else:
6757+
raise AssertionError("root-owned group-writable ancestors without sticky must remain untrusted")
67306758
PY
67316759

67326760
rm "$visible_cli"

0 commit comments

Comments
 (0)