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