// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sandbox/win/src/acl.h"
#include <windows.h>
#include "base/win/scoped_handle.h"
#include "base/win/security_descriptor.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sandbox {
namespace {
void CheckGetIntegrityLevelSid(IntegrityLevel integrity_level,
const wchar_t* sddl) {
std::optional<base::win::Sid> sddl_sid = base::win::Sid::FromSddlString(sddl);
ASSERT_TRUE(sddl_sid);
std::optional<DWORD> integrity_value = GetIntegrityLevelRid(integrity_level);
ASSERT_TRUE(integrity_value);
EXPECT_EQ(*sddl_sid, base::win::Sid::FromIntegrityLevel(*integrity_value));
}
void CheckSetObjectIntegrityLabel(DWORD mandatory_policy,
IntegrityLevel integrity_level,
DWORD expected_error = ERROR_SUCCESS) {
base::win::ScopedHandle job(::CreateJobObject(nullptr, nullptr));
DWORD result =
SetObjectIntegrityLabel(job.get(), base::win::SecurityObjectType::kKernel,
mandatory_policy, integrity_level);
EXPECT_EQ(result, expected_error);
if (result != ERROR_SUCCESS)
return;
std::optional<base::win::SecurityDescriptor> sd =
base::win::SecurityDescriptor::FromHandle(
job.get(), base::win::SecurityObjectType::kKernel,
LABEL_SECURITY_INFORMATION);
ASSERT_TRUE(sd);
PACL sacl = sd->sacl()->get();
ASSERT_EQ(sacl->AceCount, 1);
LPVOID ace_ptr;
ASSERT_TRUE(::GetAce(sacl, 0, &ace_ptr));
PSYSTEM_MANDATORY_LABEL_ACE ace =
static_cast<PSYSTEM_MANDATORY_LABEL_ACE>(ace_ptr);
ASSERT_EQ(ace->Header.AceType, SYSTEM_MANDATORY_LABEL_ACE_TYPE);
EXPECT_EQ(ace->Header.AceFlags, 0);
EXPECT_EQ(ace->Mask, mandatory_policy);
std::optional<DWORD> rid = GetIntegrityLevelRid(integrity_level);
base::win::Sid sid = base::win::Sid::FromIntegrityLevel(*rid);
ASSERT_TRUE(::IsValidSid(&ace->SidStart));
EXPECT_TRUE(sid.Equal(&ace->SidStart));
}
} // namespace
// Checks the functionality of GetIntegrityLevelRid.
TEST(AclTest, GetIntegrityLevelRid) {
EXPECT_FALSE(GetIntegrityLevelRid(INTEGRITY_LEVEL_LAST));
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_SYSTEM, L"S-1-16-16384");
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_HIGH, L"S-1-16-12288");
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_MEDIUM, L"S-1-16-8192");
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_MEDIUM_LOW, L"S-1-16-6144");
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_LOW, L"S-1-16-4096");
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_BELOW_LOW, L"S-1-16-2048");
CheckGetIntegrityLevelSid(INTEGRITY_LEVEL_UNTRUSTED, L"S-1-16-0");
}
// Checks the functionality of SetObjectIntegrityLabel.
TEST(AclTest, SetObjectIntegrityLabel) {
EXPECT_EQ(
SetObjectIntegrityLabel(nullptr, base::win::SecurityObjectType::kKernel,
0, INTEGRITY_LEVEL_LAST),
DWORD{ERROR_INVALID_SID});
EXPECT_EQ(
SetObjectIntegrityLabel(nullptr, base::win::SecurityObjectType::kKernel,
0, INTEGRITY_LEVEL_LOW),
DWORD{ERROR_INVALID_HANDLE});
// This assumes that the caller doesn't have SeRelabelPrivilege or is running
// as a service process.
CheckSetObjectIntegrityLabel(0, INTEGRITY_LEVEL_SYSTEM, ERROR_INVALID_LABEL);
CheckSetObjectIntegrityLabel(0, INTEGRITY_LEVEL_LOW);
CheckSetObjectIntegrityLabel(0, INTEGRITY_LEVEL_UNTRUSTED);
CheckSetObjectIntegrityLabel(SYSTEM_MANDATORY_LABEL_NO_WRITE_UP,
INTEGRITY_LEVEL_LOW);
CheckSetObjectIntegrityLabel(SYSTEM_MANDATORY_LABEL_NO_READ_UP,
INTEGRITY_LEVEL_LOW);
CheckSetObjectIntegrityLabel(SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP,
INTEGRITY_LEVEL_LOW);
CheckSetObjectIntegrityLabel(SYSTEM_MANDATORY_LABEL_NO_WRITE_UP |
SYSTEM_MANDATORY_LABEL_NO_READ_UP |
SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP,
INTEGRITY_LEVEL_LOW);
}
} // namespace sandbox