mirror of
https://github.com/usestrix/strix.git
synced 2026-08-17 01:29:42 +02:00
fix(llm): open the store lock file with O_NOFOLLOW
The predictable lock path was opened with Path.open("w"), following (and
truncating through) a pre-positioned symlink. Open it via os.open with
O_NOFOLLOW and no O_TRUNC, raising StoreLockError on a symlinked lock path.
This commit is contained in:
@@ -129,7 +129,15 @@ def _acquire_flock(path: Path) -> TextIOWrapper:
|
||||
raise StoreLockError(msg) from exc
|
||||
lock_path = path.with_suffix(".lock")
|
||||
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
handle = lock_path.open("w")
|
||||
# O_NOFOLLOW rejects a pre-positioned symlink at the predictable lock path
|
||||
# (so an attacker can't redirect the open), and no O_TRUNC since the lock
|
||||
# file is only an flock anchor whose contents we never use.
|
||||
try:
|
||||
fd = os.open(str(lock_path), os.O_RDWR | os.O_CREAT | os.O_NOFOLLOW, 0o600)
|
||||
except OSError as exc:
|
||||
msg = f"could not open lock file {lock_path}: {exc}"
|
||||
raise StoreLockError(msg) from exc
|
||||
handle = os.fdopen(fd, "r+")
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
|
||||
@@ -88,3 +88,20 @@ def test_mutation_aborts_when_lock_cannot_be_acquired(
|
||||
with pytest.raises(subscription_store.StoreLockError):
|
||||
grok.save_record({"type": "oauth", "access": "g", "refresh": "r"})
|
||||
assert not store.exists()
|
||||
|
||||
|
||||
def test_lock_file_rejects_a_pre_positioned_symlink(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
store_dir = tmp_path / ".strix"
|
||||
store_dir.mkdir()
|
||||
store = store_dir / "subscription-auth.json"
|
||||
monkeypatch.setattr(grok, "AUTH_PATH", store)
|
||||
# Attacker pre-plants a symlink where the lock file would be created.
|
||||
outside = tmp_path / "attacker-target"
|
||||
store.with_suffix(".lock").symlink_to(outside)
|
||||
|
||||
with pytest.raises(subscription_store.StoreLockError):
|
||||
grok.save_record({"type": "oauth", "access": "g", "refresh": "r"})
|
||||
# The symlink target was never created/truncated through the lock open.
|
||||
assert not outside.exists()
|
||||
|
||||
Reference in New Issue
Block a user