Skip to content

Instantly share code, notes, and snippets.

@steffengy
Last active March 24, 2024 13:58
Show Gist options
  • Star 58 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save steffengy/62a0b5baa124830a4b0fe4334ccc2606 to your computer and use it in GitHub Desktop.
Save steffengy/62a0b5baa124830a4b0fe4334ccc2606 to your computer and use it in GitHub Desktop.
WSL Nested Virtualization

DISCLAIMER: This can corrupt your WSL or whatever, so no guarantees this works and does what your want. Use at your own risk. Update 02/2023: Added wsl --shutdown in script. Known to work on Intel (AMD likely needs Win11) 21H2 19044.2486

Prereqs:

  • Install WinDbg (Preview from the store)
  1. You might have to build a custom WSL kernel with KVM support. This seems to be unnecessary with If your kernel is >=v4.19.104.
touch .scmversion
make menuconfig KCONFIG_CONFIG=Microsoft/config-wsl
# Virtualization -> KVM & Intel KVM
# Processor type Features -> /dev/cpu/* /msr support
make -j8 KCONFIG_CONFIG=Microsoft/config-wsl
  1. Run start-wsl.bat. If you use a custom kernel, edit it in your wsl config or uncomment the LinuxKernelDirect line in script.js. Thanks to @offlinehacker, who increased automatization of this part!
  2. In WSL run sudo kvm-ok and be happy.
REM Ensure vmcompute.exe is running
wsl.exe -e true
REM Listen for and Intercept utility vm creation
start Windbgx.exe -pn vmcompute.exe -c "bp vmcompute!Marshal::JsonParser::JsonParser;g;.scriptrun %CD%\script.js;.scriptrun %CD%\script.js;.scriptrun %CD%\script.js;.detach;qq"
REM Ensure WSL Utility VM is not running (hopefully windb starts up fast enough...)
net stop LxssManager
net start LxssManager
rem might be needed for newer builds
wsl --shutdown
echo "Press Enter if the debugger is running"
pause
REM Start WSL
start wsl.exe
"use strict";
function initializeScript()
{
return [new host.apiVersionSupport(1, 3)];
}
function continueExecution() {
var cmd = "g";
host.diagnostics.debugLog(cmd);
var lines = host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
for (var line of lines) host.diagnostics.debugLog(" ", line, "\n");
}
function invokeScript()
{
/* bp vmcompute!Marshal::JsonParser::JsonParser */
var cmd;
var lines;
// 1. Check if WSL
var magic = host.memory.readWideString(host.currentThread.Registers.User.rdx, 14);
if (magic == '{"Owner":"WSL"') {
host.diagnostics.debugLog("IS WSL\n");
} else {
host.diagnostics.debugLog("IS NOT WSL request\n");
return continueExecution();
}
// dump length and read machine spec json
var len = host.currentThread.Registers.User.r8;
host.diagnostics.debugLog("String length: ", len, " dumping memory: ", host.currentThread.Registers.User.rdx, "\n");
var jsonString = host.memory.readWideString(host.currentThread.Registers.User.rdx, len);
host.diagnostics.debugLog("Before: ", jsonString, "\n");
// parse and modify machine spec json
var machineSpec = JSON.parse(jsonString);
machineSpec.VirtualMachine.ComputeTopology.Processor.ExposeVirtualizationExtensions = true;
// machineSpec.VirtualMachine.Chipset.LinuxKernelDirect.KernelFilePath = "D:\\temp\\vmlinux.bin";
var machineSpecJson = JSON.stringify(machineSpec);
host.diagnostics.debugLog("After: ", JSON.stringify(machineSpec), "\n");
var newLen = "0x" + machineSpecJson.length.toString(16);
// allocate memory
cmd = ".dvalloc 4096"
lines = host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
var addr = lines[0];
var addrParts = addr.split(" ");
var freeMem = addrParts[addrParts.length-1].replace("`", "");
host.diagnostics.debugLog("Allocated ", freeMem, "\n");
// write memory
host.diagnostics.debugLog("Writing memory ", freeMem, " length: ", newLen, "\n");
cmd = "eu " + freeMem + ' "' + machineSpecJson.split("\\").join("\\\\").split('"').join('\\"') + '"';
lines = host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
for (var line of lines) host.diagnostics.debugLog(" ", line, "\n");
// patch rdx with new memory address
var cmd = "r @rdx = " + freeMem;
host.diagnostics.debugLog(cmd);
var lines = host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
for (var line of lines) host.diagnostics.debugLog(" ", line, "\n");
// patch r8 with new memory size
var cmd = "r @r8 = " + newLen;
host.diagnostics.debugLog(cmd);
var lines = host.namespace.Debugger.Utility.Control.ExecuteCommand(cmd)
for (var line of lines) host.diagnostics.debugLog(" ", line, "\n");
return continueExecution();
}
@Clockiscool1234
Copy link

this crash my windows

@ZeppLu
Copy link

ZeppLu commented Jun 16, 2023

For anyone failed with prompt like

虚拟机监控程序无法执行此操作,因为指定的参数无效。 // Listerally translates to "hypervisor cannot execute this operation due to invalid arguments
Error code: Wsl/Service/CreateInstance/CreateVm/0xc0350005

Your WSL2 version may to too new to use this hack. To validate, run wsl --version, if you see some versioning info rather than help text, then read on.

You should downgrade WSL2 to some ancient version by:

$pkg = Get-AppxPackage MicrosoftCorporationII.WindowsSubsystemforLinux -AllUsers
Remove-AppxPackage $pkg -AllUsers

Then rerun wsl --version, if help text appears, then congrats, you are good to use this hack.

@Clockiscool1234
Copy link

plus my system is home edition

@ml-think-tanks
Copy link

wsl --version

nice

@lsp0701
Copy link

lsp0701 commented Oct 25, 2023

WSL2 version: 2.0.4.0

i run the script,but not work

any plan to support ?

But i can get it work for ancient version of WSL2 as @ZeppLu mentioned

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