595 lines
25 KiB
C++
595 lines
25 KiB
C++
// Copyright 2022 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/win/security_descriptor.h"
|
|
|
|
#include <aclapi.h>
|
|
#include <sddl.h>
|
|
#include <windows.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/files/file_util.h"
|
|
#include "base/files/scoped_temp_dir.h"
|
|
#include "base/strings/stringprintf.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "base/unguessable_token.h"
|
|
#include "base/win/scoped_handle.h"
|
|
#include "base/win/scoped_localalloc.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
|
|
namespace base::win {
|
|
|
|
namespace {
|
|
|
|
constexpr wchar_t kOwnerOnly[] = L"O:BU";
|
|
constexpr wchar_t kGroupOnly[] = L"G:SY";
|
|
constexpr wchar_t kDaclOnly[] = L"D:(A;;GA;;;WD)";
|
|
constexpr wchar_t kProtectedDaclOnly[] = L"D:P(A;;GA;;;WD)";
|
|
constexpr wchar_t kSaclOnly[] = L"S:(ML;;;;;SI)";
|
|
constexpr wchar_t kProtectedSaclOnly[] = L"S:P(ML;;;;;SI)";
|
|
constexpr wchar_t kSaclProtected[] = L"S:P";
|
|
constexpr wchar_t kFullSd[] = L"O:BUG:SYD:P(A;;GA;;;WD)S:P(ML;;;;;SI)";
|
|
constexpr wchar_t kFileProtected[] = L"D:P(A;;FA;;;WD)";
|
|
constexpr wchar_t kFileIntegrity[] = L"S:(ML;;NW;;;ME)";
|
|
constexpr wchar_t kFileIntegrityInherit[] = L"S:(ML;OICI;NW;;;ME)";
|
|
constexpr wchar_t kFileProtectedIntegrity[] = L"D:P(A;;FA;;;WD)S:(ML;;NW;;;ME)";
|
|
constexpr wchar_t kNewDirectory[] = L"D:P(A;OICI;FA;;;WD)";
|
|
constexpr wchar_t kInheritedFile[] = L"D:(A;ID;FA;;;WD)";
|
|
constexpr wchar_t kProtectedUsers[] = L"D:P(A;;FA;;;BU)";
|
|
constexpr wchar_t kEvent[] = L"D:(A;;0x1f0003;;;WD)";
|
|
constexpr wchar_t kEventWithSystem[] = L"D:(D;;DC;;;SY)(A;;0x1f0003;;;WD)";
|
|
constexpr wchar_t kEventSystemOnly[] = L"D:(D;;DC;;;SY)";
|
|
constexpr wchar_t kEventProtectedWithLabel[] =
|
|
L"D:P(A;;0x1f0003;;;WD)S:(ML;;NW;;;ME)";
|
|
constexpr wchar_t kEventReadControl[] = L"D:(A;;RC;;;WD)";
|
|
constexpr wchar_t kEventReadControlModify[] = L"D:(A;;DCRC;;;WD)";
|
|
constexpr wchar_t kNullDacl[] = L"D:NO_ACCESS_CONTROL";
|
|
constexpr wchar_t kEmptyDacl[] = L"D:";
|
|
constexpr wchar_t kAccessCheckSd[] = L"O:SYG:SYD:P(A;;0x1fffff;;;WD)";
|
|
constexpr SECURITY_INFORMATION kAllSecurityInfo =
|
|
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
|
|
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION;
|
|
constexpr SECURITY_INFORMATION kDaclLabelSecurityInfo =
|
|
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION;
|
|
|
|
base::win::ScopedLocalAllocTyped<void> ConvertSddlToSd(const wchar_t* sddl) {
|
|
PSECURITY_DESCRIPTOR sd = nullptr;
|
|
CHECK(ConvertStringSecurityDescriptorToSecurityDescriptor(
|
|
sddl, SDDL_REVISION_1, &sd, nullptr));
|
|
return TakeLocalAlloc(sd);
|
|
}
|
|
|
|
bool CreateFileWithSd(const FilePath& path, void* sd, bool directory) {
|
|
SECURITY_ATTRIBUTES security_attr = {};
|
|
security_attr.nLength = sizeof(security_attr);
|
|
security_attr.lpSecurityDescriptor = sd;
|
|
if (directory)
|
|
return !!::CreateDirectory(path.value().c_str(), &security_attr);
|
|
|
|
return ScopedHandle(::CreateFile(path.value().c_str(), GENERIC_ALL, 0,
|
|
&security_attr, CREATE_ALWAYS, 0, nullptr))
|
|
.is_valid();
|
|
}
|
|
|
|
bool CreateFileWithDacl(const FilePath& path,
|
|
const wchar_t* sddl,
|
|
bool directory) {
|
|
auto sd_ptr = ConvertSddlToSd(sddl);
|
|
CHECK(sd_ptr);
|
|
return CreateFileWithSd(path, sd_ptr.get(), directory);
|
|
}
|
|
|
|
base::win::ScopedHandle CreateEventWithDacl(const wchar_t* name,
|
|
const wchar_t* sddl) {
|
|
auto sd_ptr = ConvertSddlToSd(sddl);
|
|
CHECK(sd_ptr);
|
|
SECURITY_ATTRIBUTES security_attr = {};
|
|
security_attr.nLength = sizeof(security_attr);
|
|
security_attr.lpSecurityDescriptor = sd_ptr.get();
|
|
return base::win::ScopedHandle(
|
|
::CreateEvent(&security_attr, FALSE, FALSE, name));
|
|
}
|
|
|
|
base::win::ScopedHandle DuplicateHandle(const base::win::ScopedHandle& handle,
|
|
DWORD access_mask) {
|
|
HANDLE dup_handle;
|
|
CHECK(::DuplicateHandle(::GetCurrentProcess(), handle.get(),
|
|
::GetCurrentProcess(), &dup_handle, access_mask,
|
|
FALSE, 0));
|
|
return base::win::ScopedHandle(dup_handle);
|
|
}
|
|
|
|
void ExpectSid(const absl::optional<Sid>& sid, WellKnownSid known_sid) {
|
|
ASSERT_TRUE(sid);
|
|
EXPECT_EQ(*sid, Sid(known_sid));
|
|
}
|
|
|
|
void AccessCheckError(const absl::optional<AccessCheckResult>& result,
|
|
DWORD expected) {
|
|
EXPECT_FALSE(result.has_value());
|
|
EXPECT_EQ(::GetLastError(), expected);
|
|
}
|
|
|
|
void AccessCheckStatusError(const absl::optional<AccessCheckResult>& result,
|
|
DWORD expected) {
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_FALSE(result->access_status);
|
|
EXPECT_EQ(::GetLastError(), expected);
|
|
}
|
|
|
|
void AccessCheckTest(const absl::optional<AccessCheckResult>& result,
|
|
ACCESS_MASK expected_access) {
|
|
ASSERT_TRUE(result.has_value());
|
|
EXPECT_TRUE(result->access_status);
|
|
EXPECT_EQ(result->granted_access, expected_access);
|
|
}
|
|
|
|
template <typename T>
|
|
void AccessCheckTest(T type,
|
|
ACCESS_MASK generic_read,
|
|
ACCESS_MASK generic_write,
|
|
ACCESS_MASK generic_execute,
|
|
ACCESS_MASK generic_all) {
|
|
absl::optional<SecurityDescriptor> sd =
|
|
SecurityDescriptor::FromSddl(kAccessCheckSd);
|
|
ASSERT_TRUE(sd);
|
|
absl::optional<AccessToken> token = AccessToken::FromCurrentProcess(
|
|
/*impersonation=*/true, TOKEN_ADJUST_DEFAULT);
|
|
ASSERT_TRUE(token.has_value());
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_READ, type), generic_read);
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_WRITE, type), generic_write);
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_EXECUTE, type),
|
|
generic_execute);
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_ALL, type), generic_all);
|
|
AccessCheckTest(sd->AccessCheck(*token, 0x1fffff, type), 0x1fffff);
|
|
AccessCheckTest(sd->AccessCheck(*token, MAXIMUM_ALLOWED, type), 0x1fffff);
|
|
ASSERT_TRUE(sd->SetMandatoryLabel(SECURITY_MANDATORY_LOW_RID, 0,
|
|
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP));
|
|
ASSERT_TRUE(token->SetIntegrityLevel(SECURITY_MANDATORY_UNTRUSTED_RID));
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_READ, type), generic_read);
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_EXECUTE, type),
|
|
generic_execute);
|
|
AccessCheckStatusError(sd->AccessCheck(*token, GENERIC_WRITE, type),
|
|
ERROR_ACCESS_DENIED);
|
|
ASSERT_TRUE(sd->SetMandatoryLabel(SECURITY_MANDATORY_UNTRUSTED_RID, 0,
|
|
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP));
|
|
AccessCheckTest(sd->AccessCheck(*token, GENERIC_ALL, type), generic_all);
|
|
}
|
|
|
|
void AccessCheckTest(const GENERIC_MAPPING& type) {
|
|
AccessCheckTest(type, type.GenericRead, type.GenericWrite,
|
|
type.GenericExecute, type.GenericAll);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(SecurityDescriptorTest, Initialize) {
|
|
SecurityDescriptor sd;
|
|
EXPECT_FALSE(sd.owner());
|
|
EXPECT_FALSE(sd.group());
|
|
EXPECT_FALSE(sd.dacl());
|
|
EXPECT_FALSE(sd.dacl_protected());
|
|
EXPECT_FALSE(sd.sacl());
|
|
EXPECT_FALSE(sd.sacl_protected());
|
|
|
|
sd.set_owner(Sid(WellKnownSid::kBuiltinUsers));
|
|
ExpectSid(sd.owner(), WellKnownSid::kBuiltinUsers);
|
|
sd.clear_owner();
|
|
EXPECT_FALSE(sd.owner());
|
|
sd.set_group(Sid(WellKnownSid::kLocalSystem));
|
|
ExpectSid(sd.group(), WellKnownSid::kLocalSystem);
|
|
sd.clear_group();
|
|
EXPECT_FALSE(sd.group());
|
|
sd.set_dacl(AccessControlList());
|
|
EXPECT_TRUE(sd.dacl());
|
|
EXPECT_FALSE(sd.dacl()->is_null());
|
|
sd.clear_dacl();
|
|
EXPECT_FALSE(sd.dacl());
|
|
sd.set_sacl(AccessControlList());
|
|
EXPECT_TRUE(sd.sacl());
|
|
EXPECT_FALSE(sd.sacl()->is_null());
|
|
sd.clear_sacl();
|
|
EXPECT_FALSE(sd.sacl());
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, FromPointer) {
|
|
auto sd = SecurityDescriptor::FromPointer(nullptr);
|
|
EXPECT_FALSE(sd);
|
|
SECURITY_DESCRIPTOR sd_abs = {};
|
|
sd = SecurityDescriptor::FromPointer(&sd_abs);
|
|
EXPECT_FALSE(sd);
|
|
sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kOwnerOnly).get());
|
|
ASSERT_TRUE(sd);
|
|
ExpectSid(sd->owner(), WellKnownSid::kBuiltinUsers);
|
|
sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kGroupOnly).get());
|
|
ASSERT_TRUE(sd);
|
|
ExpectSid(sd->group(), WellKnownSid::kLocalSystem);
|
|
sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kDaclOnly).get());
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->dacl());
|
|
EXPECT_FALSE(sd->dacl_protected());
|
|
sd = SecurityDescriptor::FromPointer(
|
|
ConvertSddlToSd(kProtectedDaclOnly).get());
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->dacl());
|
|
EXPECT_TRUE(sd->dacl_protected());
|
|
sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kSaclOnly).get());
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->sacl());
|
|
EXPECT_FALSE(sd->sacl_protected());
|
|
sd = SecurityDescriptor::FromPointer(
|
|
ConvertSddlToSd(kProtectedSaclOnly).get());
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->sacl());
|
|
EXPECT_TRUE(sd->sacl_protected());
|
|
sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kFullSd).get());
|
|
ASSERT_TRUE(sd);
|
|
ExpectSid(sd->owner(), WellKnownSid::kBuiltinUsers);
|
|
ExpectSid(sd->group(), WellKnownSid::kLocalSystem);
|
|
EXPECT_TRUE(sd->dacl());
|
|
EXPECT_TRUE(sd->dacl_protected());
|
|
EXPECT_TRUE(sd->sacl());
|
|
EXPECT_TRUE(sd->sacl_protected());
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, ToSddl) {
|
|
auto sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kFullSd).get());
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_EQ(sd->ToSddl(0), L"");
|
|
EXPECT_EQ(sd->ToSddl(OWNER_SECURITY_INFORMATION), kOwnerOnly);
|
|
EXPECT_EQ(sd->ToSddl(GROUP_SECURITY_INFORMATION), kGroupOnly);
|
|
EXPECT_EQ(sd->ToSddl(DACL_SECURITY_INFORMATION), kProtectedDaclOnly);
|
|
EXPECT_EQ(sd->ToSddl(LABEL_SECURITY_INFORMATION), kProtectedSaclOnly);
|
|
EXPECT_EQ(sd->ToSddl(SACL_SECURITY_INFORMATION), kSaclProtected);
|
|
EXPECT_EQ(sd->ToSddl(kAllSecurityInfo), kFullSd);
|
|
SecurityDescriptor empty_sd;
|
|
empty_sd.set_dacl(AccessControlList());
|
|
EXPECT_EQ(empty_sd.ToSddl(DACL_SECURITY_INFORMATION), kEmptyDacl);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, FromSddl) {
|
|
auto sd = SecurityDescriptor::FromSddl(L"");
|
|
EXPECT_TRUE(sd);
|
|
EXPECT_FALSE(sd->owner());
|
|
EXPECT_FALSE(sd->group());
|
|
EXPECT_FALSE(sd->dacl());
|
|
EXPECT_FALSE(sd->sacl());
|
|
sd = SecurityDescriptor::FromSddl(kOwnerOnly);
|
|
ASSERT_TRUE(sd);
|
|
ExpectSid(sd->owner(), WellKnownSid::kBuiltinUsers);
|
|
sd = SecurityDescriptor::FromSddl(kGroupOnly);
|
|
ASSERT_TRUE(sd);
|
|
ExpectSid(sd->group(), WellKnownSid::kLocalSystem);
|
|
sd = SecurityDescriptor::FromSddl(kDaclOnly);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->dacl());
|
|
EXPECT_FALSE(sd->dacl_protected());
|
|
sd = SecurityDescriptor::FromSddl(kProtectedDaclOnly);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->dacl());
|
|
EXPECT_TRUE(sd->dacl_protected());
|
|
sd = SecurityDescriptor::FromSddl(kSaclOnly);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->sacl());
|
|
EXPECT_FALSE(sd->sacl_protected());
|
|
sd = SecurityDescriptor::FromSddl(kProtectedSaclOnly);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_TRUE(sd->sacl());
|
|
EXPECT_TRUE(sd->sacl_protected());
|
|
sd = SecurityDescriptor::FromSddl(kFullSd);
|
|
ASSERT_TRUE(sd);
|
|
ExpectSid(sd->owner(), WellKnownSid::kBuiltinUsers);
|
|
ExpectSid(sd->group(), WellKnownSid::kLocalSystem);
|
|
EXPECT_TRUE(sd->dacl());
|
|
EXPECT_TRUE(sd->dacl_protected());
|
|
EXPECT_TRUE(sd->sacl());
|
|
EXPECT_TRUE(sd->sacl_protected());
|
|
sd = SecurityDescriptor::FromSddl(kNullDacl);
|
|
ASSERT_TRUE(sd);
|
|
ASSERT_TRUE(sd->dacl());
|
|
EXPECT_TRUE(sd->dacl()->is_null());
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, Clone) {
|
|
SecurityDescriptor cloned = SecurityDescriptor().Clone();
|
|
EXPECT_FALSE(cloned.owner());
|
|
EXPECT_FALSE(cloned.group());
|
|
EXPECT_FALSE(cloned.dacl());
|
|
EXPECT_FALSE(cloned.dacl_protected());
|
|
EXPECT_FALSE(cloned.sacl());
|
|
EXPECT_FALSE(cloned.sacl_protected());
|
|
auto sd = SecurityDescriptor::FromSddl(kFullSd);
|
|
ASSERT_TRUE(sd);
|
|
cloned = sd->Clone();
|
|
EXPECT_EQ(sd->owner(), cloned.owner());
|
|
EXPECT_NE(sd->owner()->GetPSID(), cloned.owner()->GetPSID());
|
|
EXPECT_EQ(sd->group(), cloned.group());
|
|
EXPECT_NE(sd->group()->GetPSID(), cloned.group()->GetPSID());
|
|
EXPECT_NE(sd->dacl()->get(), cloned.dacl()->get());
|
|
EXPECT_EQ(sd->dacl_protected(), cloned.dacl_protected());
|
|
EXPECT_NE(sd->sacl()->get(), cloned.sacl()->get());
|
|
EXPECT_EQ(sd->sacl_protected(), cloned.sacl_protected());
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, ToAbsolute) {
|
|
auto sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kFullSd).get());
|
|
ASSERT_TRUE(sd);
|
|
SECURITY_DESCRIPTOR sd_abs;
|
|
sd->ToAbsolute(sd_abs);
|
|
EXPECT_EQ(sd_abs.Revision, SECURITY_DESCRIPTOR_REVISION);
|
|
EXPECT_EQ(sd_abs.Control, SE_DACL_PRESENT | SE_DACL_PROTECTED |
|
|
SE_SACL_PRESENT | SE_SACL_PROTECTED);
|
|
EXPECT_EQ(sd_abs.Owner, sd->owner()->GetPSID());
|
|
EXPECT_EQ(sd_abs.Group, sd->group()->GetPSID());
|
|
EXPECT_EQ(sd_abs.Dacl, sd->dacl()->get());
|
|
EXPECT_EQ(sd_abs.Sacl, sd->sacl()->get());
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, ToSelfRelative) {
|
|
auto sd = SecurityDescriptor::FromPointer(ConvertSddlToSd(kFullSd).get());
|
|
ASSERT_TRUE(sd);
|
|
auto sd_rel = sd->ToSelfRelative();
|
|
ASSERT_TRUE(sd_rel);
|
|
EXPECT_TRUE(sd_rel->get());
|
|
EXPECT_EQ(sd_rel->size(), ::GetSecurityDescriptorLength(sd_rel->get()));
|
|
sd = SecurityDescriptor::FromPointer(sd_rel->get());
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_EQ(sd->ToSddl(kAllSecurityInfo), kFullSd);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, SetMandatoryLabel) {
|
|
SecurityDescriptor sd;
|
|
EXPECT_FALSE(sd.sacl());
|
|
sd.SetMandatoryLabel(SECURITY_MANDATORY_SYSTEM_RID, 0, 0);
|
|
EXPECT_TRUE(sd.sacl());
|
|
EXPECT_EQ(sd.ToSddl(LABEL_SECURITY_INFORMATION), kSaclOnly);
|
|
sd.SetMandatoryLabel(SECURITY_MANDATORY_MEDIUM_RID,
|
|
OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
|
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP);
|
|
EXPECT_TRUE(sd.sacl());
|
|
EXPECT_EQ(sd.ToSddl(LABEL_SECURITY_INFORMATION), kFileIntegrityInherit);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, SetDaclEntries) {
|
|
SecurityDescriptor sd;
|
|
EXPECT_FALSE(sd.dacl());
|
|
std::vector<ExplicitAccessEntry> ace_list;
|
|
EXPECT_TRUE(sd.SetDaclEntries(ace_list));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEmptyDacl);
|
|
ace_list.emplace_back(Sid(WellKnownSid::kWorld), SecurityAccessMode::kGrant,
|
|
EVENT_ALL_ACCESS, 0);
|
|
EXPECT_TRUE(sd.SetDaclEntries(ace_list));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEvent);
|
|
ace_list.emplace_back(Sid(WellKnownSid::kLocalSystem),
|
|
SecurityAccessMode::kDeny, EVENT_MODIFY_STATE, 0);
|
|
EXPECT_TRUE(sd.SetDaclEntries(ace_list));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventWithSystem);
|
|
ace_list.emplace_back(Sid(WellKnownSid::kWorld), SecurityAccessMode::kRevoke,
|
|
EVENT_MODIFY_STATE, 0);
|
|
EXPECT_TRUE(sd.SetDaclEntries(ace_list));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventSystemOnly);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, SetDaclEntry) {
|
|
SecurityDescriptor sd;
|
|
EXPECT_TRUE(sd.SetDaclEntry(Sid(WellKnownSid::kWorld),
|
|
SecurityAccessMode::kGrant, READ_CONTROL, 0));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventReadControl);
|
|
EXPECT_TRUE(sd.SetDaclEntry(Sid(WellKnownSid::kWorld),
|
|
SecurityAccessMode::kGrant, EVENT_MODIFY_STATE,
|
|
0));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventReadControlModify);
|
|
EXPECT_TRUE(sd.SetDaclEntry(Sid(WellKnownSid::kWorld),
|
|
SecurityAccessMode::kSet, EVENT_ALL_ACCESS, 0));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEvent);
|
|
EXPECT_TRUE(sd.SetDaclEntry(Sid(WellKnownSid::kLocalSystem),
|
|
SecurityAccessMode::kDeny, EVENT_MODIFY_STATE,
|
|
0));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventWithSystem);
|
|
EXPECT_TRUE(sd.SetDaclEntry(Sid(WellKnownSid::kWorld),
|
|
SecurityAccessMode::kRevoke, EVENT_ALL_ACCESS,
|
|
0));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventSystemOnly);
|
|
sd.clear_dacl();
|
|
EXPECT_TRUE(sd.SetDaclEntry(WellKnownSid::kWorld, SecurityAccessMode::kGrant,
|
|
READ_CONTROL, 0));
|
|
EXPECT_EQ(sd.ToSddl(DACL_SECURITY_INFORMATION), kEventReadControl);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, FromFile) {
|
|
ScopedTempDir temp_dir;
|
|
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
|
|
FilePath path = temp_dir.GetPath().Append(L"test");
|
|
EXPECT_FALSE(SecurityDescriptor::FromFile(path, kAllSecurityInfo));
|
|
ASSERT_TRUE(CreateFileWithDacl(path, kFileProtectedIntegrity, false));
|
|
auto sd = SecurityDescriptor::FromFile(path, kAllSecurityInfo);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_EQ(sd->ToSddl(DACL_SECURITY_INFORMATION), kFileProtected);
|
|
sd = SecurityDescriptor::FromFile(path, LABEL_SECURITY_INFORMATION);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_EQ(sd->ToSddl(LABEL_SECURITY_INFORMATION), kFileIntegrity);
|
|
sd = SecurityDescriptor::FromFile(path, kAllSecurityInfo);
|
|
ASSERT_TRUE(sd);
|
|
EXPECT_EQ(sd->ToSddl(kDaclLabelSecurityInfo), kFileProtectedIntegrity);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, WriteToFile) {
|
|
ScopedTempDir temp_dir;
|
|
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
|
|
FilePath dir_path = temp_dir.GetPath().Append(L"test");
|
|
ASSERT_TRUE(CreateFileWithDacl(dir_path, kNewDirectory, true));
|
|
FilePath path = dir_path.Append(L"test");
|
|
ASSERT_TRUE(CreateFileWithSd(path, nullptr, false));
|
|
|
|
auto curr_sd = SecurityDescriptor::FromFile(path, DACL_SECURITY_INFORMATION);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(DACL_SECURITY_INFORMATION), kInheritedFile);
|
|
|
|
AccessControlList new_acl;
|
|
EXPECT_TRUE(new_acl.SetEntry(Sid(WellKnownSid::kBuiltinUsers),
|
|
SecurityAccessMode::kGrant, FILE_ALL_ACCESS, 0));
|
|
SecurityDescriptor new_sd;
|
|
new_sd.set_dacl(new_acl);
|
|
new_sd.set_dacl_protected(true);
|
|
EXPECT_TRUE(new_sd.WriteToFile(path, DACL_SECURITY_INFORMATION));
|
|
curr_sd = SecurityDescriptor::FromFile(path, DACL_SECURITY_INFORMATION);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(DACL_SECURITY_INFORMATION), kProtectedUsers);
|
|
|
|
SecurityDescriptor empty_sd;
|
|
empty_sd.set_dacl(AccessControlList{});
|
|
EXPECT_TRUE(empty_sd.WriteToFile(path, DACL_SECURITY_INFORMATION));
|
|
curr_sd = SecurityDescriptor::FromFile(path, DACL_SECURITY_INFORMATION);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(DACL_SECURITY_INFORMATION), kInheritedFile);
|
|
|
|
auto label_acl = AccessControlList::FromMandatoryLabel(
|
|
SECURITY_MANDATORY_MEDIUM_RID, 0, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP);
|
|
ASSERT_TRUE(label_acl);
|
|
SecurityDescriptor label_sd;
|
|
label_sd.set_sacl(*label_acl);
|
|
EXPECT_TRUE(label_sd.WriteToFile(path, LABEL_SECURITY_INFORMATION));
|
|
curr_sd = SecurityDescriptor::FromFile(path, LABEL_SECURITY_INFORMATION);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(LABEL_SECURITY_INFORMATION), kFileIntegrity);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, FromName) {
|
|
std::wstring name =
|
|
base::ASCIIToWide(base::UnguessableToken::Create().ToString());
|
|
EXPECT_FALSE(SecurityDescriptor::FromName(
|
|
name.c_str(), SecurityObjectType::kKernel, kAllSecurityInfo));
|
|
base::win::ScopedHandle handle = CreateEventWithDacl(name.c_str(), kEvent);
|
|
ASSERT_TRUE(handle.is_valid());
|
|
auto curr_sd = SecurityDescriptor::FromName(
|
|
name.c_str(), SecurityObjectType::kKernel, kAllSecurityInfo);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(DACL_SECURITY_INFORMATION), kEvent);
|
|
EXPECT_TRUE(SecurityDescriptor::FromName(
|
|
L"MACHINE\\SOFTWARE", SecurityObjectType::kRegistry, kAllSecurityInfo));
|
|
EXPECT_TRUE(SecurityDescriptor::FromName(L".", SecurityObjectType::kFile,
|
|
kAllSecurityInfo));
|
|
EXPECT_FALSE(SecurityDescriptor::FromName(
|
|
L"WinSta0", SecurityObjectType::kWindowStation, kAllSecurityInfo));
|
|
EXPECT_FALSE(SecurityDescriptor::FromName(
|
|
L"Default", SecurityObjectType::kDesktop, kAllSecurityInfo));
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, WriteToName) {
|
|
std::wstring name =
|
|
base::ASCIIToWide(base::UnguessableToken::Create().ToString());
|
|
EXPECT_FALSE(SecurityDescriptor().WriteToName(
|
|
name.c_str(), SecurityObjectType::kKernel, kAllSecurityInfo));
|
|
base::win::ScopedHandle handle = CreateEventWithDacl(name.c_str(), kEvent);
|
|
ASSERT_TRUE(handle.is_valid());
|
|
auto curr_sd = SecurityDescriptor::FromName(
|
|
name.c_str(), SecurityObjectType::kKernel, kAllSecurityInfo);
|
|
ASSERT_TRUE(curr_sd);
|
|
curr_sd->set_dacl_protected(true);
|
|
curr_sd->SetMandatoryLabel(SECURITY_MANDATORY_MEDIUM_RID, 0,
|
|
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP);
|
|
|
|
EXPECT_TRUE(curr_sd->WriteToName(name.c_str(), SecurityObjectType::kKernel,
|
|
kDaclLabelSecurityInfo));
|
|
|
|
curr_sd = SecurityDescriptor::FromName(
|
|
name.c_str(), SecurityObjectType::kKernel, kAllSecurityInfo);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(kDaclLabelSecurityInfo), kEventProtectedWithLabel);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, FromHandle) {
|
|
EXPECT_FALSE(SecurityDescriptor::FromHandle(
|
|
nullptr, SecurityObjectType::kKernel, kAllSecurityInfo));
|
|
auto handle = CreateEventWithDacl(nullptr, kEvent);
|
|
ASSERT_TRUE(handle.is_valid());
|
|
auto curr_sd = SecurityDescriptor::FromHandle(
|
|
handle.get(), SecurityObjectType::kKernel, kAllSecurityInfo);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(DACL_SECURITY_INFORMATION), kEvent);
|
|
auto dup_handle = DuplicateHandle(handle, EVENT_MODIFY_STATE);
|
|
EXPECT_FALSE(SecurityDescriptor::FromHandle(
|
|
dup_handle.get(), SecurityObjectType::kKernel, kAllSecurityInfo));
|
|
EXPECT_TRUE(SecurityDescriptor::FromHandle(::GetProcessWindowStation(),
|
|
SecurityObjectType::kWindowStation,
|
|
kAllSecurityInfo));
|
|
EXPECT_TRUE(SecurityDescriptor::FromHandle(
|
|
::GetThreadDesktop(::GetCurrentThreadId()), SecurityObjectType::kDesktop,
|
|
kAllSecurityInfo));
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, WriteToHandle) {
|
|
EXPECT_FALSE(SecurityDescriptor().WriteToHandle(
|
|
nullptr, SecurityObjectType::kKernel, kAllSecurityInfo));
|
|
base::win::ScopedHandle handle = CreateEventWithDacl(nullptr, kEvent);
|
|
ASSERT_TRUE(handle.is_valid());
|
|
auto curr_sd = SecurityDescriptor::FromHandle(
|
|
handle.get(), SecurityObjectType::kKernel, kAllSecurityInfo);
|
|
EXPECT_EQ(curr_sd->ToSddl(DACL_SECURITY_INFORMATION), kEvent);
|
|
ASSERT_TRUE(curr_sd);
|
|
curr_sd->set_dacl_protected(true);
|
|
curr_sd->SetMandatoryLabel(SECURITY_MANDATORY_MEDIUM_RID, 0,
|
|
SYSTEM_MANDATORY_LABEL_NO_WRITE_UP);
|
|
|
|
EXPECT_TRUE(curr_sd->WriteToHandle(handle.get(), SecurityObjectType::kKernel,
|
|
kDaclLabelSecurityInfo));
|
|
|
|
curr_sd = SecurityDescriptor::FromHandle(
|
|
handle.get(), SecurityObjectType::kKernel, kAllSecurityInfo);
|
|
ASSERT_TRUE(curr_sd);
|
|
EXPECT_EQ(curr_sd->ToSddl(kDaclLabelSecurityInfo), kEventProtectedWithLabel);
|
|
}
|
|
|
|
TEST(SecurityDescriptorTest, AccessCheck) {
|
|
absl::optional<SecurityDescriptor> sd =
|
|
SecurityDescriptor::FromSddl(kAccessCheckSd);
|
|
ASSERT_TRUE(sd);
|
|
absl::optional<AccessToken> token = AccessToken::FromCurrentProcess();
|
|
ASSERT_TRUE(token);
|
|
AccessCheckError(sd->AccessCheck(*token, 1, SecurityObjectType::kFile),
|
|
ERROR_NO_IMPERSONATION_TOKEN);
|
|
token = AccessToken::FromCurrentProcess(/*impersonation=*/true);
|
|
ASSERT_TRUE(token);
|
|
AccessCheckError(sd->AccessCheck(*token, 1, SecurityObjectType::kKernel),
|
|
ERROR_INVALID_PARAMETER);
|
|
sd->set_dacl(AccessControlList());
|
|
AccessCheckStatusError(sd->AccessCheck(*token, 1, SecurityObjectType::kFile),
|
|
ERROR_ACCESS_DENIED);
|
|
sd->clear_owner();
|
|
AccessCheckError(sd->AccessCheck(*token, 1, SecurityObjectType::kFile),
|
|
ERROR_INVALID_SECURITY_DESCR);
|
|
AccessCheckTest({1, 2, 4, 8});
|
|
AccessCheckTest(SecurityObjectType::kFile, FILE_GENERIC_READ,
|
|
FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS);
|
|
AccessCheckTest(SecurityObjectType::kRegistry, KEY_READ, KEY_WRITE,
|
|
KEY_EXECUTE, KEY_ALL_ACCESS);
|
|
AccessCheckTest(
|
|
SecurityObjectType::kDesktop,
|
|
STANDARD_RIGHTS_READ | DESKTOP_READOBJECTS | DESKTOP_ENUMERATE,
|
|
STANDARD_RIGHTS_WRITE | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
|
|
DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD |
|
|
DESKTOP_JOURNALPLAYBACK | DESKTOP_WRITEOBJECTS,
|
|
STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP,
|
|
STANDARD_RIGHTS_REQUIRED | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
|
|
DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK |
|
|
DESKTOP_JOURNALRECORD | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP |
|
|
DESKTOP_WRITEOBJECTS);
|
|
AccessCheckTest(
|
|
SecurityObjectType::kWindowStation,
|
|
STANDARD_RIGHTS_READ | WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE |
|
|
WINSTA_READATTRIBUTES | WINSTA_READSCREEN,
|
|
STANDARD_RIGHTS_WRITE | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP |
|
|
WINSTA_WRITEATTRIBUTES,
|
|
STANDARD_RIGHTS_EXECUTE | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS,
|
|
STANDARD_RIGHTS_REQUIRED | WINSTA_ACCESSCLIPBOARD |
|
|
WINSTA_ACCESSGLOBALATOMS | WINSTA_CREATEDESKTOP |
|
|
WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_EXITWINDOWS |
|
|
WINSTA_READATTRIBUTES | WINSTA_READSCREEN | WINSTA_WRITEATTRIBUTES);
|
|
}
|
|
|
|
} // namespace base::win
|