Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
750 changes: 375 additions & 375 deletions .github/copilot-instructions.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .github/workflows/Versioning.Checks.Job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
- name: Check schema is in sync with the Rust wire model (codegen)
run: node scripts/versioning/check-schema-codegen.js

- name: Check PSEC generated contract (provenance + drift)
run: node scripts/versioning/check-psec-codegen.js

- name: Check SDK wire types are in sync with the Rust wire model (codegen)
run: node scripts/versioning/check-sdk-types-codegen.js

Expand Down
30 changes: 27 additions & 3 deletions docs/learning-mode/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,33 @@ surfacing the resulting denials to the caller. Its `mode` selects how each
ungranted access is handled while it is recorded:

> **Host requirement.** `captureDenials` requires a feature-enabled Windows
> build exposing the BaseContainer security-environment and Learning Mode APIs.
> It is not supported by the AppContainer fallback tiers; unsupported hosts
> return `backend_unavailable`.
> build exposing the complete official V2 API set:
> `StartLearningModeTrace`, `StopLearningModeTrace`,
> `CloseLearningModeTrace`, `CreateProcessSecurityEnvironment`,
> `QueryProcessSecurityEnvironmentSupport`, and
> `CloseProcessSecurityEnvironment`. It is not supported by the AppContainer
> fallback tiers; unsupported hosts return `backend_unavailable`.
>
> Internal validation confirmed that build `26657.1002` exposes only the
> incompatible earlier contract and is rejected, while build `26663.1000`
> exposes the complete V2 contract. These are validation points, not a public
> Windows release-floor commitment; callers should rely on the runtime probe.
>
Comment thread
richiemsft marked this conversation as resolved.
> `captureDenials` cannot be combined with `processContainer.leastPrivilege`;
> the Windows process security-environment API used for capture does not expose
> an LPAC token option, so MXC rejects that combination rather than silently
> weakening the requested policy.
>
> `captureDenials` also cannot currently be combined with `network.proxy`.
> The V2 process security-environment proxy contract requires a separate proxy
> AppContainer peer identity; MXC rejects the combination until that peer is
> provisioned by the capture launch path.
>
> `filesystem.deniedPaths` requires
> `QueryProcessSecurityEnvironmentSupport` to advertise
> `PSE_SUPPORT_FS_DENY`. When the bit is absent, capture fails as
> `backend_unavailable`; it cannot fall back to AppContainer or host-DACL
> enforcement.

- `mode: "block"` (default) maps onto `learningModeLogging`
(deny-and-record) β€” the app / user-configurable flow.
Expand Down
29 changes: 29 additions & 0 deletions docs/process-container/os-version-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,35 @@ available bounds what policy can be enforced.
- **T3 (AppContainer + DACL)** is the universal fallback and enforces
filesystem policy via host path ACEs on every release.

## Schema 0.8 process security environment

BaseContainer requests using schema versions through 0.7 use the SBOX contract
and the T1/T2/T3 fallback chain above. Schema 0.8 and later use the PSEC
process-security-environment contract, even when `captureDenials` is absent,
and do not fall back to SBOX or AppContainer. The host must expose:

- `CreateProcessSecurityEnvironment`
- `QueryProcessSecurityEnvironmentSupport`
- `CloseProcessSecurityEnvironment`

When `processContainer.captureDenials` is present, the host must additionally
expose the complete official V2 Learning Mode export set:

- `StartLearningModeTrace`
- `StopLearningModeTrace`
- `CloseLearningModeTrace`

Unsupported or earlier-contract hosts fail as `backend_unavailable`. Internal
validation confirmed the earlier contract on build `26657.1002` is rejected
and the full V2 contract on build `26663.1000` is accepted. These builds are
validation points, not a public release-floor commitment; runtime export
probing is the source of truth.

The PSEC contract cannot represent `processContainer.leastPrivilege`, and MXC
does not yet supply the peer identity required by its proxy contract, so schema
0.8+ rejects both options. `filesystem.deniedPaths` is accepted only when
`QueryProcessSecurityEnvironmentSupport` advertises `PSE_SUPPORT_FS_DENY`.

