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