scripts/test-sandbox-user.py
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env python3
"""Exercise the real trusted UID/lock helper on Linux. No VM or daemon is created."""
import fcntl
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import time
import unittest
ROOT = Path(__file__).resolve().parents[1]
@unittest.skipUnless(sys.platform == "linux", "Linux prctl/setresuid/flock contract")
class SandboxUser(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.directory = tempfile.TemporaryDirectory(prefix="firecrab-sandbox-user-")
root = Path(cls.directory.name)
root.chmod(0o755)
driver = root / "driver.c"
driver.write_text('#include "user.h"\nint main(int argc, char **argv) { return firecrab_sandbox_user(argc, argv); }\n')
cls.binary = root / "sandbox-user"
subprocess.run([os.environ.get("CC", "cc"), "-std=c11", "-Wall", "-Wextra", "-Werror", "-I", str(ROOT / "packaging/guest-console"), str(ROOT / "packaging/guest-console/user.c"), str(driver), "-o", str(cls.binary)], check=True)
@classmethod
def tearDownClass(cls):
cls.directory.cleanup()
def root(self):
if os.geteuid() != 0:
self.skipTest("run with sudo to verify real UID dropping")
def run_user(self, *argv):
return subprocess.run([str(self.binary), "--reuid", "65533", "--regid", "65533", "--clear-groups", "--no-new-privs", *argv], capture_output=True, check=False, timeout=5)
def test_malformed_and_root_targets_are_rejected(self):
self.root()
for uid in ["0", "-1", "+1", "1x", "4294967295"]:
result = subprocess.run([str(self.binary), "--reuid", uid, "--regid", "65533", "--clear-groups", "--no-new-privs", "/bin/true"], capture_output=True, check=False)
self.assertEqual(result.returncode, 77)
def test_exact_identity_no_new_privileges_and_no_supplementary_groups(self):
self.root()
result = self.run_user(sys.executable, "-c", 'import json,os; print(json.dumps([os.getuid(),os.geteuid(),os.getgid(),os.getgroups()])); print(open("/proc/self/status").read().split("NoNewPrivs:")[1].splitlines()[0].strip())')
self.assertEqual(result.returncode, 0, result.stderr)
lines = result.stdout.decode().splitlines()
self.assertEqual(json.loads(lines[0]), [65533, 65533, 65533, []])
self.assertEqual(lines[1], "1")
def test_stdio_exit_and_argv_are_preserved(self):
self.root()
result = self.run_user("/bin/sh", "-c", 'printf "%s" "$1"; printf diagnostics >&2; exit 7', "sh", "$(echo escaped)'; literal")
self.assertEqual(result.returncode, 7)
self.assertEqual(result.stdout, b"$(echo escaped)'; literal")
self.assertEqual(result.stderr, b"diagnostics")
def test_unprivileged_caller_cannot_use_helper(self):
self.root()
def drop():
os.setgroups([])
os.setgid(65533)
os.setuid(65533)
result = subprocess.run([str(self.binary), "--sandbox-probe"], preexec_fn=drop, capture_output=True, check=False)
self.assertEqual(result.returncode, 77)
def test_lock_is_retained_by_the_parent_open_description_and_wait_is_bounded(self):
self.root()
path = Path(self.directory.name) / "owned.lock"
with path.open("w+") as owned:
result = subprocess.run([str(self.binary), "--sandbox-lock", str(owned.fileno()), "1"], pass_fds=(owned.fileno(),), check=False)
self.assertEqual(result.returncode, 0)
with path.open("r+") as contender:
start = time.monotonic()
result = subprocess.run([str(self.binary), "--sandbox-lock", str(contender.fileno()), "0"], pass_fds=(contender.fileno(),), check=False)
self.assertEqual(result.returncode, 81)
self.assertLess(time.monotonic() - start, 1)
with self.assertRaises(BlockingIOError):
fcntl.flock(contender, fcntl.LOCK_EX | fcntl.LOCK_NB)
with path.open("r+") as unlocked:
fcntl.flock(unlocked, fcntl.LOCK_EX | fcntl.LOCK_NB)
if __name__ == "__main__":
unittest.main()