security_descriptor.cc (15526B)
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> 24 absl::optional<T> CloneValue(const absl::optional<T>& value) { 25 if (!value) 26 return absl::nullopt; 27 return value->Clone(); 28 } 29 30 PSID UnwrapSid(const absl::optional<Sid>& sid) { 31 if (!sid) 32 return nullptr; 33 return sid->GetPSID(); 34 } 35 36 PACL UnwrapAcl(const absl::optional<AccessControlList>& acl) { 37 if (!acl) 38 return nullptr; 39 return acl->get(); 40 } 41 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 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> 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> 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 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 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; 204 SecurityDescriptor::SelfRelative::SelfRelative(std::vector<uint8_t>&& sd) 205 : sd_(sd) {} 206 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 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 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 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 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 268 bool SecurityDescriptor::WriteToFile(const base::FilePath& path, 269 SECURITY_INFORMATION security_info) const { 270 return WriteToName(path.value(), SecurityObjectType::kFile, security_info); 271 } 272 273 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 281 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 289 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 302 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> 325 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 345 SecurityDescriptor SecurityDescriptor::Clone() const { 346 return SecurityDescriptor{CloneValue(owner_), CloneValue(group_), 347 CloneValue(dacl_), dacl_protected_, 348 CloneValue(sacl_), sacl_protected_}; 349 } 350 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 364 bool SecurityDescriptor::SetDaclEntries( 365 const std::vector<ExplicitAccessEntry>& entries) { 366 if (!dacl_) { 367 dacl_ = AccessControlList{}; 368 } 369 return dacl_->SetEntries(entries); 370 } 371 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 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 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 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 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