Skip to content

Commit

Permalink
Fix for attempted use of capability API before it was introduced (mic…
Browse files Browse the repository at this point in the history
…rosoft#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.
  • Loading branch information
JohnMcPMS authored Jul 8, 2024
1 parent c00ea88 commit 43425fe
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 9 deletions.
6 changes: 6 additions & 0 deletions src/AppInstallerSharedLib/Public/winget/Security.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
19 changes: 19 additions & 0 deletions src/AppInstallerSharedLib/Security.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
35 changes: 28 additions & 7 deletions src/Microsoft.Management.Deployment/Helpers.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "pch.h"
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -168,4 +189,4 @@ namespace winrt::Microsoft::Management::Deployment::implementation

return isBackgroundProcessForPolicy;
}
}
}
5 changes: 3 additions & 2 deletions src/Microsoft.Management.Deployment/pch.h
Original file line number Diff line number Diff line change
@@ -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>
#include <random>

0 comments on commit 43425fe

Please sign in to comment.