-
Notifications
You must be signed in to change notification settings - Fork 56
Document the trust model and the outer-clamp design #728
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -467,6 +467,72 @@ The MXC β OS contract therefore reports: which feature failed, whether it was | |
| version mismatch or a runtime/capability unavailability (e.g. Hyper-V off), and | ||
| what the user should do (upgrade OS, enable feature, change the config). | ||
|
|
||
| ## Trust model and the outer clamp | ||
|
|
||
| MXC's authorization model and the (optional) unbypassable upper bound on what a | ||
| config can relax. | ||
|
|
||
| ### Authorization model: one principal, secure-and-loud defaults | ||
|
|
||
| For the agent/SDK consumers MXC is built for, the same principal authors **both** | ||
| the config JSON and the command line. There is no second, more-privileged channel | ||
| to grant capabilities from, so MXC does **not** require a mandatory second-channel | ||
| authorization for boundary-relaxing fields. | ||
|
|
||
| > **Precondition.** This holds only where the invoker and the config author are | ||
| > the same trust principal. MXC does not enforce that. An embedder that runs | ||
| > `wxc-exec` with a config derived from lower-trust input (an end user, a remote | ||
| > service, model output) has two principals, and the model above does not apply | ||
| > to it β such an embedder must validate or constrain the config itself before | ||
| > passing it in. See [the outer clamp](#the-outer-clamp-optional-platform-asymmetric) | ||
| > for the mechanism that would enforce a ceiling independently of the config. | ||
|
|
||
| Given that precondition, safety rests on three in-repo mechanisms, all | ||
| implemented: | ||
|
|
||
| 1. **Secure defaults.** Every boundary defaults closed: `network.defaultPolicy` | ||
| is `block`, `ui.disable` is `true`, clipboard/injection off, etc. (see | ||
| [the schema reference](schema.md) for each field's default). A minimal config | ||
| is a tight sandbox. | ||
| 2. **Explicit + loud relaxation.** Fields that open a network, UI, capability, | ||
| or Seatbelt boundary beyond their secure default are logged at parse time as | ||
| `SECURITY: boundary relaxed: β¦`, so those relaxations are never silent β they | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 states relaxations "are never silent," but |
||
| are auditable in the diagnostic log. Filesystem path grants and the Seatbelt | ||
| pty baseline are deliberately out of this audit's scope, being the request's | ||
| primary purpose rather than a relaxation. | ||
| 3. **Catastrophic capabilities are removed from shipped builds.** A capability | ||
| that would defeat the sandbox wholesale rather than merely widen it β | ||
| currently `seatbelt.profileOverride`, which replaces the entire generated | ||
| deny-default profile β is **rejected by release/shipped binaries** (the parser | ||
| returns a config error, and the builder branch is compiled out), so it cannot | ||
| be honored in production at all. | ||
|
|
||
| ### The outer clamp (optional, platform-asymmetric) | ||
|
|
||
| The mechanisms above bound what the *config* requests. An **outer clamp** is a | ||
| separate, optional upper bound enforced *below* the config β an unbypassable | ||
| ceiling a host operator can impose so that even a fully-relaxed config cannot | ||
| exceed it. Whether such a clamp can be made truly unbypassable is | ||
| **platform-asymmetric**, because it depends on an OS primitive MXC does not own: | ||
|
|
||
| | Platform | Clamp mechanism | Unbypassable? | Status | | ||
| |---|---|---|---| | ||
| | Windows β BaseContainer tier | OS sandbox broker enforces the policy inside `Experimental_CreateProcessInSandbox` | Yes β the broker is the kernel-side authority | OS-infra (outside this repo) | | ||
| | Windows β AppContainer fallback tiers (BFS / DACL) | AppContainer + `bfscfg.exe` BFS or host-side DACL ACEs; used when the BaseContainer API is absent | Partial β enforcement is partly host-side, not a single kernel broker | Existing backend behavior, but **not present in a stock build**: BFS requires the non-default `tier2_bfs` feature plus `bfscfg.exe` on the host, and the DACL path requires explicit config opt-in | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The AppContainer-fallback row says the DACL path "requires explicit config opt-in," but it is enabled by default: |
||
| | Linux (LXC) | Host LSM (AppArmor / SELinux) profile + root-owned policy file | Yes, with a host LSM; otherwise advisory | OS-infra / host config | | ||
| | Linux (Bubblewrap) | LSM, or compile-time capability removal | Partial β bwrap is unprivileged by design | OS-infra / build | | ||
| | macOS (Seatbelt) | Root-owned policy file + codesign / SIP | Yes, with SIP + signed binary; otherwise advisory | OS-infra (outside this repo) | | ||
| | All platforms | Root/admin-owned **clamp-policy file** read at the trust boundary, capping the boundary relaxations that the parse-time audit logs | No β a trust-boundary gate, bypassable by a local admin, not a kernel guarantee | Deferred (in-repo candidate) | | ||
|
|
||
| The truly unbypassable rows (broker, LSM, SIP) live in OS infrastructure outside | ||
| this repository and are intentionally **out of scope here**. The one piece that | ||
| *could* live in-repo β a root-owned clamp-policy file the parser enforces as a | ||
| ceiling on relaxations β is a meaningful additional gate but is **not a kernel | ||
| guarantee** (a local admin can edit the file), so it is tracked as a follow-up | ||
| rather than shipped as if it were unbypassable. Catastrophic, un-clampable | ||
| capabilities are handled instead by compile-time removal (above), which needs no | ||
| OS primitive. | ||
|
|
||
| ## Experimental Features β Clarifications | ||
|
|
||
| **Shipping model:** The shipped schema contains **only** non-experimental | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The section's opening line advertises "the (optional) unbypassable upper bound on what a config can relax," but the body correctly establishes that no in-repo unbypassable clamp ships: every "Yes" row is OS infrastructure out of scope, and the only in-repo row is "No β bypassable by a local admin / Deferred." The lead sentence promises something the section then retracts. Suggest tightening to e.g. "β¦and the platform-dependent external bounds that can constrain it."