mirror of
https://github.com/microsoft/WSL.git
synced 2026-06-12 01:37:35 -05:00
Merge branch 'master' into user/chemwolf6922/protect-wsl-core-processes-with-memory-cgroup
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user