Skip to content

Bundle and mount Linux kernel headers in WSL2 distros#40551

Open
benhillis wants to merge 3 commits into
masterfrom
benhillis/kernel-headers
Open

Bundle and mount Linux kernel headers in WSL2 distros#40551
benhillis wants to merge 3 commits into
masterfrom
benhillis/kernel-headers

Conversation

@benhillis
Copy link
Copy Markdown
Member

@benhillis benhillis commented May 15, 2026

Summary

Bundles the Linux kernel UAPI headers shipped in the Microsoft.WSL.Kernel nuget package and mounts them read-only into every WSL2 distro by default. Pattern mirrors the existing kernelModules plumbing.

What it does

  • Build: stages 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).
  • Service: new kernelHeaders= setting in .wslconfig (empty = bundled default, or a custom path). Validated alongside kernel/kernelModules in WslCoreVm.
  • Guest: mounted via 9p at /usr/src/linux-headers-$(uname -r) with a /lib/modules/$(uname -r)/build symlink so out-of-tree module builds and tools that key off uname -r find them.
  • UI: Developer page in wslsettings exposes the path with the same UX as the kernel/kernelModules controls.

Testing

  • New KernelHeaders TAEF unit test covers default-mount, custom path, and validation errors.
  • Manually verified a fresh distro shows /usr/src/linux-headers-* populated and make headers_check works against it.

Comment thread src/linux/init/config.cpp Outdated
Comment thread src/linux/init/config.cpp Outdated
Comment thread src/linux/init/config.cpp Outdated
Comment thread src/linux/init/main.cpp Outdated
Comment thread src/linux/init/main.cpp Outdated
Comment thread src/linux/init/main.cpp Outdated
@benhillis benhillis marked this pull request as ready for review May 15, 2026 02:47
@benhillis benhillis requested a review from a team as a code owner May 15, 2026 02:47
@benhillis
Copy link
Copy Markdown
Member Author

/azp run wsl-github-pr

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Ben Hillis and others added 3 commits May 16, 2026 11:45
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>
Copilot AI review requested due to automatic review settings May 16, 2026 18:49
@benhillis benhillis force-pushed the benhillis/kernel-headers branch from 7e4cba5 to 57ce9b2 Compare May 16, 2026 18:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 under tools/linux-headers.
  • Service/Config/UI: add a new wsl2.kernelHeaders setting, 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)/include and creates /lib/modules/$(uname -r)/build symlink.

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()));
            }

Comment thread src/linux/init/config.cpp
Comment thread src/windows/service/exe/WslCoreVm.cpp
Comment thread test/windows/UnitTests.cpp
Comment thread test/windows/UnitTests.cpp
@benhillis benhillis added msix Installer issue. kernel WSL kernel labels May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernel WSL kernel msix Installer issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants