Bundle and mount Linux kernel headers in WSL2 distros#40551
Open
benhillis wants to merge 3 commits into
Open
Conversation
benhillis
commented
May 15, 2026
benhillis
commented
May 15, 2026
benhillis
commented
May 15, 2026
benhillis
commented
May 15, 2026
benhillis
commented
May 15, 2026
benhillis
commented
May 15, 2026
Member
Author
|
/azp run wsl-github-pr |
|
Azure Pipelines successfully started running 1 pipeline(s). |
The Microsoft.WSL.Kernel nuget package ships UAPI headers alongside the kernel image. Stage those headers next to the kernel binary at build time and mount them read-only into every WSL2 distro via a 9p share at the standard Debian/Ubuntu paths (/usr/src/linux-headers-$(uname -r) plus a /lib/modules/$(uname -r)/build symlink). A new kernelHeaders= .wslconfig setting follows the same pattern as kernelModules: empty defaults to the bundled headers, "none" disables, or a custom path can be supplied. Surfaced in the wslsettings Developer page alongside the existing kernel/kernelModules controls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- mini_init: drop redundant comments and the LOG_ERROR for MountPlan9 (UtilMount already logs via WIL); promote uname() to THROW_LAST_ERROR_IF. - distro init: drop the explanatory block comment, drop the "source" symlink (only "build" is the universal entry point queried by out-of-tree tooling), and use THROW_LAST_ERROR_IF for uname() under the existing CATCH_LOG(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The PR-feedback commit dropped creation of the
`/lib/modules/<release>/source` symlink (only `/build` is needed),
but a few sites still referenced the removed symlink:
- test/windows/UnitTests.cpp: KernelHeaders test still asserted
`test -L /lib/modules/$(uname -r)/source`, causing the unit test
to fail.
- src/linux/init/main.cpp: stale `{build,source} symlinks` comment.
- src/windows/service/exe/WslCoreVm.cpp: stale `/build and /source
symlinks` comment.
- doc/docs/technical-documentation/boot-process.md: stale
`{build,source}` reference in the boot-process docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7e4cba5 to
57ce9b2
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds first-class support for shipping Linux kernel UAPI headers with WSL and making them available inside every WSL2 distro by default (mirroring existing kernel modules plumbing). It introduces a new .wslconfig setting (wsl2.kernelHeaders) plus service/guest/UI changes to stage, package, share, mount, and validate the headers.
Changes:
- Build/MSI: stage and package a
linux-headers/directory alongside the kernel and include it in the MSI install undertools/linux-headers. - Service/Config/UI: add a new
wsl2.kernelHeaderssetting, expose it in wslsettings, and validate it alongside existing custom kernel/kernelModules settings. - Guest init: add a new plan9 share and mount flow that places headers under
/usr/src/linux-headers-$(uname -r)/includeand creates/lib/modules/$(uname -r)/buildsymlink.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| UserConfig.cmake.sample | Adds dev-mode symlink staging for linux-headers into WSL_DEV_BINARY_PATH. |
| CMakeLists.txt | Defines WSL_KERNEL_HEADERS_PATH for dev builds to point at the staged headers directory. |
| msipackage/package.wix.in | Packages tools/linux-headers into the MSI (non-dev installs) and wires it into the main feature. |
| src/windows/common/WslCoreConfig.h | Adds wsl2.kernelHeaders config key and includes it in config serialization/reflection. |
| src/windows/common/WslCoreConfig.cpp | Parses wsl2.kernelHeaders, applies policy override, and validates safe-mode behavior. |
| src/windows/inc/WslCoreConfigInterface.h | Extends the public config-entry enum with KernelHeadersPath. |
| src/windows/libwsl/WslCoreConfigInterface.cpp | Adds get/set support for KernelHeadersPath through the libwsl config interface. |
| src/windows/service/exe/WslCoreVm.h | Adds state to track whether kernel headers should be mounted. |
| src/windows/service/exe/WslCoreVm.cpp | Resolves/validates headers path, adds a read-only plan9 share, and passes a mount flag to mini-init. |
| src/shared/inc/lxfsshares.h | Defines the new plan9 share name (kernel_headers). |
| src/shared/inc/lxinitshared.h | Adds env var names and a new MountKernelHeaders field to the mini-init config message. |
| src/linux/init/main.cpp | Mounts the kernel headers plan9 share and passes a target mount path to distro init via env vars. |
| src/linux/init/config.cpp | Moves the temporary headers mount to /usr/src/linux-headers-…/include and creates /lib/modules/.../build symlink. |
| test/windows/Common.h | Adds kernelHeaders to the test config defaults structure. |
| test/windows/Common.cpp | Emits kernelHeaders= into generated .wslconfig test content. |
| test/windows/UnitTests.cpp | Adds a KernelHeaders WSL2 unit test for default mount + error cases. |
| src/windows/wslsettings/LibWsl.cs | Adds KernelHeadersPath entry to the managed config enum used by the UI. |
| src/windows/wslsettings/Contracts/Services/IWslConfigService.cs | Marks KernelHeadersPath as a string-valued config setting in the UI layer. |
| src/windows/wslsettings/ViewModels/Settings/DeveloperViewModel.cs | Adds CustomKernelHeadersPath binding to the Developer page VM. |
| src/windows/wslsettings/Views/Settings/DeveloperPage.xaml | Adds the Developer page expander for kernel headers path editing/browsing. |
| src/windows/wslsettings/Views/Settings/DeveloperPage.xaml.cs | Adds a folder picker handler for selecting a headers directory. |
| src/windows/wslsettings/Helpers/RuntimeHelper.cs | Adds a WinUI folder picker helper (PickSingleFolderAsync). |
| src/windows/wslsettings/Views/Settings/SettingsApplyHelper.cs | Adds display-name mapping for the new kernel headers setting in pending-changes UI. |
| localization/strings/en-US/Resources.resw | Adds user-facing strings for validation errors and the new settings UI text. |
| doc/docs/technical-documentation/boot-process.md | Documents the new “mount bundled kernel headers” guest configuration behavior. |
Comments suppressed due to low confidence (2)
src/windows/service/exe/WslCoreVm.cpp:294
- If the bundled headers directory is missing/corrupt, this code will throw MessageCustomKernelHeadersNotFound(), which says the path was specified via 'wsl2.kernelHeaders' in the user’s .wslconfig. In the default-kernel + empty setting case the user didn’t specify anything, so the error is misleading and also blocks WSL startup. Consider distinguishing user-specified vs default-resolved paths (or treating missing bundled headers as a non-fatal warning that disables the mount).
if (m_vmConfig.KernelHeadersPath.empty())
{
if (m_defaultKernel)
{
#ifdef WSL_KERNEL_HEADERS_PATH
m_vmConfig.KernelHeadersPath = std::wstring(TEXT(WSL_KERNEL_HEADERS_PATH));
#else
m_vmConfig.KernelHeadersPath = m_installPath / LXSS_TOOLS_DIRECTORY / L"linux-headers";
#endif
}
}
else if (m_defaultKernel)
{
THROW_HR_WITH_USER_ERROR(WSL_E_CUSTOM_KERNEL_NOT_FOUND, Localization::MessageMismatchedKernelHeadersError());
}
if (!m_vmConfig.KernelHeadersPath.empty())
{
if (!wsl::windows::common::filesystem::FileExists(m_vmConfig.KernelHeadersPath.c_str()))
{
THROW_HR_WITH_USER_ERROR(
WSL_E_CUSTOM_KERNEL_NOT_FOUND,
Localization::MessageCustomKernelHeadersNotFound(
wsl::windows::common::helpers::GetWslConfigPath(m_userToken.get()), m_vmConfig.KernelHeadersPath.c_str()));
}
m_mountKernelHeaders = true;
}
src/windows/service/exe/WslCoreVm.cpp:292
- KernelHeadersPath is expected to be a directory tree, but this validation only checks GetFileAttributes != INVALID (via FileExists), so a regular file path would pass and later Plan9 sharing/mounting may fail. Consider validating that the path exists and is a directory (FILE_ATTRIBUTE_DIRECTORY) to fail fast with a clearer user error.
if (!m_vmConfig.KernelHeadersPath.empty())
{
if (!wsl::windows::common::filesystem::FileExists(m_vmConfig.KernelHeadersPath.c_str()))
{
THROW_HR_WITH_USER_ERROR(
WSL_E_CUSTOM_KERNEL_NOT_FOUND,
Localization::MessageCustomKernelHeadersNotFound(
wsl::windows::common::helpers::GetWslConfigPath(m_userToken.get()), m_vmConfig.KernelHeadersPath.c_str()));
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bundles the Linux kernel UAPI headers shipped in the
Microsoft.WSL.Kernelnuget package and mounts them read-only into every WSL2 distro by default. Pattern mirrors the existingkernelModulesplumbing.What it does
linux-headers/next to the kernel image in the dev binary path (CMakeLists.txt,UserConfig.cmake.sample) and packages them in the MSI (msipackage/package.wix.in).kernelHeaders=setting in.wslconfig(empty = bundled default, or a custom path). Validated alongsidekernel/kernelModulesinWslCoreVm./usr/src/linux-headers-$(uname -r)with a/lib/modules/$(uname -r)/buildsymlink so out-of-tree module builds and tools that key offuname -rfind them.Testing
KernelHeadersTAEF unit test covers default-mount, custom path, and validation errors./usr/src/linux-headers-*populated andmake headers_checkworks against it.