Skip to content

Commit cc9b7a9

Browse files
authored
Fix for attempted use of capability API before it was introduced (#4623)
## 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. Cherry-pick of #4620
1 parent 24b0112 commit cc9b7a9

File tree

4 files changed

+56
-9
lines changed

4 files changed

+56
-9
lines changed

src/AppInstallerSharedLib/Public/winget/Security.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ namespace AppInstaller::Security
2727
// and is at least equal integrity level (higher will also be allowed).
2828
bool IsCOMCallerSameUserAndIntegrityLevel();
2929

30+
// Determines if the current COM caller is at least the minimum integrity level provided.
31+
bool IsCOMCallerIntegrityLevelAtLeast(IntegrityLevel minimumLevel);
32+
33+
// Determines if the current integrity level is at least the minimum integrity level provided.
34+
bool IsCurrentIntegrityLevelAtLeast(IntegrityLevel minimumLevel);
35+
3036
// Gets the string representation of the given SID.
3137
std::string ToString(PSID sid);
3238
}

src/AppInstallerSharedLib/Security.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,25 @@ namespace AppInstaller::Security
112112
return true;
113113
}
114114

115+
bool IsCOMCallerIntegrityLevelAtLeast(IntegrityLevel minimumLevel)
116+
{
117+
auto impersonation = ImpersonateCOMorRPCCaller::BeginImpersonation();
118+
return IsCurrentIntegrityLevelAtLeast(minimumLevel);
119+
}
120+
121+
bool IsCurrentIntegrityLevelAtLeast(IntegrityLevel minimumLevel)
122+
{
123+
IntegrityLevel callingIntegrityLevel = GetEffectiveIntegrityLevel();
124+
125+
if (ToIntegral(callingIntegrityLevel) < ToIntegral(minimumLevel))
126+
{
127+
AICLI_LOG(Core, Crit, << "Attempt to access by a lower integrity process than required: " << callingIntegrityLevel << " < " << minimumLevel);
128+
return false;
129+
}
130+
131+
return true;
132+
}
133+
115134
std::string ToString(PSID sid)
116135
{
117136
wil::unique_hlocal_ansistring result;

src/Microsoft.Management.Deployment/Helpers.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
// Copyright (c) Microsoft Corporation.
32
// Licensed under the MIT License.
43
#include "pch.h"
@@ -7,6 +6,7 @@
76
#include <winrt/Windows.Security.Authorization.AppCapabilityAccess.h>
87
#include <appmodel.h>
98
#include <Helpers.h>
9+
#include <winget/Security.h>
1010

1111
using namespace std::string_literals;
1212
using namespace std::string_view_literals;
@@ -71,13 +71,34 @@ namespace winrt::Microsoft::Management::Deployment::implementation
7171

7272
HRESULT EnsureProcessHasCapability(Capability requiredCapability, DWORD callerProcessId)
7373
{
74-
// Get the caller process id and use it to check if the caller has permissions to access the feature.
75-
winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus status = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::DeniedBySystem;
74+
bool allowed = false;
75+
76+
if (winrt::Windows::Foundation::Metadata::ApiInformation::IsTypePresent(winrt::name_of<winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapability>()))
77+
{
78+
// Get the caller process id and use it to check if the caller has permissions to access the feature.
79+
winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus status = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::DeniedBySystem;
80+
81+
auto capability = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapability::CreateWithProcessIdForUser(nullptr, GetStringForCapability(requiredCapability), callerProcessId);
82+
status = capability.CheckAccess();
7683

77-
auto capability = winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapability::CreateWithProcessIdForUser(nullptr, GetStringForCapability(requiredCapability), callerProcessId);
78-
status = capability.CheckAccess();
84+
allowed = (status == winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::Allowed);
85+
}
86+
else
87+
{
88+
// If AppCapability is not present, require at least medium IL callers
89+
auto requiredIntegrityLevel = AppInstaller::Security::IntegrityLevel::Medium;
90+
91+
if (callerProcessId != GetCurrentProcessId())
92+
{
93+
allowed = AppInstaller::Security::IsCOMCallerIntegrityLevelAtLeast(requiredIntegrityLevel);
94+
}
95+
else
96+
{
97+
allowed = AppInstaller::Security::IsCurrentIntegrityLevelAtLeast(requiredIntegrityLevel);
98+
}
99+
}
79100

80-
return (status != winrt::Windows::Security::Authorization::AppCapabilityAccess::AppCapabilityAccessStatus::Allowed ? E_ACCESSDENIED : S_OK);
101+
return (allowed ? S_OK : E_ACCESSDENIED);
81102
}
82103

83104
HRESULT EnsureComCallerHasCapability(Capability requiredCapability)
@@ -168,4 +189,4 @@ namespace winrt::Microsoft::Management::Deployment::implementation
168189

169190
return isBackgroundProcessForPolicy;
170191
}
171-
}
192+
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
// Copyright (c) Microsoft Corporation.
1+
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33
#pragma once
44
#include <unknwn.h>
55
#include <winrt/Windows.Foundation.h>
66
#include <winrt/Windows.Foundation.Collections.h>
7+
#include <winrt/Windows.Foundation.Metadata.h>
78
#include <winrt/Windows.Web.Http.h>
89

910
#include <ostream>
1011
#include <string>
1112
#include <mutex>
12-
#include <random>
13+
#include <random>

0 commit comments

Comments
 (0)