From c8417df84e1e190d12907a21688aacf167d7550b Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Mon, 8 Jul 2024 14:53:36 -0700 Subject: [PATCH] Fix for attempted use of capability API before it was introduced (#4620) ## Change Check for the existence of `Windows::Security::Authorization::AppCapabilityAccess::AppCapability`, and if it is not present, simply force the caller to be at least medium integrity level. --- .../Public/winget/Security.h | 6 ++++ src/AppInstallerSharedLib/Security.cpp | 19 ++++++++++ .../Helpers.cpp | 35 +++++++++++++++---- src/Microsoft.Management.Deployment/pch.h | 5 +-- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/AppInstallerSharedLib/Public/winget/Security.h b/src/AppInstallerSharedLib/Public/winget/Security.h index c4854d8237..89378cb9cf 100644 --- a/src/AppInstallerSharedLib/Public/winget/Security.h +++ b/src/AppInstallerSharedLib/Public/winget/Security.h @@ -27,6 +27,12 @@ namespace AppInstaller::Security // and is at least equal integrity level (higher will also be allowed). bool IsCOMCallerSameUserAndIntegrityLevel(); + // Determines if the current COM caller is at least the minimum integrity level provided. + bool IsCOMCallerIntegrityLevelAtLeast(IntegrityLevel minimumLevel); + + // Determines if the current integrity level is at least the minimum integrity level provided. + bool IsCurrentIntegrityLevelAtLeast(IntegrityLevel minimumLevel); + // Gets the string representation of the given SID. std::string ToString(PSID sid); } diff --git a/src/AppInstallerSharedLib/Security.cpp b/src/AppInstallerSharedLib/Security.cpp index eaeeaf2d59..8915f8de9c 100644 --- a/src/AppInstallerSharedLib/Security.cpp +++ b/src/AppInstallerSharedLib/Security.cpp @@ -112,6 +112,25 @@ namespace AppInstaller::Security return true; } + bool IsCOMCallerIntegrityLevelAtLeast(IntegrityLevel minimumLevel) + { + auto impersonation = ImpersonateCOMorRPCCaller::BeginImpersonation(); + return IsCurrentIntegrityLevelAtLeast(minimumLevel); + } + + bool IsCurrentIntegrityLevelAtLeast(IntegrityLevel minimumLevel) + { + IntegrityLevel callingIntegrityLevel = GetEffectiveIntegrityLevel(); + + if (ToIntegral(callingIntegrityLevel) < ToIntegral(minimumLevel)) + { + AICLI_LOG(Core, Crit, << "Attempt to access by a lower integrity process than required: " << callingIntegrityLevel << " < " << minimumLevel); + return false; + } + + return true; + } + std::string ToString(PSID sid) { wil::unique_hlocal_ansistring result; diff --git a/src/Microsoft.Management.Deployment/Helpers.cpp b/src/Microsoft.Management.Deployment/Helpers.cpp index f414e5738f..0e2ba8abb1 100644 --- a/src/Microsoft.Management.Deployment/Helpers.cpp +++ b/src/Microsoft.Management.Deployment/Helpers.cpp @@ -1,4 +1,3 @@ - // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #include "pch.h" @@ -7,6 +6,7 @@ #include #include #include +#include using namespace std::string_literals; using namespace std::string_view_literals; @@ -71,13 +71,34 @@ namespace winrt::Microsoft::Management::Deployment::implementation HRESULT EnsureProcessHasCapability(Capability requiredCapability, DWORD callerProcessId) { - // Get the caller process id and use it to check if the caller has permissions to access the feature. - winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus status = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::DeniedBySystem; + bool allowed = false; + + if (winrt::Windows::Foundation::Metadata::ApiInformation::IsTypePresent(winrt::name_of())) + { + // Get the caller process id and use it to check if the caller has permissions to access the feature. + winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus status = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::DeniedBySystem; + + auto capability = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapability::CreateWithProcessIdForUser(nullptr, GetStringForCapability(requiredCapability), callerProcessId); + status = capability.CheckAccess(); - auto capability = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapability::CreateWithProcessIdForUser(nullptr, GetStringForCapability(requiredCapability), callerProcessId); - status = capability.CheckAccess(); + allowed = (status == winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::Allowed); + } + else + { + // If AppCapability is not present, require at least medium IL callers + auto requiredIntegrityLevel = AppInstaller::Security::IntegrityLevel::Medium; + + if (callerProcessId != GetCurrentProcessId()) + { + allowed = AppInstaller::Security::IsCOMCallerIntegrityLevelAtLeast(requiredIntegrityLevel); + } + else + { + allowed = AppInstaller::Security::IsCurrentIntegrityLevelAtLeast(requiredIntegrityLevel); + } + } - return (status != winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::Allowed ? E_ACCESSDENIED : S_OK); + return (allowed ? S_OK : E_ACCESSDENIED); } HRESULT EnsureComCallerHasCapability(Capability requiredCapability) @@ -168,4 +189,4 @@ namespace winrt::Microsoft::Management::Deployment::implementation return isBackgroundProcessForPolicy; } -} \ No newline at end of file +} diff --git a/src/Microsoft.Management.Deployment/pch.h b/src/Microsoft.Management.Deployment/pch.h index 47a1ae5ceb..bb44268681 100644 --- a/src/Microsoft.Management.Deployment/pch.h +++ b/src/Microsoft.Management.Deployment/pch.h @@ -1,12 +1,13 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once #include #include #include +#include #include #include #include #include -#include \ No newline at end of file +#include