From cdccade13c6d4a0933d9dca5a394383d8fd32f88 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 16:51:55 +0800 Subject: [PATCH 1/8] Fix malicious client code could cause huge allocation --- src/linux/init/GnsPortTracker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux/init/GnsPortTracker.cpp b/src/linux/init/GnsPortTracker.cpp index fb1383f77b..73d0be841f 100644 --- a/src/linux/init/GnsPortTracker.cpp +++ b/src/linux/init/GnsPortTracker.cpp @@ -375,7 +375,7 @@ std::optional GnsPortTracker::GetCallInfo( uint64_t CallId, pid_t Pid, int Arch, int SysCallNumber, const gsl::span& Arguments) { auto ParseSocket = [&](int Socket, size_t AddressPtr, size_t AddressLength) -> std::optional { - if (AddressLength < sizeof(sockaddr)) + if (AddressLength < sizeof(sockaddr) || AddressLength > sizeof(sockaddr_storage)) { return {{{}, {}, CallId}}; // Invalid sockaddr. Let it go through. } From cd5432055bff50db25b27d04cd99f90a37947b56 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 17:12:11 +0800 Subject: [PATCH 2/8] add the missing m_id assignment --- src/windows/service/exe/WslCoreGuestNetworkService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/windows/service/exe/WslCoreGuestNetworkService.cpp b/src/windows/service/exe/WslCoreGuestNetworkService.cpp index 5fae67f0ac..b79e112547 100644 --- a/src/windows/service/exe/WslCoreGuestNetworkService.cpp +++ b/src/windows/service/exe/WslCoreGuestNetworkService.cpp @@ -92,6 +92,7 @@ void wsl::core::networking::GuestNetworkService::CreateGuestNetworkService( TraceLoggingHResult(result, "result"), TraceLoggingValue(error.is_valid() ? error.get() : L"null", "errorString")); THROW_IF_FAILED_MSG(result, "%ls", error.get()); + m_id = VmId; m_guestNetworkServiceCallback = windows::common::hcs::RegisterGuestNetworkServiceCallback(m_service, Callback, CallbackContext); SetGuestNetworkServiceState(hns::GuestNetworkServiceState::Bootstrapping); From 3b692c77761c3159f29ce88b8ffdb5998723515f Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 17:18:15 +0800 Subject: [PATCH 3/8] avoid mini init from erasing link target from a distro --- src/linux/init/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/linux/init/main.cpp b/src/linux/init/main.cpp index b95fee1fa3..8188813b61 100644 --- a/src/linux/init/main.cpp +++ b/src/linux/init/main.cpp @@ -2170,7 +2170,9 @@ Return Value: try { - wil::unique_fd InitFd{open(Target, (O_CREAT | O_WRONLY | O_TRUNC), 0755)}; + THROW_LAST_ERROR_IF(unlink(Target) < 0 && errno != ENOENT); + + wil::unique_fd InitFd{open(Target, (O_CREAT | O_EXCL | O_WRONLY), 0755)}; THROW_LAST_ERROR_IF(!InitFd); THROW_LAST_ERROR_IF(mount(LX_INIT_PATH, Target, nullptr, (MS_RDONLY | MS_BIND), nullptr) < 0); From d6082dddfdf2ef2675c12cd513278df240c4c914 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 18:40:13 +0800 Subject: [PATCH 4/8] call delete endpoint for the moved away endpoint --- .../service/exe/WslCoreNetworkEndpoint.h | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/windows/service/exe/WslCoreNetworkEndpoint.h b/src/windows/service/exe/WslCoreNetworkEndpoint.h index 7dfdf57e30..42b53558fb 100644 --- a/src/windows/service/exe/WslCoreNetworkEndpoint.h +++ b/src/windows/service/exe/WslCoreNetworkEndpoint.h @@ -3,6 +3,7 @@ #pragma once #include #include +#include #include #include "WslCoreNetworkEndpointSettings.h" @@ -16,15 +17,29 @@ struct NetworkEndpoint ~NetworkEndpoint() noexcept { - if (Endpoint) + DeleteEndpoint(); + } + + NetworkEndpoint(NetworkEndpoint&&) = default; + NetworkEndpoint& operator=(NetworkEndpoint&& source) noexcept + { + if (this != &source) { - wil::unique_cotaskmem_string error; - LOG_IF_FAILED_MSG(::HcnDeleteEndpoint(EndpointId, &error), "error message: %ls", error.get()); + DeleteEndpoint(); + StateTracking.reset(); + + Network = std::move(source.Network); + NetworkId = source.NetworkId; + EndpointId = source.EndpointId; + InterfaceGuid = source.InterfaceGuid; + InterfaceLuid = source.InterfaceLuid; + Endpoint = std::move(source.Endpoint); + StateTracking = std::move(source.StateTracking); } + + return *this; } - NetworkEndpoint(NetworkEndpoint&&) = default; - NetworkEndpoint& operator=(NetworkEndpoint&& source) = default; NetworkEndpoint(const NetworkEndpoint&) = delete; NetworkEndpoint& operator=(const NetworkEndpoint&) = delete; @@ -36,6 +51,15 @@ struct NetworkEndpoint windows::common::hcs::unique_hcn_endpoint Endpoint{}; std::optional StateTracking; + void DeleteEndpoint() const noexcept + { + if (Endpoint) + { + wil::unique_cotaskmem_string error; + LOG_IF_FAILED_MSG(::HcnDeleteEndpoint(EndpointId, &error), "error message: %ls", error.get()); + } + } + void TraceLoggingRundown() const { if (Network) From 7462ca71218d1d755ae8d9f47b782591e0309511 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 16:52:17 +0800 Subject: [PATCH 5/8] Fix export format exclusive check --- src/windows/common/WslClient.cpp | 5 ++--- src/windows/common/precomp.h | 1 + test/windows/UnitTests.cpp | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index 3c120c8cec..dd493b24d5 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -256,9 +256,8 @@ int ExportDistribution(_In_ std::wstring_view commandLine) parser.AddArgument(parseFormat, WSL_EXPORT_ARG_FORMAT_OPTION); parser.Parse(); - THROW_HR_IF( - WSL_E_INVALID_USAGE, - filePath.empty() || (WI_IsFlagSet(flags, LXSS_EXPORT_DISTRO_FLAGS_GZIP) && WI_IsFlagSet(flags, LXSS_EXPORT_DISTRO_FLAGS_VHD))); + constexpr ULONG c_exportFormatFlags = LXSS_EXPORT_DISTRO_FLAGS_VHD | LXSS_EXPORT_DISTRO_FLAGS_GZIP | LXSS_EXPORT_DISTRO_FLAGS_XZIP; + THROW_HR_IF(WSL_E_INVALID_USAGE, filePath.empty() || std::popcount(flags & c_exportFormatFlags) > 1); // Determine if the target is stdout, or an on-disk file. wil::unique_hfile file; diff --git a/src/windows/common/precomp.h b/src/windows/common/precomp.h index c7b53ee547..a903ca27b3 100644 --- a/src/windows/common/precomp.h +++ b/src/windows/common/precomp.h @@ -97,6 +97,7 @@ Module Name: #include #include #include +#include // Socket APIs #include diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 035323b75a..7e1d7ec659 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -169,6 +169,10 @@ class UnitTests VERIFY_ARE_EQUAL(out, L"This operation is only supported by WSL2.\r\nError code: Wsl/Service/WSL_E_WSL2_NEEDED\r\n"); VERIFY_ARE_EQUAL(err, L""); } + + VerifyInvalidUsage( + std::format(L"--export {} {} --format tar.gz --format tar.xz", LXSS_DISTRO_NAME_TEST_L, tarPath)); + VerifyInvalidUsage(std::format(L"--export {} {} --format tar.xz --vhd", LXSS_DISTRO_NAME_TEST_L, tarPath)); } WSL2_TEST_METHOD(SystemdSafeMode) From 924dcf6ff4ee8b13dd870f72e30a85e11d805977 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 17:29:07 +0800 Subject: [PATCH 6/8] avoid command injection in --set-default-user --- src/windows/common/WslClient.cpp | 10 ++++------ test/windows/UnitTests.cpp | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index dd493b24d5..79413e70f7 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -925,12 +925,10 @@ int Manage(_In_ std::wstring_view commandLine) else if (defaultUser) { auto wslExe = wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()); - - auto commandLine = std::format( - L"\"{}\" {} -u root /usr/bin/id -u -- '{}'", - wslExe, - wsl::shared::string::GuidToString(distroGuid), - defaultUser.value()); + const auto distroGuidString = wsl::shared::string::GuidToString(distroGuid); + const std::array arguments{ + wslExe, distroGuidString, WSL_USER_ARG, L"root", WSL_EXEC_ARG, L"/usr/bin/id", L"-u", L"--", defaultUser.value()}; + const auto commandLine = wil::ArgvToCommandLine(arguments); wsl::windows::common::SubProcess process{wslExe.c_str(), commandLine.c_str()}; diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 7e1d7ec659..856e320c09 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -170,8 +170,7 @@ class UnitTests VERIFY_ARE_EQUAL(err, L""); } - VerifyInvalidUsage( - std::format(L"--export {} {} --format tar.gz --format tar.xz", LXSS_DISTRO_NAME_TEST_L, tarPath)); + VerifyInvalidUsage(std::format(L"--export {} {} --format tar.gz --format tar.xz", LXSS_DISTRO_NAME_TEST_L, tarPath)); VerifyInvalidUsage(std::format(L"--export {} {} --format tar.xz --vhd", LXSS_DISTRO_NAME_TEST_L, tarPath)); } @@ -4369,6 +4368,23 @@ localhostForwarding=true VERIFY_ARE_EQUAL( out, L"There is no distribution with the supplied name.\r\nError code: Wsl/Service/WSL_E_DISTRO_NOT_FOUND\r\n"); + + constexpr auto injectionMarker = L"/tmp/wsl-manage-default-user-injection"; + LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/rm -f {}", injectionMarker)); + auto cleanupInjectionMarker = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [injectionMarker]() { + LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/rm -f {}", injectionMarker)); + }); + + const auto injectionUsername = std::format(L"' || touch {} || '", injectionMarker); + const std::array injectionArguments{ + WSL_MANAGE_ARG, LXSS_DISTRO_NAME_TEST_L, WSL_MANAGE_ARG_SET_DEFAULT_USER_OPTION_LONG, injectionUsername}; + const auto injectionCommand = wil::ArgvToCommandLine(injectionArguments, wil::ArgvToCommandLineFlags::FirstArgumentIsNotPath); + auto injectionCommandLine = LxssGenerateWslCommandLine(injectionCommand.c_str()); + const auto [injectionOutput, injectionError, injectionExitCode] = + LxsstuLaunchCommandAndCaptureOutputWithResult(injectionCommandLine.data()); + + VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/test ! -e {}", injectionMarker)), 0L); + VERIFY_ARE_EQUAL(injectionExitCode, 1); } TEST_METHOD(PostDistroRegistrationSettingsOOBE) From 9afd437af748ec934faa105325d0f19d63736865 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 18:25:38 +0800 Subject: [PATCH 7/8] resolve comments --- src/windows/common/WslClient.cpp | 11 ++++++++--- test/windows/UnitTests.cpp | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index 79413e70f7..8c5ef60bca 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -223,8 +223,9 @@ int ExportDistribution(_In_ std::wstring_view commandLine) ArgumentParser parser(std::wstring{commandLine}, WSL_BINARY_NAME); std::filesystem::path filePath; LPCWSTR name{}; + int tarFormatSet = 0; - auto parseFormat = [&flags](LPCWSTR Value) { + auto parseFormat = [&flags, &tarFormatSet](LPCWSTR Value) { if (Value == nullptr) { return -1; @@ -242,7 +243,11 @@ int ExportDistribution(_In_ std::wstring_view commandLine) { WI_SetFlag(flags, LXSS_EXPORT_DISTRO_FLAGS_VHD); } - else if (!wsl::shared::string::IsEqual(L"tar", Value)) + else if (wsl::shared::string::IsEqual(L"tar", Value)) + { + tarFormatSet = 1; + } + else { THROW_HR(E_INVALIDARG); } @@ -257,7 +262,7 @@ int ExportDistribution(_In_ std::wstring_view commandLine) parser.Parse(); constexpr ULONG c_exportFormatFlags = LXSS_EXPORT_DISTRO_FLAGS_VHD | LXSS_EXPORT_DISTRO_FLAGS_GZIP | LXSS_EXPORT_DISTRO_FLAGS_XZIP; - THROW_HR_IF(WSL_E_INVALID_USAGE, filePath.empty() || std::popcount(flags & c_exportFormatFlags) > 1); + THROW_HR_IF(WSL_E_INVALID_USAGE, filePath.empty() || std::popcount(flags & c_exportFormatFlags) + tarFormatSet > 1); // Determine if the target is stdout, or an on-disk file. wil::unique_hfile file; diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 856e320c09..79103479b8 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -4382,6 +4382,8 @@ localhostForwarding=true auto injectionCommandLine = LxssGenerateWslCommandLine(injectionCommand.c_str()); const auto [injectionOutput, injectionError, injectionExitCode] = LxsstuLaunchCommandAndCaptureOutputWithResult(injectionCommandLine.data()); + (void)injectionOutput; + (void)injectionError; VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/test ! -e {}", injectionMarker)), 0L); VERIFY_ARE_EQUAL(injectionExitCode, 1); From 007d9656e9f99d13c728ca5af1563829f6d71c54 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Fri, 21 Aug 2026 10:33:39 +0800 Subject: [PATCH 8/8] resolve comments --- src/windows/service/exe/WslCoreNetworkEndpoint.h | 3 ++- test/windows/UnitTests.cpp | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/windows/service/exe/WslCoreNetworkEndpoint.h b/src/windows/service/exe/WslCoreNetworkEndpoint.h index 42b53558fb..7db7c3aecd 100644 --- a/src/windows/service/exe/WslCoreNetworkEndpoint.h +++ b/src/windows/service/exe/WslCoreNetworkEndpoint.h @@ -51,12 +51,13 @@ struct NetworkEndpoint windows::common::hcs::unique_hcn_endpoint Endpoint{}; std::optional StateTracking; - void DeleteEndpoint() const noexcept + void DeleteEndpoint() noexcept { if (Endpoint) { wil::unique_cotaskmem_string error; LOG_IF_FAILED_MSG(::HcnDeleteEndpoint(EndpointId, &error), "error message: %ls", error.get()); + Endpoint.reset(); } } diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 79103479b8..e3c846180c 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -4380,13 +4380,10 @@ localhostForwarding=true WSL_MANAGE_ARG, LXSS_DISTRO_NAME_TEST_L, WSL_MANAGE_ARG_SET_DEFAULT_USER_OPTION_LONG, injectionUsername}; const auto injectionCommand = wil::ArgvToCommandLine(injectionArguments, wil::ArgvToCommandLineFlags::FirstArgumentIsNotPath); auto injectionCommandLine = LxssGenerateWslCommandLine(injectionCommand.c_str()); - const auto [injectionOutput, injectionError, injectionExitCode] = - LxsstuLaunchCommandAndCaptureOutputWithResult(injectionCommandLine.data()); - (void)injectionOutput; - (void)injectionError; + const auto injectionExitCode = LxsstuRunCommand(injectionCommandLine.data()); VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/test ! -e {}", injectionMarker)), 0L); - VERIFY_ARE_EQUAL(injectionExitCode, 1); + VERIFY_ARE_EQUAL(injectionExitCode, 1L); } TEST_METHOD(PostDistroRegistrationSettingsOOBE)