microsoft / microsoft/WSL

Nested virtualization unconditionally disabled on Windows 10 in lifted WSL (regression from inbox WSL2)

Open
#40,735 6 comments 1 reaction 0 assignees View on GitHub
bug hypervisor-platform wsl2
Dominant language
C++
Stars
33.7k
Forks
1.8k
Avg merge
3d 17h
Merged PRs (30d)
116

Description

This report covers a behavior on Windows 10 hosts where `nestedVirtualization=true` in `.wslconfig` is silently overridden, even on CPUs that support nested virtualization.

### Windows Version

```
Microsoft Windows [Version 10.0.19045.7291]
```

### WSL Version

```
WSL version: 2.8.11.17
Kernel version: 6.18.26.3-1
WSLg version: 1.0.77
MSRDC version: 1.2.6676
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26100.1-240331-1435.ge-release
Windows version: 10.0.19045.7291
Commit: 9ab38e95
```

This was a local build of `microsoft/WSL` at commit `9ab38e9`.

### Are you using WSL 1 or WSL 2?

- [x] WSL 2

### Kernel Version

```
Linux DESKTOP-67D2DFE 6.18.26.3-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Wed May 27 22:03:21 UTC 2026 x86_64
```

### Distro Version

Oracle Linux Server 9.7. Also reproduced on Ubuntu 24.04.

### Other Software

- Host CPU: Intel Core i5-6300U (Skylake-U). VMCS Shadowing is supported on Haswell and later, so this CPU is hardware-capable of nested virtualization.
- Hyper-V root partition is up. `Microsoft-Hyper-V`, `HypervisorPlatform`, and `VirtualMachinePlatform` are all enabled.

### Repro Steps

1. On a Windows 10 22H2 host with an Intel CPU that supports VMCS Shadowing, install WSL from the Microsoft Store or from a build of the open-source repo.
2. Create `%USERPROFILE%\.wslconfig` with:
```ini
[wsl2]
nestedVirtualization=true
```
3. Run `wsl --shutdown`, then start any WSL2 distro.
4. Inside the distro, run `ls /dev/kvm` and `grep -E "vmx|svm" /proc/cpuinfo`.

### Expected Behavior

`/dev/kvm` exists inside the WSL2 VM and `vmx` is present in `/proc/cpuinfo`. The `nestedVirtualization=true` setting in `.wslconfig` is honored on every host whose CPU supports nested virtualization. This was the behavior of the in-box WSL2 on Windows 10 19044 and 19045.

### Actual Behavior

`/dev/kvm` is absent and `vmx` is not present, regardless of the `.wslconfig` setting. The lifted WSL service skips the HCS processor-feature lookup on Windows 10 and writes `ExposeVirtualizationExtensions = false` into the compute system config.

The code is at [`src/windows/service/exe/WslCoreVm.cpp` lines 1508-1530](https://github.com/microsoft/WSL/blob/9ab38e9/src/windows/service/exe/WslCoreVm.cpp#L1508-L1530):

```cpp
// N.B. This is done because arm64 and some older amd64 processors do not support nested virtualization.
// Nested virtualization not supported on Windows 10.
if (m_vmConfig.EnableNestedVirtualization)
{
try
{
if (wsl::windows::common::helpers::IsWindows11OrAbove())
{
const auto& processorFeatures = wsl::windows::common::hcs::GetProcessorFeatures();
auto feature = std::find(processorFeatures.begin(), processorFeatures.end(), "NestedVirt");
m_vmConfig.EnableNestedVirtualization = (feature != processorFeatures.end());
}
else
{
m_vmConfig.EnableNestedVirtualization = false;
}

vmSettings.ComputeTopology.Processor.ExposeVirtualizationExtensions = m_vmConfig.EnableNestedVirtualization;
if (!m_vmConfig.EnableNestedVirtualization)
{
EMIT_USER_WARNING(wsl::shared::Localization::MessageNestedVirtualizationNotSupported());
}
}
...
}
```

The check is on the Windows major version, not on the underlying CPU. A Win10 host with an i9-13900K is treated the same as a host with an Atom that genuinely cannot do nested virtualization. The HCS feature query that already exists for the Win11 path (`hcs::GetProcessorFeatures()` looking for `"NestedVirt"`) would answer the same question correctly on Win10.

### When the gate landed

The disable-on-Win10 effect was present at the initial open-source release. Commit [`697572d6`](https://github.com/microsoft/WSL/commit/697572d664c9371abbc53cab9cf7b4b32be1980e) (2025-05-15, "Initial open source commit for WSL") introduced the file with `processorFeatures` retrieval already wrapped in `if (IsWindows11OrAbove())`. On Win10 the vector stayed empty, the subsequent `std::find` failed, and `EnableNestedVirtualization` collapsed to `false`. Same observable result, just implicit.

Commit [`6f47fa9b`](https://github.com/microsoft/WSL/commit/6f47fa9b202fe41704e3c559b38b33a64aaa1387) ([#13971](https://github.com/microsoft/WSL/pull/13971), 2026-01-06, "diagnostics: improve logging of hcs helper utilities on debug builds") made the disable explicit by moving the HCS lookup and the `find` inside the `IsWindows11OrAbove()` block and adding an `else { EnableNestedVirtualization = false; }` branch.

### Why I am calling this a regression

The in-box WSL2 that shipped in Windows 10 builds 19041 through 19045 exposed `vmx` to the WSL2 guest on hosts whose CPUs supported nested virtualization. After moving to the lifted WSL (Microsoft Store or open-source build), the same hardware on the same Windows 10 22H2 host no longer exposes nested virtualization, even with `nestedVirtualization=true` in `.wslconfig`.

### Suggested fixes

In increasing order of effort:

1. Remove the `IsWindows11OrAbove()` gate. Let `hcs::GetProcessorFeatures()` decide on all supported Windows versions. The existing `MessageNestedVirtualizationNotSupported` warning is already in place for hosts where HCS reports no `NestedVirt` feature.
2. Keep the gate but respect `nestedVirtualization=true` from `.wslconfig` as an explicit opt-in override on Windows 10, with a logged warning that the path is unsupported. Users on compatible hardware get the feature back. Users on incompatible hardware see a clear message instead of a silent disable.
3. Document the Windows 10 limitation in the [`.wslconfig` reference](https://learn.microsoft.com/en-us/windows/wsl/wsl-config) and in [Set up a WSL development environment](https://learn.microsoft.com/en-us/windows/wsl/setup/environment). The current docs do not mention that `nestedVirtualization` is ignored on Win10.

Happy to test a patch on this hardware.

### Diagnostic Logs

None attached. The behavior is fully reproducible from the source path above. If a service trace would help, glad to capture one with `wsl --debug-shell` or similar.

Contributor guide

Open the contributing guide

Research direction

Start in src/windows/service/exe/WslCoreVm.cpp around lines 1508-1530 and compare the Windows 10 and Windows 11 paths for hcs::GetProcessorFeatures(). Reproduce the issue with nestedVirtualization=true on Windows 10, then verify completion by checking that /dev/kvm exists and vmx appears in /proc/cpuinfo on supported hardware without breaking the unsupported-CPU warning path.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.