Skip to content

Latest commit

 

History

History
65 lines (44 loc) · 5.61 KB

File metadata and controls

65 lines (44 loc) · 5.61 KB

PolicyWitness

Read the user guide for more detail.

PolicyWitness is a macOS harness for observing differences between sandbox_check's userland sandbox-prediction API and the kernel's actual enforcement. It does so by evaluating SBPL policy applied to a sandboxed worker plus a probe plan, exercising both the prediction and the kernel. Each run produces one JSON envelope describing both channels per probe step, with the policy bytes, the runner's entitlements, and unified-log deny evidence attached.

Measuring sandbox_check's prediction about a process against policy enforcement requires managing process lifecycles. sandbox_check answers for an existing PID, and sandbox application is one-way — a process gets exactly one sandbox. Evaluating a policy therefore means a fresh process per evaluation: compile and apply the policy to it once, aim both the prediction and the attempted operation at that PID while it lives, and carry the answer out through a channel the policy under test cannot sever.

Flow

Specimens -> Runs -> Steps -> Evidence

PolicyWitness operates on specimens: an SBPL policy plus a probe plan. The controller launches a fresh runner per specimen. The runner is an unsandboxed XPC host plus two short-lived children: pw-probe-runner, a sandboxed C worker that applies the specimen policy to itself and runs the probe plan and sb_api_validator --batch which queries sandbox_check for each probe against the worker's sandboxed PID. The host stays unsandboxed so the XPC reply path survives even under a strict (deny default) profile, joins both children's outputs into one JSON envelope, and replies.

After application, the worker waits for host release. The host closes validator collection before releasing the entire attempt batch. Eligible query_first records establish this ordering; they do not establish a shared state snapshot.

Each step records two evidence channels plus their comparison:

  • Attempt (steps[].attempt): in-band kernel response — rc, errno, mach kr — from actually performing the operation inside the sandboxed worker.
  • Prediction (steps[].sandbox_check): the userland sandbox_check verdict for the same operation + filter against the same PID, supplied by the validator.
  • Drift (steps[].drift): false for a supported allow/success agreement and null when the evidence leaves the comparison unavailable or merely directionally consistent. true is reserved for a difference from kernel enforcement with material alternative explanations excluded. The current runner establishes query order for eligible records but cannot establish state stability or runtime target identity, so it produces no true claims. Successful same-target unlink also makes agreement unavailable while its order against the query is unknown.

Unified-log evidence for kernel denies is attached out-of-band (best-effort).

Entitlements + SBPL

macOS sandboxing isn't just SBPL: a process's effective sandbox is its SBPL profile applied on top of the entitlements its binary was codesigned with. The same SBPL can yield different kernel behavior depending on which entitlements are granted, so a specimen has to describe both halves to be a faithful witness.

By default SBPL is applied to a process holding no entitlements. To observe a different combination, copy the bundled XPC service, sign it with your own entitlements plist, and install it via policy-witness runner install --kind byoxpc. The copied bundle inherits the runner's signed-caller check, so sign it with a Developer ID whose team matches the app (an ad-hoc/local runner must first have the caller-auth keys removed — see the guide). Specimens then select it via runner.id or runner.service. See the user guide (docs/PolicyWitness.md) for the install recipe.

What ships

This repo builds a single distributable app bundle:

  • dist/PolicyWitness.app
    • Contents/MacOS/policy-witness (Rust controller)
    • Contents/MacOS/pw-runner-client (Swift NSXPCConnection wrapper)
    • Contents/MacOS/sandbox-log-observer (Rust unified-log capture helper)
    • Contents/MacOS/sbpl-check (SBPL compile-check helper)
    • Contents/MacOS/sb_api_validator (diagnostic copy of the validator CLI)
    • Contents/XPCServices/PWRunner.xpc (Swift XPC host; one host + two short-lived children per specimen)
      • Contents/MacOS/pw-probe-runner (bundle-local C worker that applies the policy and runs probe attempts)
      • Contents/MacOS/sb_api_validator (bundle-local validator launched once per run for sandbox_check verdicts)
    • Contents/Resources/Evidence/* (generated manifests: hashes/entitlements, symbols.json)

Build the app bundle with ./build.sh (sign with IDENTITY=...; see docs/SIGNING.md).

How this is built

All of the code here was written by AI coding agents (Claude and GPT 5.x), including the tests. This project is a bet that a focus on testing and iteration over real use on top of some reasonable architectural choices will suffice for narrow, well-defined problem spaces.

Documentation