Skip to content

[WSLC] Proxy Pt. 2: Enable session host loopback - #1714

Open
Elliot (theelliotm) wants to merge 3 commits into
user/emichlin/wslc-proxy-1-sdkfrom
user/emichlin/wslc-proxy-2-host-loopback
Open

Elliot (theelliotm) wants to merge 3 commits into
user/emichlin/wslc-proxy-1-sdkfrom
user/emichlin/wslc-proxy-2-host-loopback

Conversation

@theelliotm

@theelliotm Elliot (theelliotm) commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

📖 Description

Second PR in the WSLC built-in proxy stack (#1625). Turns on WSL host loopback, so hostLoopback: allow reaches Windows 127.0.0.1. Before this, it was accepted but had no effect.

  • Every session MXC creates (create-and-run and the lifecycle daemon) sets the host loopback hostname host.wslc.internal, which WSL's CLI also uses.
  • On WSL older than 3.0.5, session creation returns WSLC_E_RUNTIME_UPDATE_NEEDED; MXC fails with the "WSLC runtime unavailable" error telling the user to install WSL 3.0.5 or newer.
  • Isolated (NONE) containers in a session with host loopback still can't reach Windows loopback, by name or by the relay address.

Behavior change: existing all-allow configs gain outbound access to every Windows loopback TCP port. There's no per-port filter; that comes with the controller later in the stack.

🔗 References

Refs #1462
Spec: #1625
Stacked on #1679

🔍 Validation

On ARM64 with WSL 3.0.5.0 and WSLC_SDK_PATH set to the local 3.0.5 SDK build:

  • cargo build -p wxc --features wslc --release and cargo build -p mxc-sdk --bin wxc-wslc-daemon --features wslc --release: passed
  • cargo fmt --all -- --check: passed
  • cargo clippy -p mxc-sdk --features wslc --all-targets -- -D warnings: passed
  • cargo test -p mxc-sdk --features wslc --lib wslc: passed (434 passed, 7 ignored)
  • tests/scripts/run_wslc_host_loopback_test.ps1 (new): passed. A bridged container gets a per-run token from a listener bound to Windows 127.0.0.1; an isolated container doesn't get it through host.wslc.internal or 169.254.73.254.
  • tests/scripts/run_wslc_state_aware_tests.ps1: passed (142/142), including new checks that, with both running in one verified session, a bridged sandbox reaches the listener and an isolated peer doesn't.

Not run: x64, the full run_wslc_all_tests.ps1 after the final test changes, and WSL older than 3.0.5.

✅ Checklist

  • Signed the Contributor License Agreement
  • Linked to an issue
  • For features or changes requiring a spec: linked the issue with maintainer-applied feature-accepted
  • For implementation: linked the required approved and merged design/API spec, or explained why no spec is required
  • Feature issue remains open unless this PR completes all agreed implementation, validation, and documentation
  • Updated documentation (if applicable)
  • Updated Copilot instructions (if build, architecture, or conventions changed)
  • If this PR changes Cargo.lock, the dependency-feed-check check passes (see pull request builds)

📋 Issue Type

  • Bug fix
  • Feature
  • Task

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@theelliotm Elliot (theelliotm) changed the title enable hostLoopback on WSL 3.0.5 [WSLC] Proxy Pt. 2: Enable session host loopback Nov 9, 2026
@theelliotm
Elliot (theelliotm) force-pushed the user/emichlin/wslc-proxy-2-host-loopback branch from 7cbd0d1 to 30303eb Compare November 10, 2026 22:17
Copilot AI balanced review requested due to automatic review settings November 10, 2026 22:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The tests can miss shared-session relay exposure, incorrectly fail supported older WSL runtimes, and lack passing regression coverage for the non-loopback retry.

3 open issues
What changed in this PR

This PR adds Windows host-loopback access to WSLC workload sessions, advancing the built-in proxy stack. Bridged containers can reach Windows loopback services through host.wslc.internal on WSL 3.0.5+.

Changes:

  • Shares session-creation logic across create-and-run execution and the lifecycle daemon, with a fallback for older runtimes.
  • Adds token-based loopback reachability and isolation tests.
  • Documents runtime requirements and the expanded access granted to existing all-allow configurations.
File Description
tests/​scripts/​wslc_loopback_token_server.ps1 Provides a Windows loopback listener with a per-run token.
tests/​scripts/​run_wslc_state_aware_tests.ps1 Adds lifecycle loopback reachability and isolation checks.
tests/​scripts/​run_wslc_host_loopback_test.ps1 Drives create-and-run loopback tests.
tests/​scripts/​run_wslc_all_tests.ps1 Includes loopback tests in the full WSLC suite.
tests/​configs/​wslc_network_host_loopback.json Defines the bridged loopback probe.
tests/​configs/​wslc_network_host_loopback_isolated.json Defines isolated probes by hostname and relay address.
src/​mxc-sdk/​src/​backends/​wslc/​common/​wslc_bindings.rs Loads the loopback-setting API and defines the runtime-update error.
src/​mxc-sdk/​src/​backends/​wslc/​common/​wsl_container_runner.rs Uses shared session creation for create-and-run execution.
src/​mxc-sdk/​src/​backends/​wslc/​common/​container_steps.rs Enables session loopback and retries without it on older runtimes.
docs/​backends/​wslc/​wslc-state-aware.md Documents loopback access through daemon sessions.
docs/​backends/​wslc/​wsl-container-getting-started.md Explains prerequisites, usage, and networking behavior changes.

Review effort: Balanced

Elliot (theelliotm) and others added 2 commits November 10, 2026 16:53
Drop the pre-3.0.5 fallback; an older runtime now fails as WSLC runtime unavailable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c3f64c2c-9005-43eb-a803-a91fb7265c5b
@theelliotm
Elliot (theelliotm) force-pushed the user/emichlin/wslc-proxy-2-host-loopback branch from 30303eb to 727d749 Compare November 11, 2026 20:14
Copilot AI balanced review requested due to automatic review settings November 11, 2026 20:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The isolation test can pass without checking containment alongside a live bridged peer in the same session because it tears down the bridged sandbox before probing its saved relay address.

1 open issue
2 resolved since last review

Review effort: Balanced

Run the host loopback checks in one shared session under one listener, so the
negative probe cannot pass against a reaped session or a dead listener.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c3f64c2c-9005-43eb-a803-a91fb7265c5b
Copilot AI balanced review requested due to automatic review settings November 11, 2026 22:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Maintainer confirmation is still needed for expanded Windows loopback access, with the design PR unmerged and x64 and older-runtime error-path validation outstanding.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@theelliotm
Elliot (theelliotm) marked this pull request as ready for review November 11, 2026 22:16
@theelliotm
Elliot (theelliotm) requested a review from a team as a code owner November 11, 2026 22:16
let msg = err_msg.to_string_lossy();
return Err(sdk_error("WslcCreateSession failed", hr, &msg));
}
let session = container_steps::create_session(sdk, &mut settings)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On x64/WSL 3.0.5 a bridged create-and-run sandbox fetched another sandbox's port mapping via host.wslc.internal:<windowsPort>: MXC passes a null windowsAddress, so WSL publishes every mapping on Windows 127.0.0.1, and this relay opens all of them to every bridged sandbox.

