Skip to content

Commit

Permalink
[Windows] Cleanup sandbox usage of Win32 security APIs.
Browse files Browse the repository at this point in the history
This CL cleans up various uses of the Win32 security APIs that can
now be replaced with the base library AccessControlList and
SecurityDescriptor classes.

Bug: 1394854
Change-Id: I7064b1c9561f149cdf96040bd9eeb9740c1e18f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4112982
Commit-Queue: James Forshaw <forshaw@chromium.org>
Reviewed-by: Will Harris <wfh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1085082}
  • Loading branch information
James Forshaw authored and Chromium LUCI CQ committed Dec 19, 2022
1 parent 8c88556 commit 85f8239
Show file tree
Hide file tree
Showing 19 changed files with 313 additions and 529 deletions.
2 changes: 1 addition & 1 deletion sandbox/policy/win/sandbox_win.cc
Expand Up @@ -950,7 +950,7 @@ ResultCode SandboxWin::AddAppContainerProfileToConfig(
BOOL granted_access_status;
bool access_check =
container->AccessCheck(command_line.GetProgram().value().c_str(),
SecurityObjectType::kFile,
base::win::SecurityObjectType::kFile,
GENERIC_READ | GENERIC_EXECUTE, &granted_access,
&granted_access_status) &&
granted_access_status;
Expand Down
166 changes: 39 additions & 127 deletions sandbox/win/src/acl.cc
Expand Up @@ -4,75 +4,15 @@

#include "sandbox/win/src/acl.h"

#include <memory>

#include <windows.h>

#include <accctrl.h>
#include <aclapi.h>
#include <sddl.h>

#include "base/check.h"
#include "base/memory/free_deleter.h"
#include "base/notreached.h"
#include "base/win/access_token.h"
#include "base/win/scoped_localalloc.h"

namespace sandbox {

namespace {

ACCESS_MODE ConvertAccessMode(SecurityAccessMode access_mode) {
switch (access_mode) {
case SecurityAccessMode::kGrant:
return GRANT_ACCESS;
case SecurityAccessMode::kSet:
return SET_ACCESS;
case SecurityAccessMode::kDeny:
return DENY_ACCESS;
case SecurityAccessMode::kRevoke:
return REVOKE_ACCESS;
default:
NOTREACHED();
break;
}
return NOT_USED_ACCESS;
}

absl::optional<base::win::ScopedLocalAllocTyped<ACL>> AddSidToDacl(
const base::win::Sid& sid,
ACL* old_dacl,
SecurityAccessMode access_mode,
ACCESS_MASK access) {
EXPLICIT_ACCESS new_access = {};
new_access.grfAccessMode = ConvertAccessMode(access_mode);
new_access.grfAccessPermissions = access;
new_access.grfInheritance = NO_INHERITANCE;
::BuildTrusteeWithSid(&new_access.Trustee, sid.GetPSID());
ACL* new_dacl = nullptr;
if (ERROR_SUCCESS != ::SetEntriesInAcl(1, &new_access, old_dacl, &new_dacl))
return absl::nullopt;
DCHECK(::IsValidAcl(new_dacl));
return base::win::TakeLocalAlloc(new_dacl);
}

SE_OBJECT_TYPE ConvertObjectType(SecurityObjectType object_type) {
switch (object_type) {
case SecurityObjectType::kFile:
return SE_FILE_OBJECT;
case SecurityObjectType::kRegistry:
return SE_REGISTRY_KEY;
case SecurityObjectType::kWindow:
return SE_WINDOW_OBJECT;
case SecurityObjectType::kKernel:
return SE_KERNEL_OBJECT;
default:
NOTREACHED();
break;
}
return SE_UNKNOWN_OBJECT_TYPE;
}

absl::optional<DWORD> GetIntegrityLevelValue(IntegrityLevel integrity_level) {
switch (integrity_level) {
case INTEGRITY_LEVEL_SYSTEM:
Expand All @@ -97,120 +37,101 @@ absl::optional<DWORD> GetIntegrityLevelValue(IntegrityLevel integrity_level) {
return absl::nullopt;
}

bool AddSidToDefaultDacl(HANDLE token,
const base::win::AccessToken& query_token,
bool AddSidToDefaultDacl(base::win::AccessToken& token,
const base::win::Sid& sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access) {
if (!token)
absl::optional<base::win::AccessControlList> dacl = token.DefaultDacl();
if (!dacl || !dacl->SetEntry(sid, access_mode, access, 0)) {
return false;

absl::optional<base::win::AccessControlList> dacl = query_token.DefaultDacl();
if (!dacl)
return false;
auto new_dacl = AddSidToDacl(sid, dacl->get(), access_mode, access);
if (!new_dacl)
return false;

TOKEN_DEFAULT_DACL new_token_dacl = {0};
new_token_dacl.DefaultDacl = new_dacl->get();
return !!::SetTokenInformation(token, TokenDefaultDacl, &new_token_dacl,
sizeof(new_token_dacl));
}
return token.SetDefaultDacl(*dacl);
}

} // namespace

bool AddSidToDefaultDacl(HANDLE token,
const base::win::Sid& sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access) {
absl::optional<base::win::AccessToken> query_token =
base::win::AccessToken::FromToken(token);
base::win::AccessToken::FromToken(token, TOKEN_ADJUST_DEFAULT);
if (!query_token)
return false;

return AddSidToDefaultDacl(token, *query_token, sid, access_mode, access);
return AddSidToDefaultDacl(*query_token, sid, access_mode, access);
}

bool AddSidToDefaultDacl(HANDLE token,
base::win::WellKnownSid known_sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access) {
return AddSidToDefaultDacl(token, base::win::Sid(known_sid), access_mode,
access);
}

bool RevokeLogonSidFromDefaultDacl(HANDLE token) {
absl::optional<base::win::AccessToken> query_token =
base::win::AccessToken::FromToken(token);
base::win::AccessToken::FromToken(token, TOKEN_ADJUST_DEFAULT);
if (!query_token)
return false;
absl::optional<base::win::Sid> logon_sid = query_token->LogonId();
if (!logon_sid)
return ::GetLastError() == ERROR_NOT_FOUND;

return AddSidToDefaultDacl(token, *query_token, *logon_sid,
SecurityAccessMode::kRevoke, 0);
return AddSidToDefaultDacl(*query_token, *logon_sid,
base::win::SecurityAccessMode::kRevoke, 0);
}

bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access) {
absl::optional<base::win::AccessToken> query_token =
base::win::AccessToken::FromToken(token);
base::win::AccessToken::FromToken(token, TOKEN_ADJUST_DEFAULT);
if (!query_token)
return false;
return AddSidToDefaultDacl(token, *query_token, query_token->User(),
SecurityAccessMode::kGrant, access);
return AddSidToDefaultDacl(*query_token, query_token->User(),
base::win::SecurityAccessMode::kGrant, access);
}

bool AddKnownSidToObject(HANDLE object,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
const base::win::Sid& sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access) {
PSECURITY_DESCRIPTOR descriptor_ptr = nullptr;
PACL old_dacl = nullptr;
SE_OBJECT_TYPE native_object_type = ConvertObjectType(object_type);
if (native_object_type == SE_UNKNOWN_OBJECT_TYPE)
return false;

if (ERROR_SUCCESS != ::GetSecurityInfo(object, native_object_type,
DACL_SECURITY_INFORMATION, nullptr,
nullptr, &old_dacl, nullptr,
&descriptor_ptr)) {
absl::optional<base::win::SecurityDescriptor> sd =
base::win::SecurityDescriptor::FromHandle(object, object_type,
DACL_SECURITY_INFORMATION);
if (!sd) {
return false;
}

auto descriptor = base::win::TakeLocalAlloc(descriptor_ptr);
auto new_dacl = AddSidToDacl(sid, old_dacl, access_mode, access);
if (!new_dacl)
if (!sd->SetDaclEntry(sid, access_mode, access, 0)) {
return false;
}

return ::SetSecurityInfo(object, native_object_type,
DACL_SECURITY_INFORMATION, nullptr, nullptr,
new_dacl->get(), nullptr) == ERROR_SUCCESS;
return sd->WriteToHandle(object, object_type, DACL_SECURITY_INFORMATION);
}

bool AddKnownSidToObject(HANDLE object,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
base::win::WellKnownSid known_sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access) {
return AddKnownSidToObject(object, object_type, base::win::Sid(known_sid),
access_mode, access);
}

bool ReplacePackageSidInDacl(HANDLE object,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
const base::win::Sid& package_sid,
ACCESS_MASK access) {
if (!AddKnownSidToObject(object, object_type, package_sid,
SecurityAccessMode::kRevoke, 0)) {
base::win::SecurityAccessMode::kRevoke, 0)) {
return false;
}

return AddKnownSidToObject(object, object_type,
base::win::WellKnownSid::kAllApplicationPackages,
SecurityAccessMode::kGrant, access);
base::win::SecurityAccessMode::kGrant, access);
}

absl::optional<base::win::Sid> GetIntegrityLevelSid(
Expand All @@ -222,33 +143,24 @@ absl::optional<base::win::Sid> GetIntegrityLevelSid(
}

DWORD SetObjectIntegrityLabel(HANDLE handle,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
DWORD mandatory_policy,
IntegrityLevel integrity_level) {
absl::optional<base::win::Sid> sid = GetIntegrityLevelSid(integrity_level);
if (!sid)
absl::optional<DWORD> value = GetIntegrityLevelValue(integrity_level);
if (!value) {
return ERROR_INVALID_SID;
}

// Get total ACL length. SYSTEM_MANDATORY_LABEL_ACE contains the first DWORD
// of the SID so remove it from total.
DWORD length = sizeof(ACL) + sizeof(SYSTEM_MANDATORY_LABEL_ACE) +
::GetLengthSid(sid->GetPSID()) - sizeof(DWORD);
std::vector<char> sacl_buffer(length);
PACL sacl = reinterpret_cast<PACL>(sacl_buffer.data());

if (!::InitializeAcl(sacl, length, ACL_REVISION))
base::win::SecurityDescriptor sd;
if (!sd.SetMandatoryLabel(*value, 0, mandatory_policy)) {
return ::GetLastError();
}

if (!::AddMandatoryAce(sacl, ACL_REVISION, 0, mandatory_policy,
sid->GetPSID())) {
if (!sd.WriteToHandle(handle, object_type, LABEL_SECURITY_INFORMATION)) {
return ::GetLastError();
}

DCHECK(::IsValidAcl(sacl));

return ::SetSecurityInfo(handle, ConvertObjectType(object_type),
LABEL_SECURITY_INFORMATION, nullptr, nullptr,
nullptr, sacl);
return ERROR_SUCCESS;
}

} // namespace sandbox
24 changes: 10 additions & 14 deletions sandbox/win/src/acl.h
Expand Up @@ -6,31 +6,27 @@
#define SANDBOX_WIN_SRC_ACL_H_

#include "base/memory/free_deleter.h"
#include "base/win/access_control_list.h"
#include "base/win/security_descriptor.h"
#include "base/win/sid.h"
#include "base/win/windows_types.h"
#include "sandbox/win/src/security_level.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

namespace sandbox {

// Represents the type of Windows kernel object to apply the operation to.
enum class SecurityObjectType { kFile, kRegistry, kWindow, kKernel };

// Represents the type of access operation to perform on an ACL.
enum class SecurityAccessMode { kGrant, kSet, kDeny, kRevoke };

// Adds an ACE represented by |sid| and |access| with |access_mode| to the
// default dacl present in the token.
bool AddSidToDefaultDacl(HANDLE token,
const base::win::Sid& sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access);

// Adds an ACE represented by |known_sid| and |access| with |access_mode| to the
// default dacl present in the token.
bool AddSidToDefaultDacl(HANDLE token,
base::win::WellKnownSid known_sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access);

// Revokes access to the logon SID for the default dacl present in the token.
Expand All @@ -43,24 +39,24 @@ bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access);
// Adds an ACE represented by |known_sid|, |access_mode|, and |access| to
// the dacl of the kernel object referenced by |object| and of |object_type|.
bool AddKnownSidToObject(HANDLE object,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
base::win::WellKnownSid known_sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access);

// Adds an ACE represented by |sid|, |access_mode|, and |access| to
// the dacl of the kernel object referenced by |object| and of |object_type|.
bool AddKnownSidToObject(HANDLE object,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
const base::win::Sid& sid,
SecurityAccessMode access_mode,
base::win::SecurityAccessMode access_mode,
ACCESS_MASK access);

// Replace package SID in DACL to the "any package" SID. It allows Low-IL
// tokens to open the object which is important for warm up when using renderer
// AppContainer.
bool ReplacePackageSidInDacl(HANDLE object,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
const base::win::Sid& package_sid,
ACCESS_MASK access);

Expand All @@ -82,7 +78,7 @@ absl::optional<base::win::Sid> GetIntegrityLevelSid(
// function fails, the return value is the win32 error code corresponding to
// the error.
DWORD SetObjectIntegrityLabel(HANDLE handle,
SecurityObjectType object_type,
base::win::SecurityObjectType object_type,
DWORD mandatory_policy,
IntegrityLevel integrity_level);

Expand Down

0 comments on commit 85f8239

Please sign in to comment.