Skip to content

Commit 4824178

Browse files
author
Ben Hillis
committed
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)
1 parent b61bb85 commit 4824178

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

localization/strings/en-US/Resources.resw

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,11 @@ For information please visit https://aka.ms/wslinstall</value>
744744
<data name="MessageAdministratorAccessRequiredForDebugShell" xml:space="preserve">
745745
<value>Running the debug shell requires running wsl.exe as Administrator.</value>
746746
</data>
747+
<data name="MessageAdminProtectionEnabled" xml:space="preserve">
748+
<value>Windows Admin Protection is enabled and your distributions may be registered under a different account.
749+
For more information on Admin Protection, please visit https://aka.ms/apdevguide</value>
750+
<comment>{Locked="Admin Protection"}{Locked="https://aka.ms/apdevguide"}Command line arguments, file names and string inserts should not be translated</comment>
751+
</data>
747752
<data name="MessageInstallProcessFailed" xml:space="preserve">
748753
<value>The installation process for distribution '{}' failed with exit code: {}.</value>
749754
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>

src/windows/common/WslSecurity.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,24 @@ bool wsl::windows::common::security::IsTokenElevated(_In_ HANDLE token)
135135
return (GetUserBasicIntegrityLevel(token) == SECURITY_MANDATORY_HIGH_RID);
136136
}
137137

138+
bool wsl::windows::common::security::IsAdminProtectionEnabled()
139+
{
140+
const auto token = wil::open_current_access_token();
141+
if (!IsTokenElevated(token.get()))
142+
{
143+
return false;
144+
}
145+
146+
using ShadowAdminEnabledFn = BOOL(WINAPI)();
147+
LxssDynamicFunction<ShadowAdminEnabledFn> isShadowAdminEnabled{DynamicFunctionErrorLogs::None};
148+
if (FAILED(isShadowAdminEnabled.load(L"SecurityHealthUdk.dll", "Shield_LUAIsShadowAdminEnabled")))
149+
{
150+
return false;
151+
}
152+
153+
return isShadowAdminEnabled();
154+
}
155+
138156
wil::unique_handle wsl::windows::common::security::GetUserToken(_In_ TOKEN_TYPE tokenType, _In_ RPC_BINDING_HANDLE handle)
139157
{
140158
wil::unique_handle contextToken;

src/windows/common/WslSecurity.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ wil::unique_handle GetUserToken(_In_ TOKEN_TYPE tokenType, _In_ RPC_BINDING_HAND
107107
/// </summary>
108108
bool IsTokenElevated(_In_ HANDLE token);
109109

110+
/// <summary>
111+
/// Returns true if the current token is elevated and Windows Admin Protection (shadow admin) is enabled.
112+
/// </summary>
113+
bool IsAdminProtectionEnabled();
114+
110115
/// <summary>
111116
/// Returns true if the provided token is a member of the localsystem group
112117
/// </summary>

src/windows/common/wslutil.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,22 @@ std::wstring wsl::windows::common::wslutil::GetErrorString(HRESULT result)
545545
return Localization::MessageHigherIntegrity();
546546

547547
case WSL_E_DEFAULT_DISTRO_NOT_FOUND:
548-
return Localization::MessageNoDefaultDistro();
548+
{
549+
auto errorString = Localization::MessageNoDefaultDistro();
550+
try
551+
{
552+
if (wsl::windows::common::security::IsAdminProtectionEnabled())
553+
{
554+
errorString = Localization::MessageAdminProtectionEnabled();
555+
errorString += L"\n\n";
556+
errorString += Localization::MessageNoDefaultDistro();
557+
return errorString;
558+
}
559+
}
560+
CATCH_LOG()
561+
562+
return errorString;
563+
}
549564

550565
case HRESULT_FROM_WIN32(WSAECONNABORTED):
551566
case HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS):

src/windows/service/exe/LxssUserSession.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,23 @@ try
12461246
}
12471247

12481248
// Return an error if no distribution was found with a matching name.
1249-
RETURN_HR_IF(WSL_E_DISTRO_NOT_FOUND, !distroFound);
1249+
if (!distroFound)
1250+
{
1251+
try
1252+
{
1253+
auto runAsUser = wil::CoImpersonateClient();
1254+
if (wsl::windows::common::security::IsAdminProtectionEnabled())
1255+
{
1256+
auto message = wsl::shared::Localization::MessageAdminProtectionEnabled();
1257+
message += L"\n\n";
1258+
message += wsl::shared::Localization::MessageDistroNotFound();
1259+
THROW_HR_WITH_USER_ERROR(WSL_E_DISTRO_NOT_FOUND, std::move(message));
1260+
}
1261+
}
1262+
CATCH_LOG()
1263+
1264+
return WSL_E_DISTRO_NOT_FOUND;
1265+
}
12501266

12511267
return S_OK;
12521268
}

0 commit comments

Comments
 (0)