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