Workaround that stopped the Luaf (luafv.sys) leak: disable UAC file virtualization
We found a workaround that stops the Luaf paged pool leak completely. We disable UAC file and registry virtualization, so the luafv filter driver no longer loads at boot. UAC itself stays enabled, and only the legacy "VirtualStore" redirection is turned off.
Results
- On a test machine (build 26200.9550), Luaf dropped to 0 after the change and reboot. Paged pool stayed at about 300–460 MB over more than 20 hours, compared with several GB per day before.
- A second machine (build 26200.9711, 8 GB RAM) reached 434 MB of Luaf within 3 hours before the change. After the change it stayed clean, and SQL Server memory waits dropped to about 0.
- The setting survives later reboots.
What we learned about the cause
- Machines with the original luafv.sys 10.0.26100.1 do not leak, even with virtualization on.
- luafv.sys 10.0.26100.8875 (build 26200.9550 and later) leaks, and so does 10.0.26100.9818 (26H2, build 26300.9818). The leak is still present in the newest version we have seen.
- So the leak is not caused only by KB5127648. Uninstalling KB5127648 does not fix it, because the leaking luafv.sys came in with an earlier cumulative update.
What we learned about the cause
- Machines with the original luafv.sys 10.0.26100.1 do not leak, even with virtualization on.
- luafv.sys 10.0.26100.8875 (build 26200.9550 and later) leaks, and so does 10.0.26100.9818 (26H2, build 26300.9818). The leak is still present in the newest version we have seen.
- So the leak is not caused only by KB5127648. Uninstalling KB5127648 does not fix it, because the leaking luafv.sys came in with an earlier cumulative update.
Script (run in an elevated PowerShell, then reboot)
# Workaround for the Luaf (luafv.sys) kernel paged pool leak - Step 1
# Turns off UAC file and registry virtualization (EnableVirtualization = 0). UAC itself
# A reboot is required afterwards. To undo: set EnableVirtualization back to 1 and reboot.
# Usage (elevated PowerShell): powershell -ExecutionPolicy Bypass -File .\Luaf-Workaround-Step1.ps1
# Writes a log to C:\ProgramData\LuafWorkaround\
cipal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host 'Run this script as Administrator.' -ForegroundColor Red; exit 1
}
$folder = Join-Path $env:ProgramData 'LuafWorkaround'
New-Item -ItemType Directory -Path $folder -Force | Out-Null
$log = Join-Path $folder ("Step1_{0}_{1}.txt" -f $env:COMPUTERNAME, (Get-Date -Format 'yyyyMMdd_HHmm'))
$key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
$nt = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
$drv = (Get-Item "$env:SystemRoot\System32\drivers\luafv.sys").VersionInfo
& {
"Computer: $env:COMPUTERNAME Date: $(Get-Date) Step 1"
"Windows build: $($nt.CurrentBuild).$($nt.UBR) luafv.sys: {0}.{1}.{2}.{3}" -f $drv.FileMajorPart, $drv.FileMinorPart, $drv.FileBuildPart, $drv.FilePrivatePart
"Before: EnableVirtualization = " + (Get-ItemProperty $key -Name EnableVirtualizatioue).EnableVirtualization +
" luafv Start = " + (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\luafv').Start
Set-ItemProperty -Path $key -Name EnableVirtualization -Value 0 -Type DWord
"After: EnableVirtualization = " + (Get-ItemProperty $key -Name EnableVirtualization).EnableVirtualization
""
"DONE. Reboot now (shutdown /r /t 0). After the reboot, check that luafv is STOPPED: sc.exe query luafv"
} | Tee-Object -FilePath $log
"`nLog saved to: $log"
After the reboot
- Run sc.exe query luafv. It should show STOPPED. On all our machines, this setting alone was enough.
- If it still shows RUNNING, run sc.exe config luafv start= disabled and reboot again.
- Check the Luaf tag a few hours after boot, for example with poolmon from the WDK. It should stay at 0 or close to 0.
To undo: set EnableVirtualization = 1, run sc.exe config luafv start= auto, and reboot.
This is a workaround until Microsoft ships a fixed luafv.sys. If anyone from Microsoft can confirm that it is supported, that would help.