1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/win/access_control_list.h"
11
12 // clang-format off
13 #include <windows.h> // Must be in front of other Windows header files.
14 // clang-format on
15
16 #include <sddl.h>
17
18 #include <string>
19 #include <vector>
20
21 #include "base/check.h"
22 #include "base/strings/string_number_conversions_win.h"
23 #include "base/win/scoped_localalloc.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace base::win {
27
28 namespace {
29
30 constexpr wchar_t kFromPACLTest[] = L"(D;;FX;;;SY)(A;;GA;;;WD)";
31 constexpr wchar_t kNullAcl[] = L"NO_ACCESS_CONTROL";
32 constexpr wchar_t kEvent[] = L"(A;;0x1f0003;;;WD)";
33 constexpr wchar_t kEventWithSystemInherit[] =
34 L"(D;OICI;DC;;;SY)(A;;0x1f0003;;;WD)";
35 constexpr wchar_t kEventSystemOnlyInherit[] = L"(D;OICI;DC;;;SY)";
36 constexpr wchar_t kEventReadControl[] = L"(A;;RC;;;WD)";
37 constexpr wchar_t kEventReadControlModify[] = L"(A;;DCRC;;;WD)";
38 constexpr wchar_t kUntrustedLabel[] = L"(ML;;;;;S-1-16-0)";
39 constexpr wchar_t kSystemLabel[] = L"(ML;;;;;SI)";
40 constexpr wchar_t kSystemLabelInherit[] = L"(ML;OICI;;;;SI)";
41 constexpr wchar_t kSystemLabelPolicy[] = L"(ML;;NWNRNX;;;SI)";
42 constexpr wchar_t kSystemLabelInheritPolicy[] = L"(ML;OICI;NWNRNX;;;SI)";
43 constexpr wchar_t kDaclPrefix[] = L"D:";
44 constexpr wchar_t kSaclPrefix[] = L"S:";
45
ConvertSddlToAcl(const wchar_t * sddl)46 std::vector<char> ConvertSddlToAcl(const wchar_t* sddl) {
47 std::wstring sddl_dacl = kDaclPrefix;
48 sddl_dacl += sddl;
49 PSECURITY_DESCRIPTOR sd = nullptr;
50 CHECK(::ConvertStringSecurityDescriptorToSecurityDescriptor(
51 sddl_dacl.c_str(), SDDL_REVISION_1, &sd, nullptr));
52 auto sd_ptr = TakeLocalAlloc(sd);
53 CHECK(sd_ptr);
54 BOOL present = FALSE;
55 BOOL defaulted = FALSE;
56 PACL dacl = nullptr;
57 CHECK(::GetSecurityDescriptorDacl(sd_ptr.get(), &present, &dacl, &defaulted));
58 CHECK(present);
59 char* dacl_ptr = reinterpret_cast<char*>(dacl);
60 return std::vector<char>(dacl_ptr, dacl_ptr + dacl->AclSize);
61 }
62
ConvertAclToSddl(const AccessControlList & acl,bool label=false)63 std::wstring ConvertAclToSddl(const AccessControlList& acl,
64 bool label = false) {
65 // WinAPI is not const-correct so even non-modifying methods accept non-const
66 // pointers. Copy the const-qualified `acl` so that we can call non-const
67 // versions of getters on it and pass the results to WinAPI.
68 auto acl_copy = acl.Clone();
69 SECURITY_DESCRIPTOR sd = {};
70 CHECK(::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));
71 if (label) {
72 CHECK(::SetSecurityDescriptorSacl(&sd, TRUE, acl_copy.get(), FALSE));
73 } else {
74 CHECK(::SetSecurityDescriptorDacl(&sd, TRUE, acl_copy.get(), FALSE));
75 }
76 LPWSTR sddl_str = nullptr;
77 CHECK(::ConvertSecurityDescriptorToStringSecurityDescriptor(
78 &sd, SDDL_REVISION_1,
79 label ? LABEL_SECURITY_INFORMATION : DACL_SECURITY_INFORMATION, &sddl_str,
80 nullptr));
81 auto sddl_str_ptr = TakeLocalAlloc(sddl_str);
82 std::wstring ret = sddl_str_ptr.get();
83 CHECK(ret.substr(0, 2) == (label ? kSaclPrefix : kDaclPrefix));
84 return ret.substr(2);
85 }
86 } // namespace
87
TEST(AccessControlListTest,FromPACL)88 TEST(AccessControlListTest, FromPACL) {
89 auto null_acl = AccessControlList::FromPACL(nullptr);
90 ASSERT_TRUE(null_acl);
91 EXPECT_TRUE(null_acl->is_null());
92 EXPECT_EQ(null_acl->get(), nullptr);
93 EXPECT_EQ(ConvertAclToSddl(*null_acl), kNullAcl);
94
95 ACL dummy_acl = {};
96 auto invalid_acl = AccessControlList::FromPACL(&dummy_acl);
97 DWORD error = ::GetLastError();
98 EXPECT_FALSE(invalid_acl);
99 EXPECT_EQ(error, DWORD{ERROR_INVALID_ACL});
100
101 std::vector<char> compare_acl = ConvertSddlToAcl(kFromPACLTest);
102 ASSERT_FALSE(compare_acl.empty());
103 auto test_acl =
104 AccessControlList::FromPACL(reinterpret_cast<ACL*>(compare_acl.data()));
105 ASSERT_TRUE(test_acl);
106 EXPECT_EQ(ConvertAclToSddl(*test_acl), kFromPACLTest);
107 }
108
TEST(AccessControlListTest,FromMandatoryLabel)109 TEST(AccessControlListTest, FromMandatoryLabel) {
110 auto acl = AccessControlList::FromMandatoryLabel(0, 0, 0);
111 ASSERT_TRUE(acl);
112 EXPECT_EQ(ConvertAclToSddl(*acl, true), kUntrustedLabel);
113 acl = AccessControlList::FromMandatoryLabel(SECURITY_MANDATORY_SYSTEM_RID, 0,
114 0);
115 ASSERT_TRUE(acl);
116 EXPECT_EQ(ConvertAclToSddl(*acl, true), kSystemLabel);
117 acl = AccessControlList::FromMandatoryLabel(
118 SECURITY_MANDATORY_SYSTEM_RID, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
119 0);
120 ASSERT_TRUE(acl);
121 EXPECT_EQ(ConvertAclToSddl(*acl, true), kSystemLabelInherit);
122 acl = AccessControlList::FromMandatoryLabel(
123 SECURITY_MANDATORY_SYSTEM_RID, 0,
124 SYSTEM_MANDATORY_LABEL_NO_WRITE_UP | SYSTEM_MANDATORY_LABEL_NO_READ_UP |
125 SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP);
126 ASSERT_TRUE(acl);
127 EXPECT_EQ(ConvertAclToSddl(*acl, true), kSystemLabelPolicy);
128 acl = AccessControlList::FromMandatoryLabel(
129 SECURITY_MANDATORY_SYSTEM_RID, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
130 SYSTEM_MANDATORY_LABEL_NO_WRITE_UP | SYSTEM_MANDATORY_LABEL_NO_READ_UP |
131 SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP);
132 ASSERT_TRUE(acl);
133 EXPECT_EQ(ConvertAclToSddl(*acl, true), kSystemLabelInheritPolicy);
134 }
135
TEST(AccessControlListTest,Empty)136 TEST(AccessControlListTest, Empty) {
137 AccessControlList acl;
138 EXPECT_FALSE(acl.is_null());
139 ACL* acl_ptr = acl.get();
140 ASSERT_NE(acl_ptr, nullptr);
141 EXPECT_EQ(acl_ptr->AceCount, 0);
142 EXPECT_EQ(acl_ptr->AclSize, sizeof(ACL));
143 EXPECT_EQ(acl_ptr->AclRevision, ACL_REVISION);
144 EXPECT_TRUE(ConvertAclToSddl(acl).empty());
145 AccessControlList acl_clone = acl.Clone();
146 EXPECT_NE(acl.get(), acl_clone.get());
147 EXPECT_TRUE(ConvertAclToSddl(acl_clone).empty());
148 }
149
TEST(AccessControlListTest,ExplicitAccessEntry)150 TEST(AccessControlListTest, ExplicitAccessEntry) {
151 constexpr DWORD FakeAccess = 0x12345678U;
152 constexpr DWORD FakeInherit = 0x87654321U;
153 Sid sid(WellKnownSid::kWorld);
154 ExplicitAccessEntry ace(sid, SecurityAccessMode::kGrant, FakeAccess,
155 FakeInherit);
156 EXPECT_EQ(sid, ace.sid());
157 EXPECT_EQ(SecurityAccessMode::kGrant, ace.mode());
158 EXPECT_EQ(FakeAccess, ace.access_mask());
159 EXPECT_EQ(FakeInherit, ace.inheritance());
160 ExplicitAccessEntry ace_clone = ace.Clone();
161 EXPECT_EQ(ace.sid(), ace_clone.sid());
162 EXPECT_NE(ace.sid().GetPSID(), ace_clone.sid().GetPSID());
163 EXPECT_EQ(ace.mode(), ace_clone.mode());
164 EXPECT_EQ(ace.access_mask(), ace_clone.access_mask());
165 EXPECT_EQ(ace.inheritance(), ace_clone.inheritance());
166 ExplicitAccessEntry ace_known(WellKnownSid::kSelf,
167 SecurityAccessMode::kRevoke, ~FakeAccess,
168 ~FakeInherit);
169 EXPECT_EQ(Sid(WellKnownSid::kSelf), ace_known.sid());
170 EXPECT_EQ(SecurityAccessMode::kRevoke, ace_known.mode());
171 EXPECT_EQ(~FakeAccess, ace_known.access_mask());
172 EXPECT_EQ(~FakeInherit, ace_known.inheritance());
173 }
174
TEST(AccessControlListTest,SetEntries)175 TEST(AccessControlListTest, SetEntries) {
176 AccessControlList acl;
177 std::vector<ExplicitAccessEntry> ace_list;
178 EXPECT_TRUE(acl.SetEntries(ace_list));
179 EXPECT_EQ(ConvertAclToSddl(acl), L"");
180 ace_list.emplace_back(Sid(WellKnownSid::kWorld), SecurityAccessMode::kGrant,
181 EVENT_ALL_ACCESS, 0);
182 EXPECT_TRUE(acl.SetEntries(ace_list));
183 EXPECT_EQ(ConvertAclToSddl(acl), kEvent);
184 ace_list.emplace_back(Sid(WellKnownSid::kLocalSystem),
185 SecurityAccessMode::kDeny, EVENT_MODIFY_STATE,
186 CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
187 EXPECT_TRUE(acl.SetEntries(ace_list));
188 EXPECT_EQ(ConvertAclToSddl(acl), kEventWithSystemInherit);
189 ace_list.emplace_back(Sid(WellKnownSid::kWorld), SecurityAccessMode::kRevoke,
190 EVENT_MODIFY_STATE, 0);
191 EXPECT_TRUE(acl.SetEntries(ace_list));
192 EXPECT_EQ(ConvertAclToSddl(acl), kEventSystemOnlyInherit);
193 AccessControlList acl_clone = acl.Clone();
194 EXPECT_NE(acl.get(), acl_clone.get());
195 EXPECT_EQ(ConvertAclToSddl(acl_clone), kEventSystemOnlyInherit);
196 }
197
TEST(AccessControlListTest,SetEntry)198 TEST(AccessControlListTest, SetEntry) {
199 AccessControlList acl;
200 EXPECT_TRUE(acl.SetEntry(Sid(WellKnownSid::kWorld),
201 SecurityAccessMode::kGrant, READ_CONTROL, 0));
202 EXPECT_EQ(ConvertAclToSddl(acl), kEventReadControl);
203 EXPECT_TRUE(acl.SetEntry(Sid(WellKnownSid::kWorld),
204 SecurityAccessMode::kGrant, EVENT_MODIFY_STATE, 0));
205 EXPECT_EQ(ConvertAclToSddl(acl), kEventReadControlModify);
206 EXPECT_TRUE(acl.SetEntry(Sid(WellKnownSid::kWorld), SecurityAccessMode::kSet,
207 EVENT_ALL_ACCESS, 0));
208 EXPECT_EQ(ConvertAclToSddl(acl), kEvent);
209 EXPECT_TRUE(acl.SetEntry(Sid(WellKnownSid::kLocalSystem),
210 SecurityAccessMode::kDeny, EVENT_MODIFY_STATE,
211 CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE));
212 EXPECT_EQ(ConvertAclToSddl(acl), kEventWithSystemInherit);
213 EXPECT_TRUE(acl.SetEntry(Sid(WellKnownSid::kWorld),
214 SecurityAccessMode::kRevoke, EVENT_ALL_ACCESS, 0));
215 EXPECT_EQ(ConvertAclToSddl(acl), kEventSystemOnlyInherit);
216 }
217
TEST(AccessControlListTest,SetEntriesError)218 TEST(AccessControlListTest, SetEntriesError) {
219 AccessControlList acl;
220 std::vector<ExplicitAccessEntry> ace_list;
221 ace_list.emplace_back(Sid(WellKnownSid::kWorld), SecurityAccessMode::kGrant,
222 EVENT_ALL_ACCESS, 0);
223 EXPECT_TRUE(acl.SetEntries(ace_list));
224 EXPECT_EQ(ConvertAclToSddl(acl), kEvent);
225 // ACL has a maximum capacity of 2^16-1 bytes or 2^16-1 ACEs. Force a fail.
226 while (ace_list.size() < 0x10000) {
227 auto sid =
228 Sid::FromSddlString(L"S-1-5-1234-" + NumberToWString(ace_list.size()));
229 ASSERT_TRUE(sid);
230 ace_list.emplace_back(*sid, SecurityAccessMode::kGrant, GENERIC_ALL, 0);
231 }
232 ::SetLastError(0);
233 bool result = acl.SetEntries(ace_list);
234 DWORD error = ::GetLastError();
235 EXPECT_FALSE(result);
236 EXPECT_EQ(error, DWORD{ERROR_INVALID_PARAMETER});
237 }
238
TEST(AccessControlListTest,Clear)239 TEST(AccessControlListTest, Clear) {
240 AccessControlList acl;
241 EXPECT_TRUE(acl.SetEntry(Sid(WellKnownSid::kWorld),
242 SecurityAccessMode::kGrant, READ_CONTROL, 0));
243 EXPECT_EQ(acl.get()->AceCount, 1);
244 acl.Clear();
245 ASSERT_NE(acl.get(), nullptr);
246 EXPECT_EQ(acl.get()->AceCount, 0);
247 }
248
249 } // namespace base::win
250