Skip to content

Default-mode Windows sandbox should resolve (or deny) writes through intermediate junctions inside opaque outputs #1355

Description

Context

The documentation scopes sandbox blocking to inter-pip dependency enforcement, and DScript specs are authored by the build's owner, so I'm filing this as a consistency observation rather than a containment claim. In default Windows sandbox mode, the reparse-point policy check inspects only the final path component, so a write issued through a junction created inside a pip's own opaque output directory is policy-checked against the junction's literal path, not the target the bytes actually reach.

Observed behavior (current main, 842e92b)

  • Full reparse-point resolving is off by default on Windows: Public/Src/Utilities/Configuration/Mutable/UnsafeSandboxConfiguration.cs ~L21 (IgnoreFullReparsePointResolving = OperatingSystemHelper.IsWindowsOS) and Public/Src/Utilities/Configuration/UnsafeSandboxConfigurationDefaultExtensions.cs ~L20, ~L42.
  • The detours fast path checks only the final component for a reparse attribute in default mode: Public/Src/Sandbox/Windows/DetoursServices/DetouredFunctions.cpp, ShouldResolveReparsePointsInPath ~L495-512, with the final-component checks around ~L131-137 and ~L3406.
  • Opaque output directories grant AllowAll, including write and symlink creation: Public/Src/Engine/Processes/FileAccessPolicy.cs ~L126 and Public/Src/Engine/ProcessPipExecutor/SandboxedProcessPipExecutor.cs ~L2604-2623.
  • Post-run enumeration hashes through junction outputs: Public/Src/Engine/Scheduler/Artifacts/FileContentManager.cs ~L826-851.

Consequence: a pip can create a junction inside its own opaque output dir and write through it, e.g.

cmd /c mklink /J Out\obj\J <target> && echo x > Out\obj\J\f.txt

The write is checked as an ordinary opaque-scope write even though the bytes land at <target>\f.txt; reads and output hashing follow the junction the same way. A spec that genuinely needs this can already declare it via unsafe.untrackedScopes, so this is audit-clarity rather than new capability — but the Linux sandbox resolves intermediate symlinks by default (Windows opted out for performance; the JavaScript resolver is excepted per JavaScriptResolverSettings.cs ~L23), so the two platforms currently disagree, and on Windows the escape is invisible to spec review.

Suggested direction

  • In default mode, resolve intermediate reparse points when the access desires write access under a writable scope. ShouldResolveReparsePointsInPath already has the policy context, so adding a wants-write condition is a targeted change that avoids the full-resolution performance cost. Alternatively, flip DefaultEnableFullReparsePointResolving on for Windows with the performance caveat documented.
  • Additionally or alternatively, treat an actionable reparse point discovered under an opaque output at post-run enumeration as a pip failure, and skip hashing through it.
  • Add a default-mode detours test for an undeclared write through an intermediate junction inside an opaque scope. The existing default-mode tests (Public/Src/Engine/UnitTests/Processes.Detours/PipExecutorDetoursTest.cs ~L7384, ~L7629) cover declared reads; the junction-output tests are currently Skipped (~L3552, ~L3594: "No support for directory junctions as outputs").

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions