* Run the nightly tests on ge-current
* Run the nightly tests on Windows Server 2025
* Skip some network tests
* Update name
* Fix mirrored check
* Use the server field
* Update the DACL to only allow access to the user when creating virtual disks
* Save state
* Increase test coverage
* Fix test
* Apply PR feedback
* Apply PR feedback
* Format
* Apply PR suggestions
* Apply PR suggestions
* Expose kernel headers and perf to distributions
Mount kernel-matched headers and perf tooling from the artifacts VHD into each distribution, expose perf through the default environment, and cover the resulting paths and replacement behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cdebc331-ad3e-492e-9591-c25587c859c5
* Address kernel artifact review feedback
Correct the documented header target and directory fallback, and log failures while removing mount path environment variables.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cdebc331-ad3e-492e-9591-c25587c859c5
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Copilot-Session: cdebc331-ad3e-492e-9591-c25587c859c5
For a newly installed distro, the drvfs are initially mount as 0:0. And is not updated after oobe sets the default uid. This could cause access issues before the distro is restarted.
This PR updates the auto mounted drvfs gid uid before completing the oobe. The non-auto mounted shares are not remounted to avoid breaking user set gid uid values.
This is a follow up to PR #41512
Remove the redundant restore cgroup namespace code.
Simplify the cgroup check logic by moving the retry inside the debug shell.
Add a new systemd boot timeout test.
When parsing the config file, non-ascii utf-16 values are casted into char. This will mangle non-ascii values in the config file. For example, a custom kernel path containing Chinese characters will cause WSL_E_CUSTOM_KERNEL_NOT_FOUND.
This PR removes the faulty static cast and stores the config value in wstring instead of string. So non-ascii values are preserved.
In 2.9.8, the distro processes are separated into their own cgroups. But they remain in the same cgroup namespace. That caused compatibility issues with softwares that assume a fixed systemd cgroup layout. For example, rootless docker and nerdctl.
Fixes on Moby and nertctl are being worked on. However, to avoid issues with other software, WSL's cgroup handling should also be improved.
This PR creates new cgroup namespaces for the distros. So, to the non-critical distro processes, the systemd cgroup layout stays the same as before.
This PR also introduces a cgroup structure change to accomplish this. The systemd init is moved from wsl-user/distro-N/systemd to wsl-user/distro-N. And the initialization of the distro-N controllers is handled by systemd instead.
The processes are also moved into the non-systemd cgroup in systemdless distros. This makes sure that sub-group controllers can be enabled in the distro root.
Cgroup v2 is now enforced when distro isolation is enabled. Instead of constructing an unusable cgroup v1 layout when cgroup v1 and distro isolation are both enabled.
Currently the stdout and stderr relay tracks the output offset separately. And when redirected to the same file, the writes could overlap.
This PR uses the append mode for overlap io writes instead of the separate offsets in the relay. So, the file write offset is correctly tracked by the system.
`case '\r': break;` made a backslash before a CR the only unrecognised
escape the parser accepts without a diagnostic. In a CRLF file that left
the value truncated at the backslash and the remainder parsed as its own
line, with nothing reported.
Letting it fall into the default case gives the same
MessageConfigInvalidEscape warning as any other bad escape. As with those,
the line is then discarded rather than kept truncated.
In systemd v261, the systemd's tmpfiles.d/x11.conf was changed from D! to D. systemd/systemd@5474cad.
This means the systemd-tmpfiles command will try to execute it when called out of the boot sequence. In the linked issue's case, it's called by the post install script by dpkg. This will fail as the wsl override is not in place when systemd is disabled.
This PR enables the wsl override file generation for all distros with wslg enabled, regardless of if the distro boots with systemd.
This PR adds a "search or file issue on github" suggestion in all user visible errors to:
Help users find solutions faster.
Collect more user reported issues to help reliability improvements.
This PR also updates all tests checking the error message to use a unified function for creating the expected error message.
This PR fixes batch of minor issues found during AI code review.
src/linux/init/GnsPortTracker.cpp: 378
Fixed oversized socket-address allocations from malicious inputs.
src/linux/init/main.cpp: 2173
Fixed mini init overwriting a distribution symlink target.
src/windows/common/WslClient.cpp: 259
src/windows/common/precomp.h: 100
test/windows/UnitTests.cpp: 172
Fixed conflicting export formats being accepted together.
src/windows/common/WslClient.cpp: 928
test/windows/UnitTests.cpp: 4371
Fixed command injection through --set-default-user.
src/windows/service/exe/WslCoreGuestNetworkService.cpp: 95
Fixed the guest network service VM ID not being stored.
src/windows/service/exe/WslCoreNetworkEndpoint.h: 20
Fixed network endpoint move assignment leaking the replaced endpoint.
The current disk attach caching logic only checks the vhd path. When the backing volume is detached than reattached, the check will pass but the stale reference won't work inside the VM.
The backing volume reattaching can happen after bitlocker locking and unlocking #12599, or vhdx detaching then reattaching.
This PR checks if the cached vhd is stale by holding a handle to the vhd file. And checks if it's still valid before reuse. If not, the vhd will be reattached.
Update the packaged kernel dependency from modules.vhd to artifacts.vhd and load kernel modules from the versioned <release>/modules directory. Preserve support for legacy flat module VHDs in the standard WSL boot path and teach WSLC sessions to mount modules from the nested layout.
Update development paths and kernel module tests for the renamed VHD and new mount source.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Copilot-Session: a7cc3086-6311-4bc8-a591-49fd0e6b03fd
Run distribution moves under a duplicated caller token whose default owner is the caller's user SID. This keeps cross-volume copies accessible without reopening the destination to rewrite its owner.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add manual VHDX compaction command
* Address compact command review feedback
* Tighten compact command validation
* Use existing user session interface for compact
* Avoid holding instance lock during compact
* Serialize compact with VHD operations
* Restore package WiX trailing newline
* Use locked distribution state for compact
* Remove allow-unsafe parser restriction
* Use conversion lock for compact
* Format compact command source
* Verify compact reclaims VHD space in test
* Reject VHD compaction with clear error
* Add compact telemetry
* Show progress while compacting
* Fix compact help locked token
* Reduce compact test data cost
* Update compact help text
* Undo package.wix.in change per review feedback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Address review: reword compact-not-supported message, merge scope_exits
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Align compact help text with shipped resw and fix locked token
- HelpMessages test expected 'stopped WSL 2 distribution' but the resw help
ships 'WSL 2 distribution'; drop 'stopped' so the test matches (compaction
auto-terminates the distro, and sibling --resize/--move help omit it too).
- Add missing trailing space to the --compact locked token in the help comment.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Trim the filesystem before compacting a distribution's VHD
WSL2 does not mount ext4 with 'discard' and does not run fsck at boot, so
blocks freed inside the guest stay marked as allocated in the VHD. A bare
'wsl --manage <distro> --compact' therefore reclaims very little space.
Before compacting, attach the stopped distribution's VHD to the utility VM
and run an offline 'e2fsck -f -y -E discard' on the raw device. This issues
the same block-discard requests that 'fstrim' would on a mounted filesystem,
so freed blocks are marked unused and the subsequent host-side compaction can
reclaim them. Running e2fsck offline (rather than fstrim on a mount) reuses
the plumbing already used by ResizeDistribution, needs no mount, relies only
on e2fsprogs (guaranteed present in the utility VM), and also performs the
filesystem check a reviewer asked for.
The trim is best-effort: any failure is logged and does not abort compaction.
The Compact unit test no longer runs 'fstrim' manually inside the guest, so it
now validates that '--compact' performs the trim itself.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Pass explicit user token to s_OpenLxssUserKey
* Remove stale VHD localization lock
* Fix --compact localization lock delimiter
* Default initialize distro configuration
* Remove redundant compaction sharing violation handling
* Remove redundant sparse setup from compact test
* Simplify VHD compaction logging
* Revert unrelated locked distribution rename
* Remove redundant shutdown from compact test
* Apply clang-format to compact changes
* Fix compact command formatting
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
std::filesystem::weakly_canonical only returns an absolute path when a leading
element of its input exists, so a relative path naming a file that has not been
created yet is returned unchanged, still relative. The service then rejects it
with "Path is not absolute". This affected `wslc build --iidfile <relative>` and
`--secret src=<relative>`, plus the distribution path and virtiofs share path
helpers in the service. Add wsl::windows::common::filesystem::GetCanonicalPath,
which applies std::filesystem::absolute first so the result is absolute whether
or not the path exists, and replace the direct weakly_canonical calls with it.
It checks the error from absolute before canonicalizing, because absolute
returns an empty path on failure and weakly_canonical both succeeds on an empty
path and clears the error_code on success, so nesting the two calls would
discard the failure and report success
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Currently, after a fresh distro installation, operations in the linux plan9 share will use the uid 0. Because the uid was cached before the OOBE is complete. And this only recovers after a distro termination.
This PR updates the plan9 registration after the OOBE completes with the new default uid.
In the port 0 tracking logic. The seccomp filter provides the tid instead of the pid. But the pidfd_open call by default requires the first parameter to be a pid. This causes bind calls in threads not tracked by the tracker. Which further causes the local host forwarding to not work for consomme.
This PR applies the PIDFD_THREAD flag introduced in kernel 6.9 to the pidfd_open call. So, it works with non group leader threads as well.
Please note:
PIDFD_THREAD is defined in place as musl does not provide <sys/pidfd.h> and including <linux/pidfd.h> introduces conflict with musl's header files.
The test is not using a perl script since the perl in the test distro is lacking threading support.
The value in locale files could be shell escaped. The old parsing logic sets the string directly. Which could set LANG to a wrong value like "en_US.UTF-8".
This PR un-escapes the value string before setting it to the env LANG.
Systemd globally unmounts shared mounts under /mnt/wsl during graceful shutdown.
This PR adds a systemd unit to set /mnt/wsl as recursive slave during shutdown before unmounting to avoid the unmount from propagating to other namespaces.
Address PR #41170 feedback from @oneblue: the wait for the distribution to enter the Exporting state was capped at ~10 seconds (100 x 100ms), which can flake on slow machines before the export acquires the lock.
Replace the hand-rolled poll loop with wsl::shared::retry::RetryWithTimeout and raise the total timeout to two minutes, matching the retryshared.h convention already used elsewhere in the tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Copilot-Session: 6c2f7701-180c-45fc-a1d6-c9ca46be324b
* Serialize move/resize/set-sparse against in-progress conversions
MoveDistribution, SetSparse, and ResizeDistribution mutate a distribution's
VHD but never checked m_lockedDistributions. A conversion (--set-version) or
export releases m_instanceLock while running yet keeps the distribution in
m_lockedDistributions, so these operations could start mid-conversion and race
on the same VHD (e.g. a corrupt export, or the VHD moved/resized out from under
a conversion).
Add _EnsureNotLocked under m_instanceLock to each so they fail with
E_ILLEGAL_STATE_CHANGE while a conversion/export/compaction is in progress,
matching how the conversion paths already guard each other via _ConversionBegin.
Add a regression test that holds a distribution in the Exporting state (via a
blocked export pipe) and verifies --resize, --set-sparse, and --move are all
rejected.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Generalize lock-guard comments to conversion/export
Compaction isn't part of this branch, so drop it from the comments.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Address review: deterministic pipe block and accurate cleanup comment
- Use an explicit 1-byte pipe buffer so the export blocks immediately regardless
of test distro size, instead of relying on the default buffer filling.
- Fix the cleanup comment: closing the read end unblocks the export via a broken
pipe, it does not drain it to completion.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37ad1fd7-a452-4056-a8cc-e91cf7870a60
* Use bespoke interfaces to communicate with wsldevicehost
* pr feedback: remove UTF-8 BOM and better device teardown/modify race handling
* pr feedback: remove extra rpcrt4; fix test failures
---------
Co-authored-by: Brian Perkins <bperkins@ntdev.microsoft.com>
This PR reorganize the wsl cgroup with the follow structure:
```
# When systemd is enabled
/ # critical wsl processes live in root with no resource limit.
--wsl-user # resource limited cgroup
-- non-distro # for processes not belonging to a distro, like plugins
-- distro-<init pid> # per distro root
-- non-systemd # for non systemd user processes
-- systemd # for systemd and it's cgroup tree
# When systemd is not enabled
/ # critical wsl processes live in root with no resource limit.
--wsl-user # resource limited cgroup
-- non-distro # for processes not belonging to a distro, like plugins
-- distro-<init pid> # per distro cgroup
```
The wsl-user cgroup has memory.max and cpu.max set so it can only take max - 32MiB of RAM and max - 0.01 CPU cores. Effectively reserving 32MiB RAM and 0.01 cores for processes not under this cgroup.
* Read /etc/locale.conf when configuring the distro locale
ConfigUpdateLanguage only read /etc/default/locale to populate the $LANG
environment variable. That path is used by Debian/Ubuntu, but systemd-based
distributions (Fedora, Arch, openSUSE, ...) store the locale in
/etc/locale.conf instead, so $LANG was never set on those distros.
Check both locations and use the first one that exists. Both files share the
same "LANG=" line format, so the existing parsing is reused unchanged.
Fixes#13207
* Add unit test for distro locale configuration
Cover the ConfigUpdateLanguage code path that populates $LANG from the distro
locale file. The test creates the locale files in the test distro and verifies
that $LANG is set correctly for each supported layout:
- only /etc/default/locale present (Debian/Ubuntu)
- only /etc/locale.conf present (Fedora, Arch, openSUSE, ...)
- both present, confirming /etc/default/locale takes precedence
The winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync function does not accept folders with hidden or system attributes. To solve that, this PR avoids the GetFolderFromPathAsync call and opens the file stream directly.
* Rename VirtioProxy networking mode to Consomme
Rename the VirtioProxy networking mode to Consomme across the C++/IDL/Linux
symbols and the networking engine class/files (VirtioNetworking ->
ConsommeNetworking). The .wslconfig networkingMode parser still accepts the
legacy "virtioproxy" string as an alias. Adds a docs section linking to
OpenVMM's consomme project, where the name comes from.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR feedback: scrub remaining virtio proxy refs, doc path, locked string
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Save state
* Save state
* Save state
* Save state
* Save state
* Prepare for PR
* Fix test hang
* Apply PR suggestions
* Apply PR feedback
* Fix typo
* Connect named pipe by default
* Handle Connect correctly
* Format
* Apply PR feedback
* Fix MoveDistribution E_ACCESSDENIED when setVhdOwner fails under impersonation (#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>
* Add test for MoveDistribution with admin-owned VHD (#40716)
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>
---------
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Improves virtiofs and VirtioProxy performance by giving each virtio
device its own SWIOTLB aperture instead of sharing a single global
pool. The guest kernel reserves a contiguous physical range at boot,
publishes the (base, size), and the host programs a matching
per-device aperture in wsldevicehost.
1. The WSL kernel allocates a contiguous range at boot
(alloc_contig_pages with __GFP_DMA32 | __GFP_ZERO) and exposes
the chosen physical (base, size) under
/sys/bus/vmbus/drivers/hv_pci/swiotlb_{base,size}
2. mini_init (WSL2) and the WSLC init handler read those sysfs files
and return the values in LX_INIT_GUEST_CAPABILITIES and
WSLC_GET_GUEST_CAPABILITIES_RESULT respectively.
3. WslCoreVm::ReadGuestCapabilities and
WSLCVirtualMachine::ReadGuestCapabilities capture the values.
WSLC forwards them to wslservice via the new
HcsVirtualMachine::ApplyGuestCapabilities IDL method (with a
WSLCGuestCapabilities struct so future kernel-published values
can be added without bumping the interface IID).
4. Both VM owners format "swiotlb=0x{base:x},{size}" once into
m_swiotlbOption and pass it verbatim to AddGuestDevice /
AddSharePath for every virtiofs share and virtio-net adapter
(VirtioProxy networking). wsldevicehost consumes the token and
creates the per-device SWIOTLB aperture.
If the kernel does not publish the sysfs files (older kernel) both
values come back as zero, the host omits the device-options token,
and the WSL2 path emits a one-time user warning via
MessageSwiotlbKernelUnsupported so users understand why performance
is degraded. (The WSLC path always uses the bundled kernel, so the
warning does not apply there.)
Other changes:
* Bump Microsoft.WSL.Kernel to 6.18.26.3-1, which is the first
official kernel that publishes the hv_pci swiotlb_{base,size}
sysfs files this PR consumes.
* Bump Microsoft.WSL.DeviceHost to 1.2.29-0 for the device-side
SWIOTLB aperture support.
* Default pool sizing moves to helpers::ComputeDefaultSwiotlbConfig
and is only requested on the kernel command line when a virtio
device that needs bounce buffers (VirtioFs / Virtio9p /
VirtioProxy) is in use.
* Telemetry: emit GuestKernelInfo / WSLCReadGuestCapabilities /
WSLCApplyGuestCapabilities events with the kernel-chosen base
and size so we can validate the handshake in CI.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Windows interop in every running WSL2 distro silently breaks whenever a
sibling systemd-enabled distro shuts down, surfacing to users as:
/bin/bash: line 1: /mnt/c/Windows/system32/cmd.exe:
cannot execute binary file: Exec format error
Root cause: `systemd-shutdown` calls `disable_binfmt()` during clean
shutdown, which writes `-1` to `/proc/sys/fs/binfmt_misc/status`.
binfmt_misc is a single kernel-global registry shared across the WSL VM
(distros do not isolate it via a user namespace), so that one write wipes
every entry -- including WSLInterop -- for every running distro.
Fix: each per-distro init bind-mounts a read-only file over
`/proc/sys/fs/binfmt_misc/status` in its own mount namespace before
exec'ing the distro's init. systemd-shutdown's wipe write then fails with
EROFS; systemd logs a warning and continues normally (its
`binfmt_mounted_and_writable()` helper deliberately tolerates this
case). Per-entry unregister (`echo -1 > .../<name>`) and runtime
registration (`echo ... > .../register`) target different files and are
unaffected, so callers retain full control over their own binfmt entries.
`LockBinfmtStatusReadOnly` is idempotent: it bails early if binfmt_misc
isn't mounted, no-ops if `/status` already resolves to our lock file,
and recovers from a stale foreign mount via `umount2(MNT_DETACH)`
followed by a retry. The existing `[boot] protectBinfmt` wsl.conf key
(default true) now controls the bind-mount and acts as a kill switch for
users who want to manage binfmt_misc themselves.
WSLInterop is also re-registered from mini_init with the `F`
(fix-binary) flag so the interpreter is opened at registration time and
remains valid across mount namespaces.
Tests:
* `BinfmtStatusIsLocked` -- mechanism test: `/status` is its own
mountpoint, writes fail with EROFS, WSLInterop survives the wipe
attempt, /register and per-entry unregister still work, and the
`protectBinfmt=false` kill switch removes the bind-mount.
* `BinfmtSurvivesDistroTermination` -- end-to-end regression test:
imports a systemd-enabled peer distro, terminates it, and asserts
that the primary distro's Windows interop still works.
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>