xref: /aosp_15_r20/external/cronet/base/win/security_descriptor.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 #include "base/win/security_descriptor.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 #include <vector>
16 
17 #include "base/files/file_path.h"
18 #include "base/logging.h"
19 #include "base/notreached.h"
20 #include "base/numerics/checked_math.h"
21 #include "base/win/scoped_localalloc.h"
22 
23 namespace base::win {
24 
25 namespace {
26 template <typename T>
CloneValue(const std::optional<T> & value)27 std::optional<T> CloneValue(const std::optional<T>& value) {
28   if (!value)
29     return std::nullopt;
30   return value->Clone();
31 }
32 
UnwrapSid(const std::optional<Sid> & sid)33 PSID UnwrapSid(const std::optional<Sid>& sid) {
34   if (!sid)
35     return nullptr;
36   return sid->GetPSID();
37 }
38 
UnwrapAcl(const std::optional<AccessControlList> & acl)39 PACL UnwrapAcl(const std::optional<AccessControlList>& acl) {
40   if (!acl)
41     return nullptr;
42   return acl->get();
43 }
44 
ConvertObjectType(SecurityObjectType object_type)45 SE_OBJECT_TYPE ConvertObjectType(SecurityObjectType object_type) {
46   switch (object_type) {
47     case SecurityObjectType::kFile:
48       return SE_FILE_OBJECT;
49     case SecurityObjectType::kRegistry:
50       return SE_REGISTRY_KEY;
51     case SecurityObjectType::kWindowStation:
52     case SecurityObjectType::kDesktop:
53       return SE_WINDOW_OBJECT;
54     case SecurityObjectType::kKernel:
55       return SE_KERNEL_OBJECT;
56   }
57   return SE_UNKNOWN_OBJECT_TYPE;
58 }
59 
GetGenericMappingForType(SecurityObjectType object_type)60 GENERIC_MAPPING GetGenericMappingForType(SecurityObjectType object_type) {
61   GENERIC_MAPPING generic_mapping = {};
62   switch (object_type) {
63     case SecurityObjectType::kFile:
64       generic_mapping.GenericRead = FILE_GENERIC_READ;
65       generic_mapping.GenericWrite = FILE_GENERIC_WRITE;
66       generic_mapping.GenericExecute = FILE_GENERIC_EXECUTE;
67       generic_mapping.GenericAll = FILE_ALL_ACCESS;
68       break;
69     case SecurityObjectType::kRegistry:
70       generic_mapping.GenericRead = KEY_READ;
71       generic_mapping.GenericWrite = KEY_WRITE;
72       generic_mapping.GenericExecute = KEY_EXECUTE;
73       generic_mapping.GenericAll = KEY_ALL_ACCESS;
74       break;
75     case SecurityObjectType::kDesktop:
76       generic_mapping.GenericRead =
77           STANDARD_RIGHTS_READ | DESKTOP_READOBJECTS | DESKTOP_ENUMERATE;
78       generic_mapping.GenericWrite =
79           STANDARD_RIGHTS_WRITE | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
80           DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD |
81           DESKTOP_JOURNALPLAYBACK | DESKTOP_WRITEOBJECTS;
82       generic_mapping.GenericExecute =
83           STANDARD_RIGHTS_EXECUTE | DESKTOP_SWITCHDESKTOP;
84       generic_mapping.GenericAll =
85           STANDARD_RIGHTS_REQUIRED | DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
86           DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK |
87           DESKTOP_JOURNALRECORD | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP |
88           DESKTOP_WRITEOBJECTS;
89       break;
90     case SecurityObjectType::kWindowStation:
91       generic_mapping.GenericRead = STANDARD_RIGHTS_READ | WINSTA_ENUMDESKTOPS |
92                                     WINSTA_ENUMERATE | WINSTA_READATTRIBUTES |
93                                     WINSTA_READSCREEN;
94       generic_mapping.GenericWrite =
95           STANDARD_RIGHTS_WRITE | WINSTA_ACCESSCLIPBOARD |
96           WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES;
97       generic_mapping.GenericExecute = STANDARD_RIGHTS_EXECUTE |
98                                        WINSTA_ACCESSGLOBALATOMS |
99                                        WINSTA_EXITWINDOWS;
100       generic_mapping.GenericAll =
101           STANDARD_RIGHTS_REQUIRED | WINSTA_ACCESSCLIPBOARD |
102           WINSTA_ACCESSGLOBALATOMS | WINSTA_CREATEDESKTOP |
103           WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_EXITWINDOWS |
104           WINSTA_READATTRIBUTES | WINSTA_READSCREEN | WINSTA_WRITEATTRIBUTES;
105       break;
106     case SecurityObjectType::kKernel:
107       NOTREACHED();
108       break;
109   }
110   return generic_mapping;
111 }
112 
113 template <typename T>
GetSecurityDescriptor(T object,SecurityObjectType object_type,SECURITY_INFORMATION security_info,DWORD (WINAPI * get_sd)(T,SE_OBJECT_TYPE,SECURITY_INFORMATION,PSID *,PSID *,PACL *,PACL *,PSECURITY_DESCRIPTOR *))114 std::optional<SecurityDescriptor> GetSecurityDescriptor(
115     T object,
116     SecurityObjectType object_type,
117     SECURITY_INFORMATION security_info,
118     DWORD(WINAPI* get_sd)(T,
119                           SE_OBJECT_TYPE,
120                           SECURITY_INFORMATION,
121                           PSID*,
122                           PSID*,
123                           PACL*,
124                           PACL*,
125                           PSECURITY_DESCRIPTOR*)) {
126   PSECURITY_DESCRIPTOR sd = nullptr;
127 
128   DWORD error = get_sd(object, ConvertObjectType(object_type), security_info,
129                        nullptr, nullptr, nullptr, nullptr, &sd);
130   if (error != ERROR_SUCCESS) {
131     ::SetLastError(error);
132     DPLOG(ERROR) << "Failed getting security descriptor for object.";
133     return std::nullopt;
134   }
135   auto sd_ptr = TakeLocalAlloc(sd);
136   return SecurityDescriptor::FromPointer(sd_ptr.get());
137 }
138 
139 template <typename T>
SetSecurityDescriptor(const SecurityDescriptor & sd,T object,SecurityObjectType object_type,SECURITY_INFORMATION security_info,DWORD (WINAPI * set_sd)(T,SE_OBJECT_TYPE,SECURITY_INFORMATION,PSID,PSID,PACL,PACL))140 bool SetSecurityDescriptor(const SecurityDescriptor& sd,
141                            T object,
142                            SecurityObjectType object_type,
143                            SECURITY_INFORMATION security_info,
144                            DWORD(WINAPI* set_sd)(T,
145                                                  SE_OBJECT_TYPE,
146                                                  SECURITY_INFORMATION,
147                                                  PSID,
148                                                  PSID,
149                                                  PACL,
150                                                  PACL)) {
151   security_info &= ~(PROTECTED_DACL_SECURITY_INFORMATION |
152                      UNPROTECTED_DACL_SECURITY_INFORMATION |
153                      PROTECTED_SACL_SECURITY_INFORMATION |
154                      UNPROTECTED_SACL_SECURITY_INFORMATION);
155   if (security_info & DACL_SECURITY_INFORMATION) {
156     if (sd.dacl_protected()) {
157       security_info |= PROTECTED_DACL_SECURITY_INFORMATION;
158     } else {
159       security_info |= UNPROTECTED_DACL_SECURITY_INFORMATION;
160     }
161   }
162   if (security_info & SACL_SECURITY_INFORMATION) {
163     if (sd.sacl_protected()) {
164       security_info |= PROTECTED_SACL_SECURITY_INFORMATION;
165     } else {
166       security_info |= UNPROTECTED_SACL_SECURITY_INFORMATION;
167     }
168   }
169   DWORD error = set_sd(object, ConvertObjectType(object_type), security_info,
170                        UnwrapSid(sd.owner()), UnwrapSid(sd.group()),
171                        UnwrapAcl(sd.dacl()), UnwrapAcl(sd.sacl()));
172   if (error != ERROR_SUCCESS) {
173     ::SetLastError(error);
174     DPLOG(ERROR) << "Failed setting DACL for object.";
175     return false;
176   }
177   return true;
178 }
179 
GetSecurityDescriptorSid(PSECURITY_DESCRIPTOR sd,BOOL (WINAPI * get_sid)(PSECURITY_DESCRIPTOR,PSID *,LPBOOL))180 std::optional<Sid> GetSecurityDescriptorSid(
181     PSECURITY_DESCRIPTOR sd,
182     BOOL(WINAPI* get_sid)(PSECURITY_DESCRIPTOR, PSID*, LPBOOL)) {
183   PSID sid;
184   BOOL defaulted;
185   if (!get_sid(sd, &sid, &defaulted) || !sid) {
186     return std::nullopt;
187   }
188   return Sid::FromPSID(sid);
189 }
190 
GetSecurityDescriptorAcl(PSECURITY_DESCRIPTOR sd,BOOL (WINAPI * get_acl)(PSECURITY_DESCRIPTOR,LPBOOL,PACL *,LPBOOL))191 std::optional<AccessControlList> GetSecurityDescriptorAcl(
192     PSECURITY_DESCRIPTOR sd,
193     BOOL(WINAPI* get_acl)(PSECURITY_DESCRIPTOR, LPBOOL, PACL*, LPBOOL)) {
194   PACL acl;
195   BOOL present;
196   BOOL defaulted;
197   if (!get_acl(sd, &present, &acl, &defaulted) || !present) {
198     return std::nullopt;
199   }
200   return AccessControlList::FromPACL(acl);
201 }
202 
203 }  // namespace
204 
205 SecurityDescriptor::SelfRelative::SelfRelative(const SelfRelative&) = default;
206 SecurityDescriptor::SelfRelative::~SelfRelative() = default;
SelfRelative(std::vector<uint8_t> && sd)207 SecurityDescriptor::SelfRelative::SelfRelative(std::vector<uint8_t>&& sd)
208     : sd_(sd) {}
209 
FromPointer(PSECURITY_DESCRIPTOR sd)210 std::optional<SecurityDescriptor> SecurityDescriptor::FromPointer(
211     PSECURITY_DESCRIPTOR sd) {
212   if (!sd || !::IsValidSecurityDescriptor(sd)) {
213     ::SetLastError(ERROR_INVALID_SECURITY_DESCR);
214     return std::nullopt;
215   }
216 
217   SECURITY_DESCRIPTOR_CONTROL control;
218   DWORD revision;
219   if (!::GetSecurityDescriptorControl(sd, &control, &revision)) {
220     return std::nullopt;
221   }
222 
223   return SecurityDescriptor{
224       GetSecurityDescriptorSid(sd, ::GetSecurityDescriptorOwner),
225       GetSecurityDescriptorSid(sd, ::GetSecurityDescriptorGroup),
226       GetSecurityDescriptorAcl(sd, ::GetSecurityDescriptorDacl),
227       !!(control & SE_DACL_PROTECTED),
228       GetSecurityDescriptorAcl(sd, ::GetSecurityDescriptorSacl),
229       !!(control & SE_SACL_PROTECTED)};
230 }
231 
FromFile(const base::FilePath & path,SECURITY_INFORMATION security_info)232 std::optional<SecurityDescriptor> SecurityDescriptor::FromFile(
233     const base::FilePath& path,
234     SECURITY_INFORMATION security_info) {
235   return FromName(path.value(), SecurityObjectType::kFile, security_info);
236 }
237 
FromName(const std::wstring & name,SecurityObjectType object_type,SECURITY_INFORMATION security_info)238 std::optional<SecurityDescriptor> SecurityDescriptor::FromName(
239     const std::wstring& name,
240     SecurityObjectType object_type,
241     SECURITY_INFORMATION security_info) {
242   return GetSecurityDescriptor(name.c_str(), object_type, security_info,
243                                ::GetNamedSecurityInfo);
244 }
245 
FromHandle(HANDLE handle,SecurityObjectType object_type,SECURITY_INFORMATION security_info)246 std::optional<SecurityDescriptor> SecurityDescriptor::FromHandle(
247     HANDLE handle,
248     SecurityObjectType object_type,
249     SECURITY_INFORMATION security_info) {
250   return GetSecurityDescriptor<HANDLE>(handle, object_type, security_info,
251                                        ::GetSecurityInfo);
252 }
253 
FromSddl(const std::wstring & sddl)254 std::optional<SecurityDescriptor> SecurityDescriptor::FromSddl(
255     const std::wstring& sddl) {
256   PSECURITY_DESCRIPTOR sd;
257   if (!::ConvertStringSecurityDescriptorToSecurityDescriptor(
258           sddl.c_str(), SDDL_REVISION_1, &sd, nullptr)) {
259     return std::nullopt;
260   }
261   auto sd_ptr = TakeLocalAlloc(sd);
262   return FromPointer(sd_ptr.get());
263 }
264 
265 SecurityDescriptor::SecurityDescriptor() = default;
266 SecurityDescriptor::SecurityDescriptor(SecurityDescriptor&&) = default;
267 SecurityDescriptor& SecurityDescriptor::operator=(SecurityDescriptor&&) =
268     default;
269 SecurityDescriptor::~SecurityDescriptor() = default;
270 
WriteToFile(const base::FilePath & path,SECURITY_INFORMATION security_info) const271 bool SecurityDescriptor::WriteToFile(const base::FilePath& path,
272                                      SECURITY_INFORMATION security_info) const {
273   return WriteToName(path.value(), SecurityObjectType::kFile, security_info);
274 }
275 
WriteToName(const std::wstring & name,SecurityObjectType object_type,SECURITY_INFORMATION security_info) const276 bool SecurityDescriptor::WriteToName(const std::wstring& name,
277                                      SecurityObjectType object_type,
278                                      SECURITY_INFORMATION security_info) const {
279   return SetSecurityDescriptor<wchar_t*>(
280       *this, const_cast<wchar_t*>(name.c_str()), object_type, security_info,
281       ::SetNamedSecurityInfo);
282 }
283 
WriteToHandle(HANDLE handle,SecurityObjectType object_type,SECURITY_INFORMATION security_info) const284 bool SecurityDescriptor::WriteToHandle(
285     HANDLE handle,
286     SecurityObjectType object_type,
287     SECURITY_INFORMATION security_info) const {
288   return SetSecurityDescriptor<HANDLE>(*this, handle, object_type,
289                                        security_info, ::SetSecurityInfo);
290 }
291 
ToSddl(SECURITY_INFORMATION security_info) const292 std::optional<std::wstring> SecurityDescriptor::ToSddl(
293     SECURITY_INFORMATION security_info) const {
294   SECURITY_DESCRIPTOR sd = {};
295   ToAbsolute(sd);
296   LPWSTR sddl;
297   if (!::ConvertSecurityDescriptorToStringSecurityDescriptor(
298           &sd, SDDL_REVISION_1, security_info, &sddl, nullptr)) {
299     return std::nullopt;
300   }
301   auto sddl_ptr = TakeLocalAlloc(sddl);
302   return sddl_ptr.get();
303 }
304 
ToAbsolute(SECURITY_DESCRIPTOR & sd) const305 void SecurityDescriptor::ToAbsolute(SECURITY_DESCRIPTOR& sd) const {
306   memset(&sd, 0, sizeof(sd));
307   sd.Revision = SECURITY_DESCRIPTOR_REVISION;
308   sd.Owner = owner_ ? owner_->GetPSID() : nullptr;
309   sd.Group = group_ ? group_->GetPSID() : nullptr;
310   if (dacl_) {
311     sd.Dacl = dacl_->get();
312     sd.Control |= SE_DACL_PRESENT;
313     if (dacl_protected_) {
314       sd.Control |= SE_DACL_PROTECTED;
315     }
316   }
317   if (sacl_) {
318     sd.Sacl = sacl_->get();
319     sd.Control |= SE_SACL_PRESENT;
320     if (sacl_protected_) {
321       sd.Control |= SE_SACL_PROTECTED;
322     }
323   }
324   DCHECK(::IsValidSecurityDescriptor(&sd));
325 }
326 
327 std::optional<SecurityDescriptor::SelfRelative>
ToSelfRelative() const328 SecurityDescriptor::ToSelfRelative() const {
329   SECURITY_DESCRIPTOR sd = {};
330   ToAbsolute(sd);
331   DWORD size = sizeof(SECURITY_DESCRIPTOR_MIN_LENGTH);
332   std::vector<uint8_t> buffer(SECURITY_DESCRIPTOR_MIN_LENGTH);
333   if (::MakeSelfRelativeSD(&sd, buffer.data(), &size)) {
334     return SelfRelative(std::move(buffer));
335   }
336 
337   if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
338     return std::nullopt;
339   }
340 
341   buffer.resize(size);
342   if (!::MakeSelfRelativeSD(&sd, buffer.data(), &size)) {
343     return std::nullopt;
344   }
345   return SelfRelative(std::move(buffer));
346 }
347 
Clone() const348 SecurityDescriptor SecurityDescriptor::Clone() const {
349   return SecurityDescriptor{CloneValue(owner_), CloneValue(group_),
350                             CloneValue(dacl_),  dacl_protected_,
351                             CloneValue(sacl_),  sacl_protected_};
352 }
353 
SetMandatoryLabel(DWORD integrity_level,DWORD inheritance,DWORD mandatory_policy)354 bool SecurityDescriptor::SetMandatoryLabel(DWORD integrity_level,
355                                            DWORD inheritance,
356                                            DWORD mandatory_policy) {
357   std::optional<AccessControlList> sacl = AccessControlList::FromMandatoryLabel(
358       integrity_level, inheritance, mandatory_policy);
359   if (!sacl) {
360     return false;
361   }
362   sacl_ = std::move(*sacl);
363   return true;
364 }
365 
SetDaclEntries(const std::vector<ExplicitAccessEntry> & entries)366 bool SecurityDescriptor::SetDaclEntries(
367     const std::vector<ExplicitAccessEntry>& entries) {
368   if (!dacl_) {
369     dacl_ = AccessControlList{};
370   }
371   return dacl_->SetEntries(entries);
372 }
373 
SetDaclEntry(const Sid & sid,SecurityAccessMode mode,DWORD access_mask,DWORD inheritance)374 bool SecurityDescriptor::SetDaclEntry(const Sid& sid,
375                                       SecurityAccessMode mode,
376                                       DWORD access_mask,
377                                       DWORD inheritance) {
378   if (!dacl_) {
379     dacl_ = AccessControlList{};
380   }
381   return dacl_->SetEntry(sid, mode, access_mask, inheritance);
382 }
383 
SetDaclEntry(WellKnownSid known_sid,SecurityAccessMode mode,DWORD access_mask,DWORD inheritance)384 bool SecurityDescriptor::SetDaclEntry(WellKnownSid known_sid,
385                                       SecurityAccessMode mode,
386                                       DWORD access_mask,
387                                       DWORD inheritance) {
388   return SetDaclEntry(Sid(known_sid), mode, access_mask, inheritance);
389 }
390 
AccessCheck(const AccessToken & token,ACCESS_MASK desired_access,const GENERIC_MAPPING & generic_mapping)391 std::optional<AccessCheckResult> SecurityDescriptor::AccessCheck(
392     const AccessToken& token,
393     ACCESS_MASK desired_access,
394     const GENERIC_MAPPING& generic_mapping) {
395   GENERIC_MAPPING local_mapping = generic_mapping;
396   ::MapGenericMask(&desired_access, &local_mapping);
397 
398   // Allocate a privilege set which could cover all possible privileges.
399   DWORD priv_set_length = checked_cast<DWORD>(
400       sizeof(PRIVILEGE_SET) +
401       (token.Privileges().size() * sizeof(LUID_AND_ATTRIBUTES)));
402   std::vector<char> priv_set(priv_set_length);
403   DWORD granted_access = 0;
404   BOOL access_status = FALSE;
405   SECURITY_DESCRIPTOR sd = {};
406   ToAbsolute(sd);
407   if (!::AccessCheck(&sd, token.get(), desired_access, &local_mapping,
408                      reinterpret_cast<PPRIVILEGE_SET>(priv_set.data()),
409                      &priv_set_length, &granted_access, &access_status)) {
410     return std::nullopt;
411   }
412   return AccessCheckResult{granted_access, !!access_status};
413 }
414 
AccessCheck(const AccessToken & token,ACCESS_MASK desired_access,SecurityObjectType object_type)415 std::optional<AccessCheckResult> SecurityDescriptor::AccessCheck(
416     const AccessToken& token,
417     ACCESS_MASK desired_access,
418     SecurityObjectType object_type) {
419   if (object_type == SecurityObjectType::kKernel) {
420     ::SetLastError(ERROR_INVALID_PARAMETER);
421     return std::nullopt;
422   }
423   return AccessCheck(token, desired_access,
424                      GetGenericMappingForType(object_type));
425 }
426 
SecurityDescriptor(std::optional<Sid> && owner,std::optional<Sid> && group,std::optional<AccessControlList> && dacl,bool dacl_protected,std::optional<AccessControlList> && sacl,bool sacl_protected)427 SecurityDescriptor::SecurityDescriptor(std::optional<Sid>&& owner,
428                                        std::optional<Sid>&& group,
429                                        std::optional<AccessControlList>&& dacl,
430                                        bool dacl_protected,
431                                        std::optional<AccessControlList>&& sacl,
432                                        bool sacl_protected) {
433   owner_.swap(owner);
434   group_.swap(group);
435   dacl_.swap(dacl);
436   dacl_protected_ = dacl_protected;
437   sacl_.swap(sacl);
438   sacl_protected_ = sacl_protected;
439 }
440 
441 }  // namespace base::win
442