Don't enable session host loopback until per-container/per-port enforcement exists, and add a two-sandbox negative test to run_wslc_host_loopback_test.ps1.

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.

Wow. Investigating.

let mut err_msg = CoTaskMemPWSTR::null();
let started = Instant::now();
let hr = sdk.WslcCreateSession(&mut settings, &mut session, err_msg.as_mut_ptr());
let session = create_session(sdk, &mut settings)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The daemon now enables host loopback, but PROTOCOL_VERSION stays 9 and ready_daemon() reuses any ready v9 daemon, so after an upgrade a still-running pre-PR daemon (alive while it holds sandboxes) keeps creating sessions without host.wslc.internal, and a new daemon gives old clients the new access.

Shall we bump the protocol version?

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.

Will bump.

Comment on lines +899 to +900
/// Create a session with host loopback enabled. A WSL runtime older than 3.0.5
/// rejects the setting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Isolated-only sessions (every deny-all create-and-run, where network_is_isolated(request) is already known) gain nothing from host loopback, yet setting it forces WSL's new session path, so they now fail below WSL 3.0.5 while available_backends() still reports WSLC available; #1625 README.md:80-81 and 407-410 say MXC sets it only on 3.0.5+ and NONE/BRIDGED keep working on older runtimes.

Set the hostname only for sessions that can hold a bridged container (pass !network_is_isolated(request) from the runner), or update #1625 and make discovery report the 3.0.5 requirement.

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.

3.0.5 is now the minimum version. I will see if I can enforce that.

let mut err_msg = CoTaskMemPWSTR::null();
let hr = sdk.WslcCreateSession(settings, &mut session, err_msg.as_mut_ptr());
if hr == WSLC_E_RUNTIME_UPDATE_NEEDED {
return Err(WslcError::Unavailable(sdk_init::prerequisite_error(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In the daemon this Unavailable surfaces on the boot thread, and finish_session rewraps it as WorkerError::Backend for every provision parked on the implicit session, so a lifecycle provision on WSL < 3.0.5 gets backend_error instead of the backend_unavailable documented at wslc-state-aware.md:701.
Forward Unavailable/Rejected unchanged to parked replies and add a session_manager test for a boot that fails with Unavailable.

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.

3.0.5 is now the minimum version. I will see if I can enforce that.

# HTTP listener bound only to Windows 127.0.0.1 that answers every request with
# a per-run token. Dot-source this file, then pair Start- with Stop-.

function Start-LoopbackTokenServer {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This duplicates tests/scripts/lib/LoopbackAnchor.ps1, whose Start-LoopbackAnchor -Body already binds an ephemeral 127.0.0.1 port and serves a fixed body from a background runspace.
Use Start-LoopbackAnchor -Body ("HOST_LOOPBACK_" + [guid]::NewGuid().ToString("N")) / Stop-LoopbackAnchor and drop this file?

@microsoft-github-policy-service microsoft-github-policy-service Bot added Needs-Author-Feedback Waiting for additional information or action from the issue or pull-request author. Needs-Attention Requires attention or a decision from the MXC maintainers. and removed Needs-Author-Feedback Waiting for additional information or action from the issue or pull-request author. labels Nov 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs-Attention Requires attention or a decision from the MXC maintainers.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants