Include the hash of the SID in the Window Class and Mutant (#19109)

Right now, we do not use a sufficiently unique name to disambiguate
Terminal instances running on the same desktop.

Mutexes (mutants) are named objects that live in the user's session,
under `Sessions\1\BaseNamedObjects` (for the local desktop session).
When multiple users are logged into the same session--such as with "Run
as different user"--they share a local BaseNamedObjects namespace. Ugh.

We cannot use [`CreatePrivateNamespace`] as it requires a boundary
descriptor, and the only boundary descriptors supported by the current
API are based on package identity. I also fear that
`CreatePrivateNamespace` is subject to a race condition with
`OpenPrivateNamespace`; Create will not Open an existing one, so we
would need to back off and retry either opening or creating. Yuck.

After this commit, we will hash the user's SID into the name of both the
window class and the mutant, right after the path hash (if running
unpackaged).

Closes #18704

[`CreatePrivateNamespace`]:
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprivatenamespacea
This commit is contained in:
Dustin L. Howett 2025-07-08 17:27:21 -05:00 committed by GitHub
parent ac07afebcb
commit 02f173d504
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -9,6 +9,7 @@
#include <ScopedResourceLoader.h>
#include <WtExeUtils.h>
#include <til/hash.h>
#include <wil/token_helpers.h>
#include "AppHost.h"
#include "resource.h"
@ -275,7 +276,7 @@ AppHost* WindowEmperor::_mostRecentWindow() const noexcept
void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
{
std::wstring windowClassName;
windowClassName.reserve(47); // "Windows Terminal Preview Admin 0123456789012345"
windowClassName.reserve(64); // "Windows Terminal Preview Admin 0123456789012345 0123456789012345"
#if defined(WT_BRANDING_RELEASE)
windowClassName.append(L"Windows Terminal");
#elif defined(WT_BRANDING_PREVIEW)
@ -300,6 +301,18 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
#endif
}
{
wil::unique_handle processToken{ GetCurrentProcessToken() };
const auto userTokenInfo{ wil::get_token_information<TOKEN_USER>(processToken.get()) };
const auto sidLength{ GetLengthSid(userTokenInfo->User.Sid) };
const auto hash{ til::hash(userTokenInfo->User.Sid, sidLength) };
#ifdef _WIN64
fmt::format_to(std::back_inserter(windowClassName), FMT_COMPILE(L" {:016x}"), hash);
#else
fmt::format_to(std::back_inserter(windowClassName), FMT_COMPILE(L" {:08x}"), hash);
#endif
}
// Windows Terminal is a single-instance application. Either acquire ownership
// over the mutex, or hand off the command line to the existing instance.
const auto mutex = acquireMutexOrAttemptHandoff(windowClassName.c_str(), nCmdShow);