mirror of
https://github.com/usestrix/strix.git
synced 2026-10-16 04:28:23 +00:00
fix(sandbox): skip host uid mapping for system/service accounts
STRIX_HOST_UID from a dedicated system account (uid < 1000 or without a usable home) triggers the sandbox entrypoint's demotion branch, leaving the in-container Caido sidecar with an unwritable HOME — it panics on its data directory and every scan silently degrades. Skip the mapping for such accounts and log a warning; regular login users are unaffected (regression tests included). Fixes #1514
This commit is contained in:
parent
f7a32ae62d
commit
07be5a1b00
2 changed files with 68 additions and 1 deletions
|
|
@ -49,6 +49,27 @@ _EXTRA_FILE_EXTRACT_TIMEOUT_S = 120
|
|||
_EXTRA_FILE_MODE = 0o644
|
||||
|
||||
|
||||
def _is_regular_login_user(uid: int) -> bool:
|
||||
"""Whether ``uid`` refers to an interactive login user whose home directory
|
||||
can take part in the sandbox uid-remapping flow.
|
||||
|
||||
System/service accounts (uid below the login range, or without a usable
|
||||
home directory) must not opt in: the sandbox image's entrypoint demotes
|
||||
itself to ``STRIX_HOST_UID``, and a demoted system uid ends up with an
|
||||
unwritable HOME, which panics the in-container Caido sidecar
|
||||
("Unable to create data directory") and silently degrades every scan.
|
||||
"""
|
||||
import pwd
|
||||
|
||||
if uid < 1000:
|
||||
return False
|
||||
try:
|
||||
pw_dir = pwd.getpwuid(uid).pw_dir
|
||||
except KeyError:
|
||||
return False
|
||||
return bool(pw_dir) and pw_dir not in ("/", "/nonexistent")
|
||||
|
||||
|
||||
def _host_identity_env() -> dict[str, str]:
|
||||
# Read the platform through a local so it is not narrowed to whichever OS is
|
||||
# type-checking: comparing sys.platform directly makes one of these branches
|
||||
|
|
@ -58,7 +79,15 @@ def _host_identity_env() -> dict[str, str]:
|
|||
return {}
|
||||
# Bind-mount ownership only needs mapping on Linux, where the container uid
|
||||
# must match the host's.
|
||||
return {"STRIX_HOST_UID": str(os.getuid()), "STRIX_HOST_GID": str(os.getgid())}
|
||||
uid, gid = os.getuid(), os.getgid()
|
||||
if not _is_regular_login_user(uid):
|
||||
logger.warning(
|
||||
"Skipping sandbox uid mapping for uid %s (system/service account): "
|
||||
"bind-mounted workspace files will keep the container user's ownership",
|
||||
uid,
|
||||
)
|
||||
return {}
|
||||
return {"STRIX_HOST_UID": str(uid), "STRIX_HOST_GID": str(gid)}
|
||||
|
||||
|
||||
def build_bind_mounts(local_sources: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
|
|
|
|||
38
tests/test_host_identity_env.py
Normal file
38
tests/test_host_identity_env.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import os
|
||||
from types import SimpleNamespace
|
||||
|
||||
from strix.runtime import session_manager
|
||||
|
||||
|
||||
def _as(monkeypatch, uid: int, gid: int) -> None:
|
||||
monkeypatch.setattr(os, "getuid", lambda: uid)
|
||||
monkeypatch.setattr(os, "getgid", lambda: gid)
|
||||
|
||||
|
||||
def test_system_account_uid_skips_mapping(monkeypatch):
|
||||
_as(monkeypatch, 997, 980)
|
||||
assert session_manager._host_identity_env() == {}
|
||||
|
||||
|
||||
def test_uid_below_login_range_skips_mapping(monkeypatch):
|
||||
_as(monkeypatch, 999, 999)
|
||||
assert session_manager._host_identity_env() == {}
|
||||
|
||||
|
||||
def test_homeless_uid_skips_mapping(monkeypatch):
|
||||
_as(monkeypatch, 1500, 1500)
|
||||
monkeypatch.setattr(
|
||||
"pwd.getpwuid", lambda uid: SimpleNamespace(pw_dir="/nonexistent")
|
||||
)
|
||||
assert session_manager._host_identity_env() == {}
|
||||
|
||||
|
||||
def test_regular_user_is_mapped(monkeypatch):
|
||||
_as(monkeypatch, 1500, 1500)
|
||||
monkeypatch.setattr(
|
||||
"pwd.getpwuid", lambda uid: SimpleNamespace(pw_dir="/home/dev")
|
||||
)
|
||||
assert session_manager._host_identity_env() == {
|
||||
"STRIX_HOST_UID": "1500",
|
||||
"STRIX_HOST_GID": "1500",
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue