Fix batch of minor issues (#41397)

This PR fixes batch of minor issues found during AI code review. src/linux/init/GnsPortTracker.cpp: 378 Fixed oversized socket-address allocations from malicious inputs. src/linux/init/main.cpp: 2173 Fixed mini init overwriting a distribution symlink target. src/windows/common/WslClient.cpp: 259 src/windows/common/precomp.h: 100 test/windows/UnitTests.cpp: 172 Fixed conflicting export formats being accepted together. src/windows/common/WslClient.cpp: 928 test/windows/UnitTests.cpp: 4371 Fixed command injection through --set-default-user. src/windows/service/exe/WslCoreGuestNetworkService.cpp: 95 Fixed the guest network service VM ID not being stored. src/windows/service/exe/WslCoreNetworkEndpoint.h: 20 Fixed network endpoint move assignment leaking the replaced endpoint.

Feng Wang committed Aug 24, 2026 at 10:46 UTC d36c29302ffb78720d4eff837ead3af1f7786b83
7 files changed +68 -18
src/linux/init/GnsPortTracker.cpp
+1 -1
@@ -375,7 +375,7 @@ std::optional<GnsPortTracker::BindCall> GnsPortTracker::GetCallInfo(
375 uint64_t CallId, pid_t Pid, int Arch, int SysCallNumber, const gsl::span<unsigned long long>& Arguments)
376 {
377 auto ParseSocket = [&](int Socket, size_t AddressPtr, size_t AddressLength) -> std::optional<BindCall> {
378 - if (AddressLength < sizeof(sockaddr))
378 + if (AddressLength < sizeof(sockaddr) || AddressLength > sizeof(sockaddr_storage))
379 {
380 return {{{}, {}, CallId}}; // Invalid sockaddr. Let it go through.
381 }
src/linux/init/main.cpp
+3 -1
@@ -2164,7 +2164,9 @@ Return Value:
2164
2165 try
2166 {
2167 - wil::unique_fd InitFd{open(Target, (O_CREAT | O_WRONLY | O_TRUNC), 0755)};
2167 + THROW_LAST_ERROR_IF(unlink(Target) < 0 && errno != ENOENT);
2168 +
2169 + wil::unique_fd InitFd{open(Target, (O_CREAT | O_EXCL | O_WRONLY), 0755)};
2170 THROW_LAST_ERROR_IF(!InitFd);
2171
2172 THROW_LAST_ERROR_IF(mount(LX_INIT_PATH, Target, nullptr, (MS_RDONLY | MS_BIND), nullptr) < 0);
src/windows/common/WslClient.cpp
+13 -11
@@ -223,8 +223,9 @@ int ExportDistribution(_In_ std::wstring_view commandLine)
223 ArgumentParser parser(std::wstring{commandLine}, WSL_BINARY_NAME);
224 std::filesystem::path filePath;
225 LPCWSTR name{};
226 + int tarFormatSet = 0;
227
227 - auto parseFormat = [&flags](LPCWSTR Value) {
228 + auto parseFormat = [&flags, &tarFormatSet](LPCWSTR Value) {
229 if (Value == nullptr)
230 {
231 return -1;
@@ -242,7 +243,11 @@ int ExportDistribution(_In_ std::wstring_view commandLine)
243 {
244 WI_SetFlag(flags, LXSS_EXPORT_DISTRO_FLAGS_VHD);
245 }
245 - else if (!wsl::shared::string::IsEqual(L"tar", Value))
246 + else if (wsl::shared::string::IsEqual(L"tar", Value))
247 + {
248 + tarFormatSet = 1;
249 + }
250 + else
251 {
252 THROW_HR(E_INVALIDARG);
253 }
@@ -256,9 +261,8 @@ int ExportDistribution(_In_ std::wstring_view commandLine)
261 parser.AddArgument(parseFormat, WSL_EXPORT_ARG_FORMAT_OPTION);
262 parser.Parse();
263
259 - THROW_HR_IF(
260 - WSL_E_INVALID_USAGE,
261 - filePath.empty() || (WI_IsFlagSet(flags, LXSS_EXPORT_DISTRO_FLAGS_GZIP) && WI_IsFlagSet(flags, LXSS_EXPORT_DISTRO_FLAGS_VHD)));
264 + constexpr ULONG c_exportFormatFlags = LXSS_EXPORT_DISTRO_FLAGS_VHD | LXSS_EXPORT_DISTRO_FLAGS_GZIP | LXSS_EXPORT_DISTRO_FLAGS_XZIP;
265 + THROW_HR_IF(WSL_E_INVALID_USAGE, filePath.empty() || std::popcount(flags & c_exportFormatFlags) + tarFormatSet > 1);
266
267 // Determine if the target is stdout, or an on-disk file.
268 wil::unique_hfile file;
@@ -926,12 +930,10 @@ int Manage(_In_ std::wstring_view commandLine)
930 else if (defaultUser)
931 {
932 auto wslExe = wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle());
929 -
930 - auto commandLine = std::format(
931 - L"\"{}\" {} -u root /usr/bin/id -u -- '{}'",
932 - wslExe,
933 - wsl::shared::string::GuidToString<wchar_t>(distroGuid),
934 - defaultUser.value());
933 + const auto distroGuidString = wsl::shared::string::GuidToString<wchar_t>(distroGuid);
934 + const std::array<std::wstring_view, 9> arguments{
935 + wslExe, distroGuidString, WSL_USER_ARG, L"root", WSL_EXEC_ARG, L"/usr/bin/id", L"-u", L"--", defaultUser.value()};
936 + const auto commandLine = wil::ArgvToCommandLine(arguments);
937
938 wsl::windows::common::SubProcess process{wslExe.c_str(), commandLine.c_str()};
939
src/windows/common/precomp.h
+1
@@ -97,6 +97,7 @@ Abstract:
97 #include <format>
98 #include <cwctype>
99 #include <variant>
100 +#include <bit>
101
102 // Socket APIs
103 #include <mswsock.h>
src/windows/service/exe/WslCoreGuestNetworkService.cpp
+1
@@ -92,6 +92,7 @@ void wsl::core::networking::GuestNetworkService::CreateGuestNetworkService(
92 TraceLoggingHResult(result, "result"),
93 TraceLoggingValue(error.is_valid() ? error.get() : L"null", "errorString"));
94 THROW_IF_FAILED_MSG(result, "%ls", error.get());
95 + m_id = VmId;
96
97 m_guestNetworkServiceCallback = windows::common::hcs::RegisterGuestNetworkServiceCallback(m_service, Callback, CallbackContext);
98 SetGuestNetworkServiceState(hns::GuestNetworkServiceState::Bootstrapping);
src/windows/service/exe/WslCoreNetworkEndpoint.h
+30 -5
@@ -3,6 +3,7 @@
3 #pragma once
4 #include <memory>
5 #include <optional>
6 +#include <utility>
7 #include <hcs.hpp>
8
9 #include "WslCoreNetworkEndpointSettings.h"
@@ -16,15 +17,29 @@ struct NetworkEndpoint
17
18 ~NetworkEndpoint() noexcept
19 {
19 - if (Endpoint)
20 + DeleteEndpoint();
21 + }
22 +
23 + NetworkEndpoint(NetworkEndpoint&&) = default;
24 + NetworkEndpoint& operator=(NetworkEndpoint&& source) noexcept
25 + {
26 + if (this != &source)
27 {
21 - wil::unique_cotaskmem_string error;
22 - LOG_IF_FAILED_MSG(::HcnDeleteEndpoint(EndpointId, &error), "error message: %ls", error.get());
28 + DeleteEndpoint();
29 + StateTracking.reset();
30 +
31 + Network = std::move(source.Network);
32 + NetworkId = source.NetworkId;
33 + EndpointId = source.EndpointId;
34 + InterfaceGuid = source.InterfaceGuid;
35 + InterfaceLuid = source.InterfaceLuid;
36 + Endpoint = std::move(source.Endpoint);
37 + StateTracking = std::move(source.StateTracking);
38 }
39 +
40 + return *this;
41 }
42
26 - NetworkEndpoint(NetworkEndpoint&&) = default;
27 - NetworkEndpoint& operator=(NetworkEndpoint&& source) = default;
43 NetworkEndpoint(const NetworkEndpoint&) = delete;
44 NetworkEndpoint& operator=(const NetworkEndpoint&) = delete;
45
@@ -36,6 +51,16 @@ struct NetworkEndpoint
51 windows::common::hcs::unique_hcn_endpoint Endpoint{};
52 std::optional<IpStateTracking> StateTracking;
53
54 + void DeleteEndpoint() noexcept
55 + {
56 + if (Endpoint)
57 + {
58 + wil::unique_cotaskmem_string error;
59 + LOG_IF_FAILED_MSG(::HcnDeleteEndpoint(EndpointId, &error), "error message: %ls", error.get());
60 + Endpoint.reset();
61 + }
62 + }
63 +
64 void TraceLoggingRundown() const
65 {
66 if (Network)
test/windows/UnitTests.cpp
+19
@@ -169,6 +169,9 @@ class UnitTests
169 VERIFY_ARE_EQUAL(out, L"This operation is only supported by WSL2.\r\nError code: Wsl/Service/WSL_E_WSL2_NEEDED\r\n");
170 VERIFY_ARE_EQUAL(err, L"");
171 }
172 +
173 + VerifyInvalidUsage(std::format(L"--export {} {} --format tar.gz --format tar.xz", LXSS_DISTRO_NAME_TEST_L, tarPath));
174 + VerifyInvalidUsage(std::format(L"--export {} {} --format tar.xz --vhd", LXSS_DISTRO_NAME_TEST_L, tarPath));
175 }
176
177 WSL2_TEST_METHOD(SystemdSafeMode)
@@ -4366,6 +4369,22 @@ localhostForwarding=true
4369
4370 VERIFY_ARE_EQUAL(
4371 out, L"There is no distribution with the supplied name.\r\nError code: Wsl/Service/WSL_E_DISTRO_NOT_FOUND\r\n");
4372 +
4373 + constexpr auto injectionMarker = L"/tmp/wsl-manage-default-user-injection";
4374 + LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/rm -f {}", injectionMarker));
4375 + auto cleanupInjectionMarker = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [injectionMarker]() {
4376 + LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/rm -f {}", injectionMarker));
4377 + });
4378 +
4379 + const auto injectionUsername = std::format(L"' || touch {} || '", injectionMarker);
4380 + const std::array<std::wstring_view, 4> injectionArguments{
4381 + WSL_MANAGE_ARG, LXSS_DISTRO_NAME_TEST_L, WSL_MANAGE_ARG_SET_DEFAULT_USER_OPTION_LONG, injectionUsername};
4382 + const auto injectionCommand = wil::ArgvToCommandLine(injectionArguments, wil::ArgvToCommandLineFlags::FirstArgumentIsNotPath);
4383 + auto injectionCommandLine = LxssGenerateWslCommandLine(injectionCommand.c_str());
4384 + const auto injectionExitCode = LxsstuRunCommand(injectionCommandLine.data());
4385 +
4386 + VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-u root -e /usr/bin/test ! -e {}", injectionMarker)), 0L);
4387 + VERIFY_ARE_EQUAL(injectionExitCode, 1L);
4388 }
4389
4390 TEST_METHOD(PostDistroRegistrationSettingsOOBE)