From e0ede96fdb882ab6c2e305b4438c6863f9cb67a9 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Fri, 10 Apr 2026 13:12:02 -0700 Subject: [PATCH 1/3] Add admin protection error message for shadow admin scenarios When Windows Admin Protection is enabled, the elevated process runs as a shadow admin with a different SID, so distributions registered under the real user are not visible. Surface an informational message in two cases: 1. Launching a distribution by name that is not found (WSL_E_DISTRO_NOT_FOUND) 2. Listing distributions when none are registered (WSL_E_DEFAULT_DISTRO_NOT_FOUND) --- localization/strings/en-US/Resources.resw | 5 ++ src/windows/common/wslutil.cpp | 59 +++++++++++++++++++++-- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index 1a9b8cbd8..1d4d48dc0 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -744,6 +744,11 @@ For information please visit https://aka.ms/wslinstall Running the debug shell requires running wsl.exe as Administrator. + + Windows Admin Protection is enabled and your distributions may be registered under a different account. +For more information on Admin Protection, please visit https://aka.ms/apdevguide + {Locked="Windows Admin Protection"}{Locked="Admin Protection"}{Locked="https://aka.ms/apdevguide"}Command line arguments, file names and string inserts should not be translated + The installation process for distribution '{}' failed with exit code: {}. {FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated diff --git a/src/windows/common/wslutil.cpp b/src/windows/common/wslutil.cpp index 24d21733e..ce907ecf4 100644 --- a/src/windows/common/wslutil.cpp +++ b/src/windows/common/wslutil.cpp @@ -522,10 +522,42 @@ wsl::windows::common::wslutil::GetDefaultVersion(void) return version; } +namespace +{ + +// Returns true if the current process is running as a shadow admin under +// Windows Admin Protection. Caches the DLL lookup on first call. +bool IsAdminProtectionEnabled() +{ + const auto token = wil::open_current_access_token(); + if (!wsl::windows::common::security::IsTokenElevated(token.get())) + { + return false; + } + + using ShadowAdminEnabledFn = BOOL(WINAPI)(); + static std::optional> s_fn; + static std::once_flag s_initFlag; + + std::call_once(s_initFlag, []() + { + LxssDynamicFunction fn{DynamicFunctionErrorLogs::None}; + if (SUCCEEDED(fn.load(L"SecurityHealthUdk.dll", "Shield_LUAIsShadowAdminEnabled"))) + { + s_fn.emplace(std::move(fn)); + } + }); + + return s_fn.has_value() && (*s_fn)(); +} + +} // anonymous namespace + std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result) { ULONG buildNumber = 0; std::wstring kbUrl; + std::wstring errorString; switch (result) { @@ -545,14 +577,16 @@ std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result) return Localization::MessageHigherIntegrity(); case WSL_E_DEFAULT_DISTRO_NOT_FOUND: - return Localization::MessageNoDefaultDistro(); + errorString = Localization::MessageNoDefaultDistro(); + break; case HRESULT_FROM_WIN32(WSAECONNABORTED): case HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS): return Localization::MessageInstanceTerminated(); case WSL_E_DISTRO_NOT_FOUND: - return Localization::MessageDistroNotFound(); + errorString = Localization::MessageDistroNotFound(); + break; case HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS): return Localization::MessageDistroNameAlreadyExists(); @@ -695,7 +729,26 @@ std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result) } } - return GetSystemErrorString(result); + if (errorString.empty()) + { + return GetSystemErrorString(result); + } + + // If Admin Protection is enabled, prepend an informational message for + // errors that may be caused by the shadow admin's separate registry hive. + try + { + if (IsAdminProtectionEnabled()) + { + auto message = Localization::MessageAdminProtectionEnabled(); + message += L"\n\n"; + message += errorString; + return message; + } + } + CATCH_LOG() + + return errorString; } std::optional> wsl::windows::common::wslutil::GetGitHubAssetFromRelease(const GitHubRelease& Release) From 84407b1526f0842a2e81aff53d39e95c3212cc0d Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Mon, 13 Apr 2026 12:55:15 -0700 Subject: [PATCH 2/3] formatting --- src/windows/common/wslutil.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/windows/common/wslutil.cpp b/src/windows/common/wslutil.cpp index ce907ecf4..4a808f9ef 100644 --- a/src/windows/common/wslutil.cpp +++ b/src/windows/common/wslutil.cpp @@ -522,8 +522,7 @@ wsl::windows::common::wslutil::GetDefaultVersion(void) return version; } -namespace -{ +namespace { // Returns true if the current process is running as a shadow admin under // Windows Admin Protection. Caches the DLL lookup on first call. @@ -539,8 +538,7 @@ bool IsAdminProtectionEnabled() static std::optional> s_fn; static std::once_flag s_initFlag; - std::call_once(s_initFlag, []() - { + std::call_once(s_initFlag, []() { LxssDynamicFunction fn{DynamicFunctionErrorLogs::None}; if (SUCCEEDED(fn.load(L"SecurityHealthUdk.dll", "Shield_LUAIsShadowAdminEnabled"))) { From 0f29dbbdc04982137cca5aab85b43fad773920a4 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Mon, 13 Apr 2026 16:22:30 -0700 Subject: [PATCH 3/3] adjust error text --- localization/strings/en-US/Resources.resw | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index 1d4d48dc0..6def84997 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -745,9 +745,9 @@ For information please visit https://aka.ms/wslinstall Running the debug shell requires running wsl.exe as Administrator. - Windows Admin Protection is enabled and your distributions may be registered under a different account. -For more information on Admin Protection, please visit https://aka.ms/apdevguide - {Locked="Windows Admin Protection"}{Locked="Admin Protection"}{Locked="https://aka.ms/apdevguide"}Command line arguments, file names and string inserts should not be translated + Administrator protection is enabled, and your distributions might be registered with a different account. +Sign in with the account that registered them, and try again. To learn more, go to aka.ms/apdevguide. + {Locked="Administrator protection"}{Locked="https://aka.ms/apdevguide"}Command line arguments, file names and string inserts should not be translated The installation process for distribution '{}' failed with exit code: {}.