Skip to content

Commit 0a63942

Browse files
authored
Fix WSL PATH corruption & potential use-after-free (#19211)
Closes #19152 ## Validation Steps Performed * Set `PATH` on a linux profile * `PATH` isn't messed up inside WSL ✅
1 parent 88ab154 commit 0a63942

File tree

2 files changed

+21
-26
lines changed

2 files changed

+21
-26
lines changed

src/cascadia/TerminalConnection/ConptyConnection.cpp

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
3030
{
3131
// Function Description:
3232
// - launches the client application attached to the new pseudoconsole
33-
HRESULT ConptyConnection::_LaunchAttachedClient() noexcept
34-
try
33+
void ConptyConnection::_LaunchAttachedClient()
3534
{
3635
STARTUPINFOEX siEx{ 0 };
3736
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
@@ -43,15 +42,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
4342
auto attrList{ std::make_unique<std::byte[]>(size) };
4443
#pragma warning(suppress : 26490) // We have to use reinterpret_cast because we allocated a byte array as a proxy for the adjustable size list.
4544
siEx.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(attrList.get());
46-
RETURN_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
45+
THROW_IF_WIN32_BOOL_FALSE(InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size));
4746

48-
RETURN_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(siEx.lpAttributeList,
49-
0,
50-
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
51-
_hPC.get(),
52-
sizeof(HPCON),
53-
nullptr,
54-
nullptr));
47+
THROW_IF_WIN32_BOOL_FALSE(UpdateProcThreadAttribute(
48+
siEx.lpAttributeList,
49+
0,
50+
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
51+
_hPC.get(),
52+
sizeof(HPCON),
53+
nullptr,
54+
nullptr));
5555

5656
auto cmdline{ wil::ExpandEnvironmentStringsW<std::wstring>(_commandline.c_str()) }; // mutable copy -- required for CreateProcessW
5757
auto environment = _initialEnv;
@@ -72,7 +72,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
7272
std::wstring additionalWslEnv;
7373

7474
// WSLENV.2: Figure out what variables are already in WSLENV.
75-
std::unordered_set<std::wstring_view> wslEnvVars;
75+
std::unordered_set<std::wstring> wslEnvVars{
76+
// We never want to put a custom Windows PATH variable into WSLENV,
77+
// because that would override WSL's computation of the NIX PATH.
78+
L"PATH",
79+
};
7680
for (const auto& part : til::split_iterator{ std::wstring_view{ wslEnv }, L':' })
7781
{
7882
// Each part may contain a variable name and flags (e.g., /p, /l, etc.)
@@ -97,25 +101,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
97101
}
98102
}
99103

104+
// add additional env vars
100105
if (_environment)
101106
{
102-
// Order the environment variable names so that resolution order is consistent
103-
// NOTE(lhecker): I'm like 99% sure that this is unnecessary.
104-
std::set<std::wstring, til::env_key_sorter> keys{};
105107
for (const auto item : _environment)
106-
{
107-
keys.insert(std::wstring{ item.Key() });
108-
}
109-
// add additional env vars
110-
for (const auto& key : keys)
111108
{
112109
try
113110
{
111+
const auto key = item.Key();
114112
// This will throw if the value isn't a string. If that
115113
// happens, then just skip this entry.
116114
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
117115

118-
environment.set_user_environment_var(key.c_str(), value.c_str());
116+
environment.set_user_environment_var(key, value);
119117

120118
// WSLENV.4: Add custom user environment variables to WSLENV.
121119
if (wslEnvVars.emplace(key).second)
@@ -166,7 +164,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
166164
auto [newCommandLine, newStartingDirectory] = Utils::MangleStartingDirectoryForWSL(cmdline, _startingDirectory);
167165
const auto startingDirectory = newStartingDirectory.size() > 0 ? newStartingDirectory.c_str() : nullptr;
168166

169-
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
167+
THROW_IF_WIN32_BOOL_FALSE(CreateProcessW(
170168
nullptr,
171169
newCommandLine.data(),
172170
nullptr, // lpProcessAttributes
@@ -193,10 +191,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
193191
TraceLoggingWideString(_clientName.c_str(), "Client", "The attached client process"),
194192
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
195193
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
196-
197-
return S_OK;
198194
}
199-
CATCH_RETURN();
200195

201196
// Who decided that?
202197
#pragma warning(suppress : 26455) // Default constructor should not throw. Declare it 'noexcept' (f.6).
@@ -418,7 +413,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
418413
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
419414
}
420415

421-
THROW_IF_FAILED(_LaunchAttachedClient());
416+
_LaunchAttachedClient();
422417
}
423418
// But if it was an inbound handoff... attempt to synchronize the size of it with what our connection
424419
// window is expecting it to be on the first layout.

src/cascadia/TerminalConnection/ConptyConnection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
5858
static HRESULT NewHandoff(HANDLE* in, HANDLE* out, HANDLE signal, HANDLE reference, HANDLE server, HANDLE client, const TERMINAL_STARTUP_INFO* startupInfo) noexcept;
5959
static winrt::hstring _commandlineFromProcess(HANDLE process);
6060

61-
HRESULT _LaunchAttachedClient() noexcept;
61+
void _LaunchAttachedClient();
6262
void _indicateExitWithStatus(unsigned int status) noexcept;
6363
static std::wstring _formatStatus(uint32_t status);
6464
void _LastConPtyClientDisconnected() noexcept;

0 commit comments

Comments
 (0)