[FIR-112]: macOS structural confinement strategy decision: parity path vs ESF-native model#141
Conversation
| } | ||
|
|
||
| // Sensitive home path masking for claude-code profile. | ||
| if claude_profile && is_absolute_sandbox_path(&home) { |
There was a problem hiding this comment.
Are these gates necessary?
There was a problem hiding this comment.
Yes, both gates are intentional.
claude_profile keeps this masking scoped to the built-in claude-code profile, these deny rules block common home-secret paths like .ssh, .aws, .kube, .gnupg, and .config/gcloud, applying them to every macOS profile would be a behavior change for generic and any future profiles that may intentionally need different filesystem access, is_absolute_sandbox_path(&home) avoids generating malformed or overly broad SBPL rules when HOME is missing or relative, the generated rules are path-based, e.g. (deny file-read* (subpath "...")), so we only emit them when the home path is a macOS/SBPL absolute path.
The helper uses sandbox path semantics (/Users/...) rather than Path::is_absolute() because these profiles are tested on Windows CI too, where /Users/tester is not considered absolute by the host OS even though it is the correct path shape for the macOS sandbox profile.
|
@therandomsecurityguy @TommasoAlderigi some notes before merging this one. The proposed direction is:
The key docs are:
What is implemented in this PRRuntime-side:
Docs/testing:
What this PR does not implementThis PR does not implement the actual Apple Virtualization.framework runner. The VZ guest contract path is now present in
This PR also does not implement ESF. The current recommendation is that ESF remains a separate hardening/audit track unless we explicitly decide otherwise. Decisions I’d like reviewers to confirmBefore merging, I’d like feedback on these points:
Known follow-up workIf this PR is accepted, the next implementation work should be split roughly as:
Please review especially the strategy/claim boundaries and whether anything is missing before we merge this as the macOS confinement decision + VZ contract foundation. Follow-up PRs should be created after merging. |
6e1ab88 to
9b17ff3
Compare
9b17ff3 to
726141a
Compare
…trategy-decision-parity-path
macOS sandbox-exec was failing because we were handing it a bad sandbox profile. the structural experiment for the VZ backend uses TrustedBSD sandbox rules: deny network-outbound, then allow loopback so the agent can still reach the host proxy bridge and DNS refusal stub. Apple documents sandbox failures in this area as network-outbound violations in the App Sandbox diagnostics page https://developer.apple.com/documentation/security/discovering-and-diagnosing-app-sandbox-violations tested with: cargo test -p firma-run macos_vz
cherry-picking the VZ guest work from #141 the split is useful to isolated the guest work development to match Apples Virtualization.framework boundaries https://developer.apple.com/documentation/virtualization here we specifically use FIRMA_RUN_VZ_GUEST to select the macOS vz mode. before launch, the backend validates the configured runner and guest artifacts, rejects missing or relative paths, checks that the runner is executable on Unix and only then emits a macos_vz_guest proof. the contract carries the execution envelope the runner must enforce: - sandbox id - runtime dir - runner path - guest image paths - command - args - cwd - environment - mounts - identity mode - seccomp artifact path - proxy URL - DNS stub address - attribution headers - required invariants: - sidecar-only egress - confined DNS - fail-closed startup/runtime - direct-bypass resistance - stdio/signal/exit preservation **since there is still no Apple Virtualization.framework runner here**, it servers us as a bedside contract for the future runner. routing also learns that macOS structural modes may need a host DNS refusal stub even when they are not using the Linux namespace path. the sandbox-exec uses that stub on loopback. the VZ guest contract exposes the same endpoint so the future runner can make guest DNS deterministic instead of letting the agent fall back to ambient resolution. *Note that the ESF remains out of this change.* Tested with: cargo test -p firma-run macos_vz
Thinking Path
What Changed
FIRMA_RUN_VZ_GUEST=1mode for the macOSvzbackend.FIRMA_RUN_VZ_GUEST_RUNNERFIRMA_RUN_VZ_GUEST_KERNELFIRMA_RUN_VZ_GUEST_INITRDFIRMA_RUN_VZ_GUEST_ROOTFSmacos_vz_guestenforcement proof behavior withstructural=truewhen VZ guest mode is selected.vz-guest-launch.jsoncontract containing:--launch-contract <path>.macos_vz_guestserializationfirma runguidellms.txtVerification
cargo test -p firma-runResult:
Result:
Also checked that internal card IDs were not present in the changed docs/runtime scope:
rg -n "FIR-112|FIR_112|FIR 112|FIR-72" docs-site examples crates/firma-run/srcResult:
make checkwas not run locally for this branch; verification was scoped to the changed crate and docs build to avoid unnecessary full-workspace runtime.Security Considerations
normalizer → Stage 1 → Stage 2).firma runand the operator-provided VZ runner.firma runowns validation, contract generation, proof metadata, and process supervision.Risks
macos_vz_guestreports structural mode when guest mode is selected, but the actual confinement guarantee still depends on the configured runner and guest image enforcing the contract correctly.Model Used
Checklist
make checkpasses locally (fmt + toml-fmt + lint + test + build + audit + deny).unwrap(),.expect(),panic!(), orunsafeintroduced outside of test codedocs/anddocs-site/