Phase 2: fallback_detector module for tier selection#294
Merged
Conversation
2b7f10a to
5ff6459
Compare
a94ed8f to
7013144
Compare
5ff6459 to
374c03b
Compare
7013144 to
a9137c0
Compare
374c03b to
cddf163
Compare
a9137c0 to
da91c35
Compare
cddf163 to
33af9d6
Compare
da91c35 to
ebecee9
Compare
33af9d6 to
c2d1bb8
Compare
ebecee9 to
2827445
Compare
1cc2ced to
8cc6e01
Compare
849884d to
3071668
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a new fallback_detector module that selects an IsolationTier (BaseContainer / AppContainerBfs / AppContainerDacl) based on ContainerPolicy plus runtime probes (BaseContainer API, bfscfg.exe, WRITE_DAC). Pure module with a debug-only MXC_FORCE_TIER test seam; no logging or telemetry.
Changes:
- New
fallback_detectormodule withdetect(),TierDecision,FallbackError, and runtime probes. - Promoted
BFSCFG_EXEtopub(crate)so the detector can reuse the constant. - Registered the new module in
wxc_common'slib.rsundercfg(target_os = "windows").
Show a summary per file
| File | Description |
|---|---|
| src/wxc_common/src/lib.rs | Exposes the new fallback_detector module on Windows. |
| src/wxc_common/src/filesystem_bfs.rs | Widens visibility of BFSCFG_EXE to pub(crate) for reuse. |
| src/wxc_common/src/fallback_detector.rs | New pure tier-selection module with probes, force-tier seam, and unit tests. |
Copilot's findings
- Files reviewed: 3/3 changed files
- Comments generated: 5
08062b6 to
ba96205
Compare
shschaefer
reviewed
May 14, 2026
a54589c to
6e46423
Compare
6e46423 to
77574f9
Compare
jsidewhite
reviewed
May 18, 2026
| @@ -151,8 +151,23 @@ fn print_error_envelope(error: &MxcError) { | |||
| } | |||
|
|
|||
| fn delete_app_container_profile(name: &str, logger: &mut Logger) -> bool { | |||
Member
jsidewhite
reviewed
May 18, 2026
| /// | ||
| /// - **Release builds** consult `GetWindowsDirectoryW` exclusively. The | ||
| /// `SystemRoot` environment variable is deliberately ignored to deny | ||
| /// an attacker who can scrub or rewrite the process environment a |
Member
There was a problem hiding this comment.
Is this a real threat? If an attacker can manipulate the environment of wxc-exec.exe, then it's it's already in.
Is this merely defense in depth?
Member
There was a problem hiding this comment.
ohhh it's moreso this,
preventing
/// executable-search-order hijacking by an attacker who can plant a
/// rogue `bfscfg.exe` next to `wxc-exec.exe`
jsidewhite
reviewed
May 18, 2026
| format!("\"{escaped}\"") | ||
| } else { | ||
| exe_path.to_string() | ||
| }; |
Member
There was a problem hiding this comment.
can't you use the path crate?
use std::path::Path;
let p = Path::new(r"C:\Windows").join("System32").join("kernel32.dll");
or
use std::path::PathBuf;
let mut path = PathBuf::from(r"C:\");
path.push("Windows");
path.push("System32");
path.set_extension("dll");
println!("{}", path.display());
…olution Adds a pure detection module that produces a TierDecision from policy + runtime probes (BaseContainer API, bfscfg.exe presence, WRITE_DAC). Module: - Three-tier model: BaseContainer / AppContainerBfs / AppContainerDacl - allow_dacl_fallback=false blocks any tier requiring host DACL modification (including T1/T2 deny-augmentation) - MXC_FORCE_TIER injection seam (debug builds only) for testing - Pure module: no Logger dependency, no telemetry emission; Phase 4 wires this into the dispatcher Security hardening for the Tier 2 (AppContainer + BFS) path: 1. Environment-driven downgrade. The previous probe read the SystemRoot env var when locating bfscfg.exe, letting an attacker who could influence the process environment force a silent demotion to Tier 3 (DACL) even with the real binary in System32. Release builds now resolve via GetWindowsDirectoryW exclusively, which the OS populates from boot configuration rather than the process environment. 2. Executable-search-order hijacking. FileSystemBfsManager previously invoked CreateProcessW with lpApplicationName = NULL and a bare `bfscfg.exe` command line, exposing the standard image-dir / CWD / System32 / PATH search order to attackers who could drop a malicious bfscfg.exe alongside wxc-exec.exe or earlier on PATH. find_bfscfg_exe now returns the absolute path resolved at probe time and FileSystemBfsManager passes it as lpApplicationName, so Windows loads exactly that binary and skips the search order. Probe and execution share one resolution via TierDecision.bfscfg_path, eliminating any TOCTOU gap between tier decision and broker invocation. Debug-only test seam MXC_BFSCFG_PATH overrides resolution under `#[cfg(debug_assertions)]`; release builds never read it. Follow-up TODO in fallback_detector.rs flags BaseContainerRunner's LoadLibrary on processmodel.dll for the same DLL-search-order audit on the Tier 1 surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
77574f9 to
4150bb3
Compare
MGudgin
pushed a commit
that referenced
this pull request
May 19, 2026
Move `delete_app_container_profile` from `src/wxc/src/main.rs` into `src/wxc_common/src/appcontainer_runner.rs`, next to `AppContainerScriptRunner` (which owns the create/setup path). Both ends of the AppContainer profile lifecycle now live in the same module. While moving the function, replace the open-coded `FileSystemBfsManager::new(...) + remove_configuration(...)` block with `FileSystemBfsManager::clear_policy(name, logger)`. The original code created a fresh manager and called `remove_configuration` without first setting `configured = true`, so the early-return in `remove_configuration` made the BFS-clear step a silent no-op for `wxc-exec --delete`. `clear_policy` is the helper purpose-built for externally-created sandboxes and sets `configured = true` itself, so the cleanup actually runs now. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MGudgin
added a commit
that referenced
this pull request
May 20, 2026
Move `delete_app_container_profile` from `src/wxc/src/main.rs` into `src/wxc_common/src/appcontainer_runner.rs`, next to `AppContainerScriptRunner` (which owns the create/setup path). Both ends of the AppContainer profile lifecycle now live in the same module. While moving the function, replace the open-coded `FileSystemBfsManager::new(...) + remove_configuration(...)` block with `FileSystemBfsManager::clear_policy(name, logger)`. The original code created a fresh manager and called `remove_configuration` without first setting `configured = true`, so the early-return in `remove_configuration` made the BFS-clear step a silent no-op for `wxc-exec --delete`. `clear_policy` is the helper purpose-built for externally-created sandboxes and sets `configured = true` itself, so the cleanup actually runs now. Co-authored-by: Gudge <gudge@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
huzaifa-d
pushed a commit
that referenced
this pull request
May 21, 2026
fallback_detector: tier-selection module with hardened bfscfg.exe resolution Adds a pure detection module that produces a TierDecision from policy + runtime probes (BaseContainer API, bfscfg.exe presence, WRITE_DAC). Module: - Three-tier model: BaseContainer / AppContainerBfs / AppContainerDacl - allow_dacl_fallback=false blocks any tier requiring host DACL modification (including T1/T2 deny-augmentation) - MXC_FORCE_TIER injection seam (debug builds only) for testing - Pure module: no Logger dependency, no telemetry emission; Phase 4 wires this into the dispatcher Security hardening for the Tier 2 (AppContainer + BFS) path: 1. Environment-driven downgrade. The previous probe read the SystemRoot env var when locating bfscfg.exe, letting an attacker who could influence the process environment force a silent demotion to Tier 3 (DACL) even with the real binary in System32. Release builds now resolve via GetWindowsDirectoryW exclusively, which the OS populates from boot configuration rather than the process environment. 2. Executable-search-order hijacking. FileSystemBfsManager previously invoked CreateProcessW with lpApplicationName = NULL and a bare `bfscfg.exe` command line, exposing the standard image-dir / CWD / System32 / PATH search order to attackers who could drop a malicious bfscfg.exe alongside wxc-exec.exe or earlier on PATH. find_bfscfg_exe now returns the absolute path resolved at probe time and FileSystemBfsManager passes it as lpApplicationName, so Windows loads exactly that binary and skips the search order. Probe and execution share one resolution via TierDecision.bfscfg_path, eliminating any TOCTOU gap between tier decision and broker invocation. Debug-only test seam MXC_BFSCFG_PATH overrides resolution under `#[cfg(debug_assertions)]`; release builds never read it. Follow-up TODO in fallback_detector.rs flags BaseContainerRunner's LoadLibrary on processmodel.dll for the same DLL-search-order audit on the Tier 1 surface. Co-authored-by: Gudge <gudge@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📖 Description
Adds a pure detection module that produces a
TierDecisionfrom policy + runtime probes (BaseContainer API,bfscfg.exepresence,WRITE_DAC), plus security hardening for the Tier 2 (AppContainer + BFS) execution path.Module
allow_dacl_fallback=falseblocks any tier requiring host DACL modification (including T1/T2 deny-augmentation)MXC_FORCE_TIERinjection seam (debug builds only) for testingLoggerdependency, no telemetry emission. Phase 4 wires this into the dispatcher.🛡️ Security hardening
Environment-driven Tier 2 → Tier 3 downgrade. The original probe read the
SystemRootenv var when locatingbfscfg.exe, letting an attacker who could influence the process environment (parent process, persisted user env, service definition) force a silent demotion to Tier 3 (DACL) even with the real binary in System32. Release builds now resolve viaGetWindowsDirectoryWexclusively — the OS populates it from boot configuration, not the process environment.Executable-search-order hijacking.
FileSystemBfsManagerpreviously invokedCreateProcessWwithlpApplicationName = NULLand a barebfscfg.execommand line, exposing the standard image-dir → CWD → System32 → System → Windows → PATH search order. An attacker who could dropbfscfg.exenext towxc-exec.exe, in CWD, or earlier onPATHwould have their binary executed as the BFS broker regardless of what the probe concluded.find_bfscfg_exenow returns the absolute path resolved at probe time;FileSystemBfsManagerpasses it aslpApplicationNameso Windows loads exactly that binary and skips the search order.Probe and execution share one resolution via
TierDecision.bfscfg_path— single source of truth, no TOCTOU gap between tier decision and broker invocation.Debug-only test seam:
MXC_BFSCFG_PATHoverrides resolution under#[cfg(debug_assertions)]. Release builds never read it, so it cannot be used as an attack vector in production.A follow-up TODO in
fallback_detector.rsflagsBaseContainerRunnersLoadLibraryonprocessmodel.dllas the next surface to audit for the same DLL-search-order family of attacks (Tier 1 surface).🔗 References
Stacked on top of #293 (phase1_integrate → phase1d).
🔍 Validation
cargo fmt --all -- --checkcleancargo clippy --workspace --all-targets -- -D warningscleancargo test -p wxc_common— 357 tests pass (16fallback_detectorincl. 4 new for theMXC_BFSCFG_PATHseam; 8filesystem_bfsincl. 1 new for absolute-path quoting)Win25H2Safe-Tests.ps1in phase5 (held)