microsoft / microsoft/WSL

wslc: support constrained archive upload with held no-follow resolution

Open
#41,594 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature wslc
Dominant language
C++
Stars
33.7k
Forks
1.8k
Avg merge
3d 17h
Merged PRs (30d)
116

Description

**Is your feature request related to a problem? Please describe.**
WSLC's archive upload has no supported operation that confines extraction beneath a checked container directory while an untrusted guest is running. Checking the components first and then calling `wslc container cp - CONTAINER:/` leaves a check/copy window. Archive uid/gid values do not bound placement to that user.

Measured with WSLC/WSL 2.9.4.0, kernel 6.18.35.2-1, Windows 10.0.26220.9223, and an Azure Linux core 3.0 container whose image user is 10001:20001:

- Create `/work` writable by that user and `/protected` owned by root, mode 0700. A direct guest write to `/protected/control` fails with Permission denied.
- Check `/work/parent` while it is a directory. As the non-root guest, rename it and replace it with a symlink to `/protected`.
- Upload an archive containing `work/parent/landed`, uid/gid 10001:20001, to the container root. The copy succeeds, `/protected/landed` contains the uploaded bytes, and its owner is 10001:20001. `/protected` remains root-owned mode 0700.
- An archive containing a missing child directory and a file beneath that same swapped existing parent also succeeds under `/protected`. Directory-only upload has the same behavior.
- A directory entry at the exact symlink path replaces that link instead, but does not protect an existing prefix omitted from the archive or bind resolution across extraction.

The interleaving is deterministic: the swap finishes after validation and before copy starts. This is container-internal placement authority, not a claim of host-filesystem escape.

**Describe the solution you'd like**
A supported constrained archive-upload operation, in the CLI and SDK, that takes an explicit container destination base and holds safe no-follow resolution through creation and replacement. It should reject symlinked ancestors, prevent a concurrently renamed/replaced ancestor from redirecting entries outside that base, and apply the same confinement to missing-directory creation. Entry ownership should remain independently selectable. A second path check inside the CLI followed by ordinary extraction would still leave the window.

Please document the concurrency and partial-failure/cancellation contract, including whether earlier entries can remain after a later refusal. It should work without trusting utilities supplied by the container image. This can be an opt-in operation; changing ordinary Docker-compatible `cp` behavior is not required.

**Describe alternatives you've considered**
- A real container freeze spanning trusted metadata reads and copy could also close this window. No pause/unpause command or public SDK freezer is exposed in the inspected interfaces. `container kill --signal SIGSTOP` returned success, but a new exec still ran before SIGCONT; it is not a container freezer. Stopping/restarting loses running process state.
- A guest-authority transfer bounds placement but adds a trusted helper or guest utilities and a different image contract.
- #41310 would allow a caller to inspect archive type metadata without guest utilities, but would not bind those observations to a later upload. #41309 is also separate from this input direction.

**Additional context**
This is the missing primitive identified by sokolaidev/maf-extensions#1203. The caller retains an explicit residual until a supported closure is available.

Source inspected at microsoft/WSL commit `eaa69e766cf375d96053207a4ba8858f54ea1536`: `ContainerCpCommand::GetArguments` has no user or no-follow selector; `WSLCContainerImpl::UploadArchive` calls the internal runtime's `PutArchive` with a destination string. Its shared object lock does not hold the caller's earlier path classification or prevent guest filesystem mutation. This source inspection is separate from the live 2.9.4.0 measurement.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ContainerCpCommand::GetArguments and WSLCContainerImpl::UploadArchive at commit eaa69e766cf375d96053207a4ba8858f54ea1536, then trace the internal PutArchive call. Define the CLI and SDK inputs for an explicit destination base, held no-follow resolution, selectable ownership, and partial-failure behavior. Done means concurrent ancestor replacement cannot redirect extraction outside the base without relying on guest utilities.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
cli, operating-systems, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.