• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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