tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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