Merge branch 'master' into user/chemwolf6922/protect-wsl-core-processes-with-memory-cgroup

This commit is contained in:
Feng Wang
2026-05-13 13:34:52 +08:00
3 changed files with 90 additions and 18 deletions

View File

@@ -160,6 +160,8 @@ void WaitForBootProcess(wsl::linux::WslDistributionConfig& Config);
wil::unique_fd UnmarshalConsoleFromServer(int MessageFd, LXBUS_IPC_CONSOLE_ID ConsoleId);
int WslInitWatcher(int Argc, char** Argv);
int WslEntryPoint(int Argc, char* Argv[])
{
//
@@ -222,6 +224,10 @@ int WslEntryPoint(int Argc, char* Argv[])
{
ExitCode = GenerateUserSystemdUnits(Argc, Argv);
}
else if (strcmp(BaseName, LX_INIT_WSL_INIT_WATCHER) == 0)
{
ExitCode = WslInitWatcher(Argc, Argv);
}
else
{
// Handle the special case for import result messages, everything else is sent to the binfmt interpreter.
@@ -2409,6 +2415,16 @@ Return Value:
_exit(1);
}
//
// Fork a watcher process that monitors WSL init and tears down
// the PID namespace if it exits unexpectedly.
//
UtilCreateChildProcess(LX_INIT_WSL_INIT_WATCHER, [&]() {
execl(LX_INIT_PATH, LX_INIT_WSL_INIT_WATCHER, static_cast<char*>(nullptr));
LOG_ERROR("execl({}) failed {}", LX_INIT_WSL_INIT_WATCHER, errno);
});
//
// Keep track of the new pid for WSL init.
//
@@ -3501,4 +3517,37 @@ void WaitForBootProcess(wsl::linux::WslDistributionConfig& Config)
LOG_ERROR("{} failed to start within {}ms", INIT_PATH, Config.BootInitTimeout);
}
}
}
}
int WslInitWatcher(int Argc, char** Argv)
{
// Ignore log initialization failure. Not critical.
InitializeLogging(false);
UtilSetThreadName(LX_INIT_WSL_INIT_WATCHER);
const pid_t wslInitPid = getppid();
const int pidfd = syscall(SYS_pidfd_open, wslInitPid, 0);
if (pidfd < 0)
{
LOG_ERROR("pidfd_open failed {}", errno);
_exit(1);
}
pollfd pfd{pidfd, POLLIN, 0};
int rc;
while ((rc = poll(&pfd, 1, -1)) < 0 && errno == EINTR)
{
}
if (rc <= 0 || (pfd.revents & POLLIN) == 0)
{
LOG_ERROR("poll failed {} {}", rc, errno);
_exit(1);
}
LOG_ERROR("wsl init has exited, shutting down the distro");
// Teardown the current PID namespace. Not shutting down the VM.
reboot(RB_POWER_OFF);
_exit(1);
}

View File

@@ -245,6 +245,8 @@ Abstract:
#define LX_INIT_WSL_USER_GENERATOR "wsl-user-generator"
#define LX_INIT_WSL_INIT_WATCHER "init-watcher"
//
// WSL2-specific environment variables.
//

View File

@@ -393,6 +393,26 @@ class UnitTests
}
}
WSL2_TEST_METHOD(SystemdKillInitTerminatesDistro)
{
WslConfigChange config(LxssGenerateTestConfig() + L"[general]\ninstanceIdleTimeout=-1");
auto revert = EnableSystemd("initTimeout=0");
// Wait for systemd to start
VERIFY_NO_THROW(wsl::shared::retry::RetryWithTimeout<void>(
[&]() { THROW_HR_IF(E_UNEXPECTED, !IsSystemdRunning(L"--system")); }, std::chrono::seconds(1), std::chrono::minutes(1)));
// Kill the WSL init process
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"kill -9 2"), 0L);
// Wait for the distro to exit.
VERIFY_NO_THROW(wsl::shared::retry::RetryWithTimeout<void>(
[&]() { THROW_HR_IF(E_ABORT, GetDistroState() == LxssDistributionStateRunning); }, std::chrono::seconds(1), std::chrono::seconds(30)));
// Verify that a new WSL command succeeds (the distro restarts cleanly).
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(L"echo hello");
VERIFY_ARE_EQUAL(out, L"hello\n");
}
TEST_METHOD(Dup)
{
VERIFY_NO_THROW(LxsstuRunTest(L"/data/test/wsl_unit_tests dup", L"Dup"));
@@ -6152,31 +6172,32 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
}
}
static LxssDistributionState GetDistroState()
{
wsl::windows::common::SvcComm service;
for (const auto& e : service.EnumerateDistributions())
{
if (wsl::shared::string::IsEqual(e.DistroName, LXSS_DISTRO_NAME_TEST_L))
{
return e.State;
}
}
return LxssDistributionStateInvalid;
}
TEST_METHOD(DistroTimeout)
{
WslConfigChange config(LxssGenerateTestConfig() + L"[general]\ninstanceIdleTimeout=-1");
auto distroId = GetDistributionId(LXSS_DISTRO_NAME_TEST_L);
auto getDistroState = [&]() {
wsl::windows::common::SvcComm service;
for (const auto& e : service.EnumerateDistributions())
{
if (wsl::shared::string::IsEqual(e.DistroName, LXSS_DISTRO_NAME_TEST_L))
{
return e.State;
}
}
return LxssDistributionStateInvalid;
};
// Validate that distributions don't time out when timeout is -1
{
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"echo OK"), 0L);
std::this_thread::sleep_for(std::chrono::seconds(20));
VERIFY_ARE_EQUAL(getDistroState(), LxssDistributionStateRunning);
VERIFY_ARE_EQUAL(GetDistroState(), LxssDistributionStateRunning);
}
// Validate that distributions time out when timeout value is > 0
@@ -6190,7 +6211,7 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
unsigned long iterations = 0;
while (std::chrono::steady_clock::now() < deadline)
{
if (getDistroState() == LxssDistributionStateInstalled)
if (GetDistroState() == LxssDistributionStateInstalled)
{
LogInfo("Distribution stopped after %lu iterations", iterations);
return;
@@ -6200,7 +6221,7 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
iterations++;
}
LogError("Distribution failed to time out after %lu iterations. State: %i", iterations, getDistroState());
LogError("Distribution failed to time out after %lu iterations. State: %i", iterations, GetDistroState());
VERIFY_FAIL();
}
}