commit 43425fe97d237e03026fca4530dbc422ab445595
parent c00ea884520808ca58d9e74f62cd14ac66e0494c
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Mon, 8 Jul 2024 14:53:36 -0700
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.
Diffstat:
4 files changed, 56 insertions(+), 11 deletions(-)
diff --git 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
@@ -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
@@ -1,4 +1,3 @@
-
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
@@ -7,6 +6,7 @@
#include <winrt/Windows.Security.Authorization.AppCapabilityAccess.h>
#include <appmodel.h>
#include <Helpers.h>
+#include <winget/Security.h>
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<winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapability>()))
+ {
+ // 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
@@ -1,12 +1,13 @@
-// Copyright (c) Microsoft Corporation.
+// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
+#include <winrt/Windows.Foundation.Metadata.h>
#include <winrt/Windows.Web.Http.h>
#include <ostream>
#include <string>
#include <mutex>
-#include <random>-
\ No newline at end of file
+#include <random>