Skip to content

Fix MoveDistribution E_ACCESSDENIED when setVhdOwner fails under impersonation#40717

Open
benhillis wants to merge 2 commits into
masterfrom
benhill/fix-move-distro-access-denied
Open

Fix MoveDistribution E_ACCESSDENIED when setVhdOwner fails under impersonation#40717
benhillis wants to merge 2 commits into
masterfrom
benhill/fix-move-distro-access-denied

Conversation

@benhillis
Copy link
Copy Markdown
Member

Summary

Fixes #40716wsl --manage <distro> --move <path> fails with E_ACCESSDENIED when the VHD owner becomes BUILTIN\Administrators after a cross-volume move.

PR Checklist

  • Fixes a bug
  • Includes tests

Detailed Description

After a cross-volume MoveFileEx, the new VHD file's owner may be set to BUILTIN\Administrators (Windows behavior for elevated callers). The setVhdOwner lambda was opening the moved file with WRITE_OWNER under user impersonation, which fails with E_ACCESSDENIED because the impersonated token doesn't have ownership-based access to the file.

The wil::run_as_self() call that grants SYSTEM privileges was placed after CreateFileW — too late.

Fix: Move wil::run_as_self() and AcquirePrivilege(SE_RESTORE_NAME) before CreateFileW so the file handle is opened as SYSTEM. FILE_FLAG_OPEN_REPARSE_POINT is retained to prevent symlink following.

Previously, this failure left the VHD physically moved but the registry BasePath still pointing at the old location, leaving the distro unusable.

Validation Steps

  1. Full build: cmake . && cmake --build . -- -m
  2. Run new test: bin\x64\debug\test.bat /name:*MoveVhdWithAdminOwner*PASSED
  3. Test imports a distro, sets VHD owner to Administrators, then moves as non-elevated user. Verifies move succeeds, ownership is preserved, and distro still launches.

Copilot AI review requested due to automatic review settings June 5, 2026 17:01
@benhillis benhillis requested a review from a team as a code owner June 5, 2026 17:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a WSL service regression where wsl --manage <distro> --move <path> could fail with E_ACCESSDENIED after a cross-volume move changes the VHD owner to BUILTIN\Administrators, leaving the VHD moved on disk but the registry BasePath unchanged (breaking the distro). The fix ensures the VHD is opened and its owner restored under SYSTEM (not the impersonated user) by moving wil::run_as_self() and privilege acquisition before CreateFileW, and adds a regression test.

Changes:

  • In MoveDistribution, run as self (SYSTEM) and acquire SE_RESTORE_NAME before opening the moved VHD with WRITE_OWNER, ensuring owner restoration succeeds even when the impersonated user lacks ownership-based access.
  • Add a new WSL2 unit test that forces the VHD owner to BUILTIN\Administrators, performs a non-elevated move, and validates ownership preservation and distro usability.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/windows/service/exe/LxssUserSession.cpp Fixes setVhdOwner to open the VHD as SYSTEM with needed privilege before CreateFileW, preventing E_ACCESSDENIED under impersonation.
test/windows/UnitTests.cpp Adds regression test MoveVhdWithAdminOwner validating non-elevated move succeeds when VHD owner is Administrators and that the distro still launches.

Ben Hillis and others added 2 commits June 5, 2026 14:00
…rsonation (#40716)

After a cross-volume MoveFileEx, the new VHD file's owner may be set to
BUILTIN\Administrators. The setVhdOwner lambda was opening the file with
WRITE_OWNER under user impersonation, which fails with E_ACCESSDENIED if
the user doesn't own the file. The subsequent run_as_self() came too late.

Move run_as_self() and AcquirePrivilege(SE_RESTORE_NAME) before the
CreateFileW call so the file is opened as SYSTEM, which always has
WRITE_OWNER regardless of file ownership.

Previously, this failure left the VHD at the new location with the
registry BasePath still pointing at the old path, corrupting the distro.

Fixes #40716

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regression test that simulates a cross-volume move scenario: after moving
a distro, the VHD owner is explicitly set to BUILTIN\Administrators
(mimicking MoveFileEx cross-volume behavior), then a second move is
attempted as a non-elevated user. Before the fix, setVhdOwner would fail
with E_ACCESSDENIED because CreateFileW(WRITE_OWNER) ran under user
impersonation.

The test verifies:
- The move succeeds even when the VHD is owned by Administrators
- The VHD owner is restored to the user's SID after the move
- The distro launches successfully after the move

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@benhillis benhillis force-pushed the benhill/fix-move-distro-access-denied branch from 326d51f to 7171848 Compare June 5, 2026 21:00

// Simulate cross-volume MoveFileEx side-effect: change VHD owner to BUILTIN\Administrators.
{
BYTE adminsSidBuffer[SECURITY_MAX_SID_SIZE];
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.

nit: This can be simplified by using: wsl::windows::common::security::CreateSid (and factored since we do the same thing below)

Comment thread src/windows/service/exe/LxssUserSession.cpp
Copy link
Copy Markdown
Collaborator

@OneBlue OneBlue left a comment

Choose a reason for hiding this comment

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

Scratch my previous review, looks like the FILE_FLAG_OPEN_REPARSE_POINT flag already protects us from that

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--move fails to update Registry

3 participants