Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions .github/workflows/Build.Linux.Job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@ jobs:

# Exercises the real binary against the real dependencies: launches the
# slirp4netns supervisor, joins its user namespace, and asserts the
# sandbox lands in a private network namespace. Needs unix-test-proxy
# (builtinTestServer) alongside lxc-exec, which the two build steps
# above place in the same target directory.
# sandbox lands in a private network namespace. The test script starts
# unix-test-proxy independently alongside lxc-exec; the two build steps
# above place them in the same target directory.
- name: Test Bubblewrap proxy networking (end-to-end)
working-directory: ${{ github.workspace }}
env:
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ Repository contributors can browse the [development documentation](docs/developm
| [tests/scripts/README.md](tests/scripts/README.md) | Local and CI backend test suites |
| [Host preparation](docs/backends/process-container/host-prep.md) | Windows host preparation (`wxc-host-prep.exe`) |
| [Diagnostics](docs/development/guides/diagnostics.md) | Diagnostic logging and ETW |
| [Containment configuration 0.7.0](docs/containment-configuration/0.7.0/policy.md) | Containment configuration 0.7.0 specification |
| [Adding ProcessContainer OS features](docs/development/guides/process-container-adding-os-features.md) | Windows AppContainer / BaseContainer developer guide |
| [docs/backends/lxc/lxc-backend.md](docs/backends/lxc/lxc-backend.md) | LXC backend (Linux) |
| [docs/backends/bwrap/bubblewrap-backend.md](docs/backends/bwrap/bubblewrap-backend.md) | Bubblewrap backend (Linux) |
Expand Down
8 changes: 3 additions & 5 deletions build-mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ echo ""
echo "=== Building mxc-exec-mac ($BUILD_TYPE) ==="
cd "$SRC_DIR"

# mxc-exec-mac is the seatbelt executor. unix-test-proxy is the bundled,
# testing-only HTTP proxy that backs `network.proxy.builtinTestServer`; it is
# spawned as a sibling of mxc-exec-mac by the proxy coordinator.
# mxc-exec-mac is the Seatbelt executor. Keep unix-test-proxy as an
# externally managed test endpoint for integration probes.
CARGO_FLAGS=("-p" "mxc_darwin" "-p" "unix_test_proxy" "-p" "mxc_ffi")
if [ "$BUILD_TYPE" = "release" ]; then
CARGO_FLAGS+=("--release")
Expand Down Expand Up @@ -141,8 +140,7 @@ copy_binary_for_target() {
echo "Warning: $ffi_src not found, skipping copy"
fi

# unix-test-proxy backs network.proxy.builtinTestServer (testing only).
# It must sit next to mxc-exec-mac so the proxy coordinator can resolve it.
# Retain the test proxy binary for callers that start it independently.
local proxy_src="$SRC_DIR/target/$triple/$BUILD_TYPE/unix-test-proxy"
if [ -f "$proxy_src" ]; then
cp "$proxy_src" "$bin_dir/unix-test-proxy"
Expand Down
8 changes: 4 additions & 4 deletions docs/api-reference/dotnet/v1/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ public enum NetworkAction

## `Microsoft.Mxc.Sdk.V1.NetworkEgressPolicy`

Schema-0.8 outbound network policy.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thank you for this!

Supported directional outbound network policy.

```csharp
public sealed class NetworkEgressPolicy
Expand All @@ -801,7 +801,7 @@ public sealed class NetworkEgressPolicy

## `Microsoft.Mxc.Sdk.V1.NetworkIngressPolicy`

Schema-0.8 inbound and host-loopback network policy.
Supported directional inbound and host-loopback network policy.

```csharp
public sealed class NetworkIngressPolicy
Expand Down Expand Up @@ -893,7 +893,7 @@ public sealed class NetworkRulePolicy

## `Microsoft.Mxc.Sdk.V1.NetworkRuntimeConfig`

Schema-0.8 runtime network values.
Supported runtime network values.

```csharp
public sealed class NetworkRuntimeConfig
Expand Down Expand Up @@ -1209,7 +1209,7 @@ Schema versions supported by this SDK release.
```csharp
public static class SchemaVersions
{
public const string Minimum = "0.6.0-alpha";
public const string Minimum = "0.9.0-alpha";
public const string MaximumSupported = "1.1.0-alpha";
public const string LatestStable = "1.0.0";
}
Expand Down
16 changes: 8 additions & 8 deletions docs/backends/bwrap/bubblewrap-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ requiring root privileges or a container runtime.
> Versions before `0.9.0-alpha` are rejected; changing only the version of an
> old config does not migrate its policy. Legacy `defaultPolicy`,
> `enforcementMode`, host lists, `allowLocalNetwork`, and `network.proxy`
> are not accepted. See [schema migration](../../schema.md).
> are rejected by supported exact contracts. Typed Rust requests no longer
> contain these fields. See [schema migration](../../schema.md).
> Bubblewrap still rejects enforceable-looking requests it cannot honor
> (such as `ingress.default: "allow"` or direct egress rules combined with a
> runtime proxy) before provisioning. An omitted `network` section takes the
> directional deny defaults.

## Prerequisites

Expand Down Expand Up @@ -220,11 +225,6 @@ block's value, while bash (RHEL) fabricates a shorter `/usr/local/bin:/usr/bin`
plus `TERM=dumb`. So neither reads back as empty from inside the workload,
whatever MXC passed.

> **Historical (retired pre-v0.9 contracts):** the child received only
> `process.env`, with no default `PATH`. Those contracts are no longer
> registered: a request declaring one fails as an unsupported version before
> `inheritDefaultEnv` or any other process field is evaluated.

### Filesystem Policy

| Field | bwrap Mapping | Description |
Expand Down Expand Up @@ -382,8 +382,8 @@ Be honest about what this buys. It is **not** new protection: nothing outside
the sandbox can reach in already, because the runner configures no port
forwarding into the namespace, so there is no path for an inbound packet to
arrive on. The chain is defense in depth against a future change that adds
one, and the mechanism the GA networking spec expects a backend to apply
`ingress.default` through. The terminal `DROP` is deliberately independent of
one, and a defense-in-depth implementation of `ingress.default`. The terminal
`DROP` is deliberately independent of
`egress.default`, which governs outbound traffic only β€” an open outbound posture
must not open inbound as a side effect.

Expand Down
28 changes: 18 additions & 10 deletions docs/backends/lxc/lxc-backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

The LXC backend provides Linux container isolation using [LXC (Linux Containers)](https://linuxcontainers.org/lxc/).

For exact `0.9.0-alpha`, networking is directional-only: use `network.egress`
and `network.ingress`. LXC rejects `runtimeConfig.networkProxy`, so a v0.9 LXC
request has no proxy surface at all β€” see [Proxy](#proxy) below.
For every registered contract from `0.9.0-alpha` onward, networking is
directional-only: use `network.egress` and `network.ingress`. LXC rejects
`runtimeConfig.networkProxy`, so a supported LXC request has no proxy surface
at all β€” see [Proxy](#proxy) below.
Legacy host lists and enforcement-mode fields in older examples are not
accepted. Do not relabel an old request as v0.9 without migrating its policy.
See [the schema migration reference](../../schema.md).
Expand Down Expand Up @@ -143,9 +144,6 @@ in `process.env` replaces it.
> configuration, not just project input. Pass `"HOME=…"` to point elsewhere
> when the workspace is untrusted.

Below 0.9 only `process.env` is passed through and `inheritDefaultEnv` is
rejected.

Shells like bash also have a fallback `PATH`, so a truly empty environment is
not reachable through `process.env`.

Expand Down Expand Up @@ -173,9 +171,15 @@ The legacy `network.proxy` fields also have no supported exact contract.
Choose a backend that supports a loopback proxy if the workload needs one;
relabeling a retired LXC proxy request as v0.9 cannot make its policy enforceable.

The retired host-list, enforcement-mode, local-network, and `network.proxy`
fields are no longer representable in typed Rust requests. LXC still rejects
the supported `runtimeConfig.networkProxy` field before creating a container.
Omitting `network.egress` or `network.ingress` means default deny for that
direction; retired fields never supply a fallback.

### No network at all

A request that permits nothing and names no proxy keeps its own loopback and reaches nothing else.
A request that permits nothing keeps its own loopback and reaches nothing else.

## Usage

Expand Down Expand Up @@ -247,7 +251,11 @@ LXC reads a run's network section only when the container starts. Omit
`containerId` for a generated name. The claim is released when the handle drops.

**Teardown is owed on every terminal path,** including a drop without `wait`:
the proxy pin and the network chains come down, and the container is released.
the network chains come down, and the container is released. A reused container
also has any stale proxy hosts-file pin from an earlier run cleared before its
new workload launches. MXC checks for marked lines inside the running
container using `lxc-attach` and removes them if present. A failed check
refuses to run the workload.
A teardown failure is reported through `Sandbox::warnings`, which a bare drop
leaves no handle to read.

Expand Down Expand Up @@ -336,8 +344,8 @@ The zone query should answer the zone you assigned.
and anything it starts run unfiltered in both directions for that interval. The
requested command is attached afterwards. A connection opened during that window
keeps working once the rules land, because the chains accept established flows.
- **A filtered container cannot renew a DHCP lease.** The chains permit loopback,
established flows, and DNS, with no carve-out for DHCP. A container that
- **A filtered container cannot renew a DHCP lease.** The chains permit loopback
and established flows, with no implicit carve-out for DHCP or DNS. A container that
outlives its lease loses its address; one that finishes within the lease period
is unaffected.
- **A container that needs a network waits for an IPv4 address.** A dual-stack
Expand Down
71 changes: 8 additions & 63 deletions docs/backends/nanvix/nanvix.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,70 +181,15 @@ including egress allow with omitted ingress defaults.
Disabled networking prevents guest socket creation (`OSError: [Errno 134]`).
Unrestricted networking includes host-backed bind/listen capabilities;
NanVix cannot independently enforce ingress or host-loopback restrictions.
Directional egress rules are explicitly rejected because the legacy IPv4
filter does not implement their full semantics, including default-deny DNS.
Directional egress rules are explicitly rejected rather than translated to
the guest's IPv4 host filter, which cannot implement their full semantics,
including default-deny DNS.
Runtime proxy configuration is also unsupported.

### Legacy per-host filter implementation (compatibility/reference only)

The following describes the retained legacy runtime filter, not accepted v1.1
JSON vocabulary. The exact cutover does not silently translate directional
rules into this weaker contract.

Legacy `defaultPolicy` and host-list interactions follow the
[backend-agnostic network policy semantics](../../schema.md#legacy-network-host-list-semantics).
Invalid legacy combinations are rejected by shared policy validation:
`blockedHosts` requires an `allowedHosts` exception set under a block default,
and `allowedHosts` cannot be used under an allow default.

NanVix forwards the validated host list to the guest's host-side socket proxy,
which enforces egress at `connect()`. The guest filter is **allow-XOR-block**,
so NanVix rejects requests that supply both lists instead of dropping either
one.

Entries may be IPv4 literals (`93.184.216.34`), IPv4 CIDR blocks
(`10.0.0.0/8`), or hostnames. Hostnames are resolved to their IPv4 (A-record)
addresses at preflight; IPv6 (AAAA) results are dropped because the guest filter
is IPv4-only. Resolution failures are handled per direction so neither list ever
fails open:

- **allowlist** (deny-by-default): each dropped entry is logged as a warning and
the run continues, since dropping an entry only *narrows* access. If the list
resolves to **no** IPv4 address at all, the run is rejected at preflight rather
than silently allowing all traffic.
- **blocklist** (allow-by-default): **any** entry that resolves to no IPv4
address rejects the run at preflight. Silently dropping a blocked host would
let traffic the policy explicitly blocks flow freely, and the static preflight
filter cannot enforce a name that does not resolve β€” so the blocklist
fails closed.

**DNS:** in allowlist mode the guest daemon automatically exempts the DNS port
(53), so name resolution works without adding the resolver to `allowedHosts`.

Network proxies (`network.proxy`) are not supported and are rejected at
preflight.

```jsonc
{
"containment": "microvm",
"process": { "commandLine": "import urllib.request; ..." },
// Historical legacy shape, not accepted by the exact v1.1 contract:
"network": { "defaultPolicy": "allow" }
}
```

```jsonc
{
"containment": "microvm",
"process": { "commandLine": "import urllib.request; ..." },
// Historical legacy shape, not accepted by the exact v1.1 contract:
"network": { "allowedHosts": ["example.com", "10.0.0.0/8"] }
}
```

## Not Supported

| Workload | Error |
| ------------------------------- | ----------------------------------- |
| Both `allowedHosts` + `blockedHosts` | Rejected at preflight (mutually exclusive) |
| File writing outside `/mnt/rw/` | `OSError: Read-only file system` |
| Workload | Error |
| -------------------------------------------- | -------------------------------- |
| Mixed directional networking or egress rules | Rejected before VM creation |
| Runtime proxy | Rejected before VM creation |
| File writing outside `/mnt/rw/` | `OSError: Read-only file system` |
8 changes: 4 additions & 4 deletions docs/backends/process-container/examples/0.8.0-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

> **Audience:** MXC consumers and developers

> Historical design reference: schema 0.8 is retired. For supported requests,
> Schema 0.8 is retired. For supported requests,
> use [current ProcessContainer networking guidance](../networking.md).

See the shared [0.7-to-0.8 network schema comparison](../../../containment-configuration/0.8.0/networking/schema-updates.md)
for egress, ingress, and proxy endpoint changes. This page covers the
ProcessContainer-specific proxy peer.
For the supported egress, ingress, and proxy endpoint fields, see
[directional networking](../../../schema.md#directional-networking-supported-contracts).
The example below covers the ProcessContainer-specific proxy peer.

## Contained proxy

Expand Down
18 changes: 11 additions & 7 deletions docs/backends/process-container/networking.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ Supported exact contracts from `0.9.0-alpha` use the shared `network.egress`
and `network.ingress` policy plus `runtimeConfig.networkProxy` and
`processContainer.network.allowedProxyPeer` configuration.

Implementation companion to the parent
[MXC Network Configuration, GA design](../../containment-configuration/0.8.0/networking/networking.md)
doc. The parent owns the shared policy schema, connectivity models, and GA goal.
This doc covers only how the Windows ProcessContainer backend enforces them.
For the shared policy shape and defaults, see
[directional networking](../../schema.md#directional-networking-supported-contracts).
This guide covers how the Windows ProcessContainer backend enforces them.

## 1. What this backend targets at GA

Expand Down Expand Up @@ -206,7 +205,7 @@ middle rows provide different protections and are not ordered relative to each o

For identity-scoped proxies, the scoped peer rule and `privateNetworkClientServer` do not bypass Windows
Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall
declaration shown in the [historical schema 0.8 manifest example](examples/0.8.0-schema.md); its application entry uses
declaration shown in the [proxy package manifest example](examples/0.8.0-schema.md); its application entry uses
`uap10:RuntimeBehavior="packagedClassicApp"` with `uap10:TrustLevel="appContainer"`. An unpackaged AppContainer proxy
requires its installer or administrator to own an equivalent rule scoped to the AppContainer profile SID, proxy
executable, and configured port.
Expand Down Expand Up @@ -254,7 +253,9 @@ Do not infer otherwise from the schema:
- Per-source or per-port inbound rules. GA ingress is limited to the
`default` and `hostLoopback` allow/deny toggles.

See the parent doc on the last 4.
The egress schema selects numeric destinations, protocols, and ports, not
durable DNS names or application payloads. Its ingress schema has only
`default` and `hostLoopback` toggles; it cannot select inbound peers or ports.

## 2. Supported-contract selection and downlevel behavior

Expand All @@ -280,7 +281,10 @@ proxy peer identity, and host-loopback allow fail with a typed unsupported-polic
## 3. WFP enforcement

PSEC applies outbound WFP filters in the OS's elevated context and owns their lifetime. AppContainer fallback does not
install directional WFP filters.
install directional WFP filters. It uses capabilities for supported direction
defaults and keeps the external runtime proxy setup. Its network audit records retain the firewall fields with
`firewall_rules_created` and `firewall_rules_removed` at `0`, `firewall_applied` at `false`, and
`firewall_removal_ok` at `true`.

WFP implements `egress` rules for public and private destinations. `internetClient` enables public-network access.
`privateNetworkClientServer`, selected through `ingress.default`, is the prerequisite for private-network access and
Expand Down
13 changes: 8 additions & 5 deletions docs/backends/process-container/os-version-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ document are Windows 11**, and the minimum considered here is Windows 11 23H2.

For the enforcement mechanisms themselves see the
[UI policy schema](./UIPolicy_Schema.md) and the
[containment configuration spec](../../containment-configuration/0.7.0/policy.md).
[supported configuration schema](../../schema.md).

## Windows 11 releases

Expand Down Expand Up @@ -125,7 +125,9 @@ Notes:

## Network policy

The release matrix describes the legacy schema 0.6/0.7 implementation.
The following release matrix documents the retired schema 0.6/0.7
implementation, not support for executable requests. For current directional
policy and tier behavior, see [ProcessContainer networking](networking.md).

| Aspect | 23H2 | 24H2 | 25H2 | 25H2+ |
|--------|:--:|:--:|:--:|:--:|
Expand All @@ -143,9 +145,10 @@ Notes:
the forward-looking proxy architecture; support for the model-2 BaseContainer
contract should replace this fallback in a separate change.

Schema 0.8 support is selected by runtime contract rather than Windows release:
Supported directional network policy (schema 0.9+) depends on the available
backend enforcement tier rather than the declared version:

| Schema 0.8 capability | PSEC | AppContainer fallback |
| Directional capability | PSEC | AppContainer fallback |
|---|:---:|:---:|
| Directional defaults represented by capabilities | βœ… | βœ… when the capability mapping preserves the request |
| Explicit egress IP/CIDR/port/protocol rules | βœ… WFP | ❌ |
Expand All @@ -155,7 +158,7 @@ Schema 0.8 support is selected by runtime contract rather than Windows release:
PSEC owns the WFP policy lifetime through workload completion. The
AppContainer fallback rejects
`egress.default: "deny"` with `ingress.default: "allow"` because
`privateNetworkClientServer` is bidirectional and no schema 0.8 WFP filter is
`privateNetworkClientServer` is bidirectional and no per-container WFP filter is
available there to block private-network egress.

## UI restrictions
Expand Down
Loading
Loading