## Filesystem policy

| Aspect | 23H2 | 24H2 | 25H2 | 25H2+ |
Expand Down
2 changes: 2 additions & 0 deletions docs/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ production configs and the dev schema when working on experimental features:
} // dir must already exist; a unique per-run id is stamped
// into the stem (denials.<run-id>.json) and the actual
// path printed on stderr. Omit outputPath for a managed temp file.
// captureDenials cannot be combined with leastPrivilege.
// captureDenials cannot currently be combined with network.proxy.
},

"lxc": { // LXC-specific
Expand Down
93 changes: 93 additions & 0 deletions external/windows-sdk/ProcessSecurityEnvironment.fbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//
// FlatBuffers schema for the BaseContainer sandbox specification used in the
// CreateProcessSecurityEnvironment Windows API.
//
// This is the CPSE wire format. The legacy CPIS path continues to use
// SandboxSpec.fbs and its "SBOX" file identifier.
//
// ---- FlatBuffers Schema Evolution Rules ----
//
// Compatible (non-breaking) changes:
// - Add new fields to the END of a table (they get the next vtable slot).
// - Add new tables, structs, enums, or union members.
// - Deprecate a field with (deprecated) - the slot is preserved, readers skip it.
// - Rename a field or table (wire format uses slot indices, not names).
//
// BREAKING changes (will corrupt existing buffers):
// - Remove or reorder fields in a table or struct.
// - Change a field's type (e.g. uint32 -> int32, or scalar -> string).
// - Change a field's default value.
// - Add/remove/reorder values in an enum that is already serialized.
// - Change the file_identifier or root_type.
// - Change a field from scalar to non-scalar (or vice versa).
//
// To machine-check for breaking changes, keep a copy of the last shipped schema
// (e.g. ProcessSecurityEnvironment.previous.fbs) and run:
//
// flatc --conform ProcessSecurityEnvironment.previous.fbs ProcessSecurityEnvironment.fbs
//
// --conform verifies that every field/enum/table in the old schema still exists
// at the same vtable slot, type, and default in the new schema.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This schema is copied from the official OS PSEC schema, including the FlatBuffer evolution guidance, so I retained it to keep the checked-in contract aligned with its source. If you intended a different specific section on line 32 to be removed, could you clarify which portion?


namespace ProcessSecurityEnvironmentLayout;

struct SchemaVersion {
major:uint16;
minor:uint16;
}

table ProcessSecurityEnvironment {
version:SchemaVersion (required);
capabilities:string;
disallow_win32k_system_calls:bool = false;
ui_restrictions:uint64 = 0;
fs_read_write:[string];
fs_read_only:[string];
fs_deny:[string];
network_policy:NetworkPolicy;
}

table ProxyInfo {
url:string;
}

enum FilterAction : byte { deny, allow }
enum IpProtocol : byte { any, tcp, udp, icmpv4, icmpv6 }

table IpSubnet {
address:string;
prefix_length:ubyte = 0;
}

table DestinationRule {
subnet:IpSubnet;
except:[IpSubnet];
}

table PortRule {
protocol:IpProtocol = any;
port:uint16 = 0;
end_port:uint16 = 0;
}

table EndpointRule {
destinations:[DestinationRule];
ports:[PortRule];
}

table EndpointPolicy {
default_action:FilterAction = deny;
allow:[EndpointRule];
deny:[EndpointRule];
}

table NetworkPolicy {
proxy:ProxyInfo;
egress:EndpointPolicy;
allowed_appcontainer_peer:string;
}

root_type ProcessSecurityEnvironment;
file_identifier "PSEC";
52 changes: 52 additions & 0 deletions external/windows-sdk/ProcessSecurityEnvironment.provenance.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Provenance for the vendored ProcessSecurityEnvironment FlatBuffers schema.
#
# This file is the single source of truth for the pinned regeneration toolchain
# and the authoritative hash of the vendored `ProcessSecurityEnvironment.fbs`.
# It is consumed by:
# * src/core/generated/process_security_environment_specification/regenerate.ps1
# (validates the schema hash + pins the exact flatc version before generating)
# * scripts/versioning/check-psec-codegen.js
# (CI drift gate β€” verifies the committed schema + generated crate)
#
# Update this file whenever the vendored schema is refreshed from the OS source,
# then regenerate the bindings (see the crate README).

[source]
# The schema originates from the internal Microsoft Windows OS repository and is
# not publicly redistributable. Only the schema text (not the OS tree) is vendored.
repository = "Windows OS (internal Azure DevOps)"
# The PSEC schema is a Windows OS containment contract; there is no public OS
# revision to cite. Instead of guessing a source path/revision, we record the
# Windows build the vendored schema contract was validated against.
validated_windows_build = "10.0.26663.1000"
# Azure DevOps PR 16307987 is the RELATED Learning Mode trace ABI change β€” it is
# NOT the pull request that introduced or last modified this PSEC schema.
# Recorded for traceability only; do not represent it as the schema's origin.
related_trace_abi_pull_request = 16307987

[schema]
# SHA-256 of external/windows-sdk/ProcessSecurityEnvironment.fbs, computed over
# the LF-normalized (git-blob) content so it is checkout-independent regardless
# of autocrlf. Verified by regenerate.ps1 and the CI drift gate.
sha256 = "7d14b01850a735329da00cde4d4d2e32e463f49026a39708be9059fd64e764d3"

[tool]
# Exact flatc version used to generate the committed bindings. Regeneration
# pins this exact version (not a floor) so output is byte-reproducible.
# 25.12.19 is the first release carrying flatbuffers PR #8709, which stops flatc
# emitting elided lifetimes that trip the `mismatched_lifetime_syntaxes` lint
# (added in Rust 1.89).
flatc_version = "25.12.19"
flatc_release = "https://github.com/google/flatbuffers/releases/tag/v25.12.19"
generated_date = "2026-08-03"

# Exact GitHub release assets for flatc 25.12.19. The CI drift gate downloads the
# platform asset, verifies its SHA-256 against these values, unzips it, and
# regenerates into a temp directory to diff against the committed bindings.
[tool.flatc_assets.linux]
name = "Linux.flatc.binary.clang++-18.zip"
sha256 = "50c1915deeeb714f2a05c8ec795bd1af898d251a62e2774067703b29188efc90"

[tool.flatc_assets.windows]
name = "Windows.flatc.binary.zip"
sha256 = "fff9445c9db907227bc64b54cc98743084c4949282aa4e576cff6a955724ddc8"
4 changes: 2 additions & 2 deletions schemas/dev/mxc-config.schema.0.8.0-dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
},
"CaptureDenials": {
"additionalProperties": false,
"description": "Windows denial-capture settings. The presence of the `captureDenials` object enables capture; all fields are optional.",
"description": "Windows denial-capture settings. The presence of the `captureDenials` object enables capture; all fields are optional. Capture is incompatible with `processContainer.leastPrivilege` and `network.proxy`. Explicit `filesystem.deniedPaths` requires the host's V2 process security-environment support query to advertise native deny enforcement.",
"properties": {
"mode": {
"anyOf": [
Expand Down Expand Up @@ -699,7 +699,7 @@
"type": "null"
}
],
"description": "Windows denial capture. When present, the runner records the sandboxed process's access attempts to a learning-mode ETL trace for later inspection. Requires a host that exposes the learning-mode OS API."
"description": "Windows denial capture. When present, the runner records the sandboxed process's access attempts to a learning-mode ETL trace for later inspection. Requires a host that exposes the complete official V2 Learning Mode and process security-environment API set. Cannot be combined with `leastPrivilege` or `network.proxy`; `filesystem.deniedPaths` additionally requires the V2 deny-support capability."
},
"learningMode": {
"description": "AppContainer learning mode (deny-and-record): failed access checks are logged for diagnostics while the accesses stay denied; containment is unchanged. Distinct from the allow-all `permissiveLearningMode` capability, which is injected internally by the `--audit` CLI flag or dedicated denial-capture configuration.",
Expand Down
Loading
Loading