xref: /aosp_15_r20/external/cronet/base/win/security_util_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 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 #include "base/win/security_util.h"
6 
7 // clang-format off
8 #include <windows.h>  // Must be in front of other Windows header files.
9 // clang-format on
10 
11 #include <aclapi.h>
12 #include <sddl.h>
13 
14 #include <utility>
15 
16 #include "base/files/file_util.h"
17 #include "base/files/scoped_temp_dir.h"
18 #include "base/strings/string_number_conversions_win.h"
19 #include "base/win/scoped_handle.h"
20 #include "base/win/scoped_localalloc.h"
21 #include "base/win/sid.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 
24 namespace base {
25 namespace win {
26 
27 namespace {
28 
29 constexpr wchar_t kBaseDacl[] = L"D:P(A;;FA;;;WD)";
30 constexpr wchar_t kTest1Dacl[] = L"D:PAI(A;;FR;;;AU)(A;;FA;;;WD)";
31 constexpr wchar_t kTest2Dacl[] = L"D:PAI(A;;FA;;;BA)(A;;FA;;;AU)(A;;FA;;;WD)";
32 constexpr wchar_t kTest1DenyDacl[] = L"D:PAI(D;;FR;;;LG)(A;;FA;;;WD)";
33 constexpr wchar_t kTest1DaclNoInherit[] = L"D:P(A;;FR;;;AU)(A;;FA;;;WD)";
34 constexpr wchar_t kTest2DaclNoInherit[] =
35     L"D:P(A;;FA;;;BA)(A;;FA;;;AU)(A;;FA;;;WD)";
36 
37 constexpr wchar_t kBaseDirDacl[] = L"D:P(A;OICI;FA;;;WD)";
38 constexpr wchar_t kTest1InheritedDacl[] = L"D:(A;ID;FA;;;WD)";
39 constexpr wchar_t kBaseDir2Dacl[] = L"D:PAI(A;OICI;FR;;;AU)(A;OICI;FA;;;WD)";
40 constexpr wchar_t kTest2InheritedDacl[] = L"D:AI(A;ID;FR;;;AU)(A;ID;FA;;;WD)";
41 constexpr wchar_t kBaseDir2DaclNoInherit[] =
42     L"D:P(A;OICI;FR;;;AU)(A;OICI;FA;;;WD)";
43 constexpr wchar_t kTest2InheritedDaclNoInherit[] = L"D:P(A;;FA;;;WD)";
44 constexpr wchar_t kTest3InheritedDacl[] = L"D:(A;ID;FR;;;AU)(A;ID;FA;;;WD)";
45 
46 constexpr wchar_t kNoWriteDacDacl[] = L"D:(D;;WD;;;OW)(A;;FRSD;;;WD)";
47 
48 constexpr wchar_t kAuthenticatedUsersSid[] = L"AU";
49 constexpr wchar_t kLocalGuestSid[] = L"LG";
50 
GetFileDacl(const FilePath & path)51 std::wstring GetFileDacl(const FilePath& path) {
52   PSECURITY_DESCRIPTOR sd;
53   if (::GetNamedSecurityInfo(path.value().c_str(), SE_FILE_OBJECT,
54                              DACL_SECURITY_INFORMATION, nullptr, nullptr,
55                              nullptr, nullptr, &sd) != ERROR_SUCCESS) {
56     return std::wstring();
57   }
58   auto sd_ptr = TakeLocalAlloc(sd);
59   LPWSTR sddl;
60   if (!::ConvertSecurityDescriptorToStringSecurityDescriptor(
61           sd_ptr.get(), SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &sddl,
62           nullptr)) {
63     return std::wstring();
64   }
65   return TakeLocalAlloc(sddl).get();
66 }
67 
CreateWithDacl(const FilePath & path,const wchar_t * sddl,bool directory)68 bool CreateWithDacl(const FilePath& path, const wchar_t* sddl, bool directory) {
69   PSECURITY_DESCRIPTOR sd;
70   if (!::ConvertStringSecurityDescriptorToSecurityDescriptor(
71           sddl, SDDL_REVISION_1, &sd, nullptr)) {
72     return false;
73   }
74   auto sd_ptr = TakeLocalAlloc(sd);
75   SECURITY_ATTRIBUTES security_attr = {};
76   security_attr.nLength = sizeof(security_attr);
77   security_attr.lpSecurityDescriptor = sd_ptr.get();
78   if (directory)
79     return !!::CreateDirectory(path.value().c_str(), &security_attr);
80 
81   return ScopedHandle(::CreateFile(path.value().c_str(), GENERIC_ALL, 0,
82                                    &security_attr, CREATE_ALWAYS, 0, nullptr))
83       .is_valid();
84 }
85 
86 }  // namespace
87 
TEST(SecurityUtilTest,GrantAccessToPathErrorCase)88 TEST(SecurityUtilTest, GrantAccessToPathErrorCase) {
89   ScopedTempDir temp_dir;
90   auto sids = Sid::FromSddlStringVector({kAuthenticatedUsersSid});
91   ASSERT_TRUE(sids);
92   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
93   FilePath path = temp_dir.GetPath().Append(L"test");
94   EXPECT_FALSE(
95       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
96   EXPECT_FALSE(
97       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, false));
98   ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
99   EXPECT_TRUE(
100       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
101   EXPECT_TRUE(
102       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, false));
103   std::vector<Sid> large_sid_list;
104   while (large_sid_list.size() < 0x10000) {
105     auto sid = Sid::FromSddlString(L"S-1-5-1234-" +
106                                    NumberToWString(large_sid_list.size()));
107     ASSERT_TRUE(sid);
108     large_sid_list.emplace_back(std::move(*sid));
109   }
110   EXPECT_FALSE(GrantAccessToPath(path, large_sid_list, FILE_GENERIC_READ,
111                                  NO_INHERITANCE, false));
112   path = temp_dir.GetPath().Append(L"test_nowritedac");
113   ASSERT_TRUE(CreateWithDacl(path, kNoWriteDacDacl, false));
114   EXPECT_FALSE(
115       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
116   EXPECT_FALSE(
117       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, false));
118 }
119 
TEST(SecurityUtilTest,GrantAccessToPathFile)120 TEST(SecurityUtilTest, GrantAccessToPathFile) {
121   ScopedTempDir temp_dir;
122   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
123   FilePath path = temp_dir.GetPath().Append(L"test");
124   ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
125   EXPECT_EQ(kBaseDacl, GetFileDacl(path));
126   auto sids = Sid::FromSddlStringVector({kAuthenticatedUsersSid});
127   ASSERT_TRUE(sids);
128   EXPECT_TRUE(
129       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
130   EXPECT_EQ(kTest1Dacl, GetFileDacl(path));
131   auto sids2 = Sid::FromSddlStringVector({L"S-1-5-11", L"BA"});
132   ASSERT_TRUE(sids2);
133   EXPECT_TRUE(
134       GrantAccessToPath(path, *sids2, GENERIC_ALL, NO_INHERITANCE, true));
135   EXPECT_EQ(kTest2Dacl, GetFileDacl(path));
136 }
137 
TEST(SecurityUtilTest,GrantAccessToPathFileNoInherit)138 TEST(SecurityUtilTest, GrantAccessToPathFileNoInherit) {
139   ScopedTempDir temp_dir;
140   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
141   FilePath path = temp_dir.GetPath().Append(L"test");
142   ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
143   EXPECT_EQ(kBaseDacl, GetFileDacl(path));
144   EXPECT_TRUE(
145       GrantAccessToPath(path, {}, FILE_GENERIC_READ, NO_INHERITANCE, false));
146   EXPECT_EQ(kBaseDacl, GetFileDacl(path));
147   auto sids = Sid::FromSddlStringVector({kAuthenticatedUsersSid});
148   ASSERT_TRUE(sids);
149   EXPECT_TRUE(
150       GrantAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, false));
151   EXPECT_EQ(kTest1DaclNoInherit, GetFileDacl(path));
152   auto sids2 = Sid::FromSddlStringVector({L"S-1-5-11", L"BA"});
153   ASSERT_TRUE(sids2);
154   EXPECT_TRUE(
155       GrantAccessToPath(path, *sids2, GENERIC_ALL, NO_INHERITANCE, false));
156   EXPECT_EQ(kTest2DaclNoInherit, GetFileDacl(path));
157 }
158 
TEST(SecurityUtilTest,DenyAccessToPathFile)159 TEST(SecurityUtilTest, DenyAccessToPathFile) {
160   ScopedTempDir temp_dir;
161   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
162   FilePath path = temp_dir.GetPath().Append(L"test");
163   ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
164   EXPECT_EQ(kBaseDacl, GetFileDacl(path));
165   EXPECT_TRUE(
166       DenyAccessToPath(path, {}, FILE_GENERIC_READ, NO_INHERITANCE, true));
167   EXPECT_EQ(kBaseDacl, GetFileDacl(path));
168   auto sids = Sid::FromSddlStringVector({kLocalGuestSid});
169   ASSERT_TRUE(sids);
170   EXPECT_TRUE(
171       DenyAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
172   EXPECT_EQ(kTest1DenyDacl, GetFileDacl(path));
173 }
174 
TEST(SecurityUtilTest,DenyAccessToPathFileMultiple)175 TEST(SecurityUtilTest, DenyAccessToPathFileMultiple) {
176   ScopedTempDir temp_dir;
177   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
178   FilePath path = temp_dir.GetPath().Append(L"test");
179   ASSERT_TRUE(CreateWithDacl(path, kBaseDacl, false));
180   EXPECT_EQ(kBaseDacl, GetFileDacl(path));
181   auto sids = Sid::FromSddlStringVector({kLocalGuestSid});
182   ASSERT_TRUE(sids);
183   EXPECT_TRUE(
184       DenyAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
185   // Verify setting same ACE on same file does not change the ACL.
186   EXPECT_TRUE(
187       DenyAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
188   EXPECT_TRUE(
189       DenyAccessToPath(path, *sids, FILE_GENERIC_READ, NO_INHERITANCE, true));
190   EXPECT_EQ(kTest1DenyDacl, GetFileDacl(path));
191 }
192 
TEST(SecurityUtilTest,GrantAccessToPathDirectory)193 TEST(SecurityUtilTest, GrantAccessToPathDirectory) {
194   ScopedTempDir temp_dir;
195   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
196   FilePath path = temp_dir.GetPath().Append(L"testdir");
197   ASSERT_TRUE(CreateWithDacl(path, kBaseDirDacl, true));
198   EXPECT_EQ(kBaseDirDacl, GetFileDacl(path));
199   FilePath file_path = path.Append(L"test");
200   File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
201   ASSERT_TRUE(file.IsValid());
202   file.Close();
203   EXPECT_EQ(kTest1InheritedDacl, GetFileDacl(file_path));
204   auto sids = Sid::FromSddlStringVector({kAuthenticatedUsersSid});
205   ASSERT_TRUE(sids);
206   EXPECT_TRUE(GrantAccessToPath(path, *sids, FILE_GENERIC_READ,
207                                 OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
208                                 true));
209   EXPECT_EQ(kBaseDir2Dacl, GetFileDacl(path));
210   EXPECT_EQ(kTest2InheritedDacl, GetFileDacl(file_path));
211 }
212 
TEST(SecurityUtilTest,GrantAccessToPathDirectoryNoInherit)213 TEST(SecurityUtilTest, GrantAccessToPathDirectoryNoInherit) {
214   ScopedTempDir temp_dir;
215   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
216   FilePath path = temp_dir.GetPath().Append(L"testdir");
217   ASSERT_TRUE(CreateWithDacl(path, kBaseDirDacl, true));
218   EXPECT_EQ(kBaseDirDacl, GetFileDacl(path));
219   FilePath file_path = path.Append(L"test");
220   File file(file_path, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
221   ASSERT_TRUE(file.IsValid());
222   file.Close();
223   EXPECT_EQ(kTest1InheritedDacl, GetFileDacl(file_path));
224   auto sids = Sid::FromSddlStringVector({kAuthenticatedUsersSid});
225   ASSERT_TRUE(sids);
226   EXPECT_TRUE(GrantAccessToPath(path, *sids, FILE_GENERIC_READ,
227                                 OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
228                                 false));
229   EXPECT_EQ(kBaseDir2DaclNoInherit, GetFileDacl(path));
230   EXPECT_EQ(kTest2InheritedDaclNoInherit, GetFileDacl(file_path));
231 
232   FilePath file_path2 = path.Append(L"test2");
233   File file2(file_path2, File::FLAG_CREATE_ALWAYS | File::FLAG_WRITE);
234   ASSERT_TRUE(file2.IsValid());
235   file2.Close();
236   EXPECT_EQ(kTest3InheritedDacl, GetFileDacl(file_path2));
237 }
238 
TEST(SecurityUtilTest,CloneSidVector)239 TEST(SecurityUtilTest, CloneSidVector) {
240   std::vector<Sid> sids =
241       Sid::FromKnownSidVector({WellKnownSid::kNull, WellKnownSid::kWorld});
242   std::vector<Sid> clone = CloneSidVector(sids);
243   ASSERT_EQ(sids.size(), clone.size());
244   for (size_t index = 0; index < sids.size(); ++index) {
245     ASSERT_EQ(sids[index], clone[index]);
246     ASSERT_NE(sids[index].GetPSID(), clone[index].GetPSID());
247   }
248   ASSERT_EQ(CloneSidVector(std::vector<Sid>()).size(), 0U);
249 }
250 
TEST(SecurityUtilTest,AppendSidVector)251 TEST(SecurityUtilTest, AppendSidVector) {
252   std::vector<Sid> sids =
253       Sid::FromKnownSidVector({WellKnownSid::kNull, WellKnownSid::kWorld});
254 
255   std::vector<Sid> total_sids;
256   AppendSidVector(total_sids, sids);
257   EXPECT_EQ(total_sids.size(), sids.size());
258 
259   std::vector<Sid> sids2 = Sid::FromKnownSidVector(
260       {WellKnownSid::kCreatorOwner, WellKnownSid::kNetwork});
261   AppendSidVector(total_sids, sids2);
262   EXPECT_EQ(total_sids.size(), sids.size() + sids2.size());
263 
264   auto sid_interator = total_sids.cbegin();
265   for (size_t index = 0; index < sids.size(); ++index) {
266     ASSERT_EQ(*sid_interator, sids[index]);
267     ASSERT_NE(sid_interator->GetPSID(), sids[index].GetPSID());
268     sid_interator++;
269   }
270   for (size_t index = 0; index < sids2.size(); ++index) {
271     ASSERT_EQ(*sid_interator, sids2[index]);
272     ASSERT_NE(sid_interator->GetPSID(), sids2[index].GetPSID());
273     sid_interator++;
274   }
275 }
276 
TEST(SecurityUtilTest,GetGrantedAccess)277 TEST(SecurityUtilTest, GetGrantedAccess) {
278   EXPECT_FALSE(GetGrantedAccess(nullptr));
279   ScopedHandle handle(::CreateMutexEx(nullptr, nullptr, 0, MUTEX_MODIFY_STATE));
280   EXPECT_EQ(GetGrantedAccess(handle.get()), DWORD{MUTEX_MODIFY_STATE});
281   handle.Set(::CreateMutexEx(nullptr, nullptr, 0, READ_CONTROL));
282   EXPECT_EQ(GetGrantedAccess(handle.get()), DWORD{READ_CONTROL});
283   handle.Set(::CreateMutexEx(nullptr, nullptr, 0, GENERIC_ALL));
284   EXPECT_EQ(GetGrantedAccess(handle.get()), DWORD{MUTEX_ALL_ACCESS});
285 }
286 
287 }  // namespace win
288 }  // namespace base
289