diff options
Diffstat (limited to 'security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc')
-rw-r--r-- | security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc b/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc new file mode 100644 index 0000000000..e388a9978e --- /dev/null +++ b/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc @@ -0,0 +1,337 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include <aclapi.h> +#include <userenv.h> + +#include "base/strings/stringprintf.h" +#if !defined(MOZ_SANDBOX) +#include "base/win/scoped_co_mem.h" +#endif +#include "base/win/scoped_handle.h" +#include "sandbox/win/src/app_container_profile_base.h" +#include "sandbox/win/src/restricted_token_utils.h" +#include "sandbox/win/src/win_utils.h" + +namespace sandbox { + +namespace { + +typedef decltype(::CreateAppContainerProfile) CreateAppContainerProfileFunc; + +typedef decltype(::DeriveAppContainerSidFromAppContainerName) + DeriveAppContainerSidFromAppContainerNameFunc; + +typedef decltype(::DeleteAppContainerProfile) DeleteAppContainerProfileFunc; + +typedef decltype(::GetAppContainerFolderPath) GetAppContainerFolderPathFunc; + +typedef decltype( + ::GetAppContainerRegistryLocation) GetAppContainerRegistryLocationFunc; + +struct FreeSidDeleter { + inline void operator()(void* ptr) const { ::FreeSid(ptr); } +}; + +bool IsValidObjectType(SE_OBJECT_TYPE object_type) { + switch (object_type) { + case SE_FILE_OBJECT: + case SE_REGISTRY_KEY: + return true; + default: + break; + } + return false; +} + +bool GetGenericMappingForType(SE_OBJECT_TYPE object_type, + GENERIC_MAPPING* generic_mapping) { + if (!IsValidObjectType(object_type)) + return false; + if (object_type == SE_FILE_OBJECT) { + generic_mapping->GenericRead = FILE_GENERIC_READ; + generic_mapping->GenericWrite = FILE_GENERIC_WRITE; + generic_mapping->GenericExecute = FILE_GENERIC_EXECUTE; + generic_mapping->GenericAll = FILE_ALL_ACCESS; + } else { + generic_mapping->GenericRead = KEY_READ; + generic_mapping->GenericWrite = KEY_WRITE; + generic_mapping->GenericExecute = KEY_EXECUTE; + generic_mapping->GenericAll = KEY_ALL_ACCESS; + } + return true; +} + +class ScopedImpersonation { + public: + ScopedImpersonation(const base::win::ScopedHandle& token) { + BOOL result = ::ImpersonateLoggedOnUser(token.Get()); + DCHECK(result); + } + + ~ScopedImpersonation() { + BOOL result = ::RevertToSelf(); + DCHECK(result); + } +}; + +} // namespace + +// static +AppContainerProfileBase* AppContainerProfileBase::Create( + const wchar_t* package_name, + const wchar_t* display_name, + const wchar_t* description) { + static auto create_app_container_profile = + reinterpret_cast<CreateAppContainerProfileFunc*>(GetProcAddress( + GetModuleHandle(L"userenv"), "CreateAppContainerProfile")); + if (!create_app_container_profile) + return nullptr; + + PSID package_sid = nullptr; + HRESULT hr = create_app_container_profile( + package_name, display_name, description, nullptr, 0, &package_sid); + if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + return Open(package_name); + + if (FAILED(hr)) + return nullptr; + std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid); + return new AppContainerProfileBase(Sid(package_sid)); +} + +// static +AppContainerProfileBase* AppContainerProfileBase::Open( + const wchar_t* package_name) { + static auto derive_app_container_sid = + reinterpret_cast<DeriveAppContainerSidFromAppContainerNameFunc*>( + GetProcAddress(GetModuleHandle(L"userenv"), + "DeriveAppContainerSidFromAppContainerName")); + if (!derive_app_container_sid) + return nullptr; + + PSID package_sid = nullptr; + HRESULT hr = derive_app_container_sid(package_name, &package_sid); + if (FAILED(hr)) + return nullptr; + + std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid); + return new AppContainerProfileBase(Sid(package_sid)); +} + +// static +bool AppContainerProfileBase::Delete(const wchar_t* package_name) { + static auto delete_app_container_profile = + reinterpret_cast<DeleteAppContainerProfileFunc*>(GetProcAddress( + GetModuleHandle(L"userenv"), "DeleteAppContainerProfile")); + if (!delete_app_container_profile) + return false; + + return SUCCEEDED(delete_app_container_profile(package_name)); +} + +AppContainerProfileBase::AppContainerProfileBase(const Sid& package_sid) + : ref_count_(0), + package_sid_(package_sid), + enable_low_privilege_app_container_(false) {} + +AppContainerProfileBase::~AppContainerProfileBase() {} + +void AppContainerProfileBase::AddRef() { + ::InterlockedIncrement(&ref_count_); +} + +void AppContainerProfileBase::Release() { + LONG ref_count = ::InterlockedDecrement(&ref_count_); + if (ref_count == 0) { + delete this; + } +} + +bool AppContainerProfileBase::GetRegistryLocation( + REGSAM desired_access, + base::win::ScopedHandle* key) { + static GetAppContainerRegistryLocationFunc* + get_app_container_registry_location = + reinterpret_cast<GetAppContainerRegistryLocationFunc*>(GetProcAddress( + GetModuleHandle(L"userenv"), "GetAppContainerRegistryLocation")); + if (!get_app_container_registry_location) + return false; + + base::win::ScopedHandle token; + if (!BuildLowBoxToken(&token)) + return false; + + ScopedImpersonation impersonation(token); + HKEY key_handle; + if (FAILED(get_app_container_registry_location(desired_access, &key_handle))) + return false; + key->Set(key_handle); + return true; +} + +bool AppContainerProfileBase::GetFolderPath(base::FilePath* file_path) { +#if defined(MOZ_SANDBOX) + IMMEDIATE_CRASH(); +#else + static GetAppContainerFolderPathFunc* get_app_container_folder_path = + reinterpret_cast<GetAppContainerFolderPathFunc*>(GetProcAddress( + GetModuleHandle(L"userenv"), "GetAppContainerFolderPath")); + if (!get_app_container_folder_path) + return false; + std::wstring sddl_str; + if (!package_sid_.ToSddlString(&sddl_str)) + return false; + base::win::ScopedCoMem<wchar_t> path_str; + if (FAILED(get_app_container_folder_path(sddl_str.c_str(), &path_str))) + return false; + *file_path = base::FilePath(path_str.get()); + return true; +#endif +} + +bool AppContainerProfileBase::GetPipePath(const wchar_t* pipe_name, + base::FilePath* pipe_path) { +#if defined(MOZ_SANDBOX) + IMMEDIATE_CRASH(); +#else + std::wstring sddl_str; + if (!package_sid_.ToSddlString(&sddl_str)) + return false; + *pipe_path = base::FilePath(base::StringPrintf(L"\\\\.\\pipe\\%ls\\%ls", + sddl_str.c_str(), pipe_name)); + return true; +#endif +} + +bool AppContainerProfileBase::AccessCheck(const wchar_t* object_name, + SE_OBJECT_TYPE object_type, + DWORD desired_access, + DWORD* granted_access, + BOOL* access_status) { + GENERIC_MAPPING generic_mapping; + if (!GetGenericMappingForType(object_type, &generic_mapping)) + return false; + MapGenericMask(&desired_access, &generic_mapping); + PSECURITY_DESCRIPTOR sd = nullptr; + PACL dacl = nullptr; + if (GetNamedSecurityInfo( + object_name, object_type, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, + nullptr, nullptr, &dacl, nullptr, &sd) != ERROR_SUCCESS) { + return false; + } + + std::unique_ptr<void, LocalFreeDeleter> sd_ptr(sd); + + if (enable_low_privilege_app_container_) { + Sid any_package_sid(::WinBuiltinAnyPackageSid); + // We can't create a LPAC token directly, so modify the DACL to simulate it. + // Set mask for ALL APPLICATION PACKAGE Sid to 0. + for (WORD index = 0; index < dacl->AceCount; ++index) { + PVOID temp_ace; + if (!GetAce(dacl, index, &temp_ace)) + return false; + PACE_HEADER header = static_cast<PACE_HEADER>(temp_ace); + if ((header->AceType != ACCESS_ALLOWED_ACE_TYPE) && + (header->AceType != ACCESS_DENIED_ACE_TYPE)) { + continue; + } + // Allowed and deny aces have the same underlying structure. + PACCESS_ALLOWED_ACE ace = static_cast<PACCESS_ALLOWED_ACE>(temp_ace); + if (!::IsValidSid(&ace->SidStart)) { + continue; + } + if (::EqualSid(&ace->SidStart, any_package_sid.GetPSID())) { + ace->Mask = 0; + } + } + } + + PRIVILEGE_SET priv_set = {}; + DWORD priv_set_length = sizeof(PRIVILEGE_SET); + + base::win::ScopedHandle token; + if (!BuildLowBoxToken(&token)) + return false; + + return !!::AccessCheck(sd, token.Get(), desired_access, &generic_mapping, + &priv_set, &priv_set_length, granted_access, + access_status); +} + +bool AppContainerProfileBase::AddCapability(const wchar_t* capability_name) { + return AddCapability(Sid::FromNamedCapability(capability_name), false); +} + +bool AppContainerProfileBase::AddCapability(WellKnownCapabilities capability) { + return AddCapability(Sid::FromKnownCapability(capability), false); +} + +bool AppContainerProfileBase::AddCapabilitySddl(const wchar_t* sddl_sid) { + return AddCapability(Sid::FromSddlString(sddl_sid), false); +} + +bool AppContainerProfileBase::AddCapability(const Sid& capability_sid, + bool impersonation_only) { + if (!capability_sid.IsValid()) + return false; + if (!impersonation_only) + capabilities_.push_back(capability_sid); + impersonation_capabilities_.push_back(capability_sid); + return true; +} + +bool AppContainerProfileBase::AddImpersonationCapability( + const wchar_t* capability_name) { + return AddCapability(Sid::FromNamedCapability(capability_name), true); +} + +bool AppContainerProfileBase::AddImpersonationCapability( + WellKnownCapabilities capability) { + return AddCapability(Sid::FromKnownCapability(capability), true); +} + +bool AppContainerProfileBase::AddImpersonationCapabilitySddl( + const wchar_t* sddl_sid) { + return AddCapability(Sid::FromSddlString(sddl_sid), true); +} + +const std::vector<Sid>& AppContainerProfileBase::GetCapabilities() { + return capabilities_; +} + +const std::vector<Sid>& +AppContainerProfileBase::GetImpersonationCapabilities() { + return impersonation_capabilities_; +} + +Sid AppContainerProfileBase::GetPackageSid() const { + return package_sid_; +} + +void AppContainerProfileBase::SetEnableLowPrivilegeAppContainer(bool enable) { + enable_low_privilege_app_container_ = enable; +} + +bool AppContainerProfileBase::GetEnableLowPrivilegeAppContainer() { + return enable_low_privilege_app_container_; +} + +std::unique_ptr<SecurityCapabilities> +AppContainerProfileBase::GetSecurityCapabilities() { + return std::unique_ptr<SecurityCapabilities>( + new SecurityCapabilities(package_sid_, capabilities_)); +} + +bool AppContainerProfileBase::BuildLowBoxToken(base::win::ScopedHandle* token) { + return CreateLowBoxToken(nullptr, IMPERSONATION, + GetSecurityCapabilities().get(), nullptr, 0, + token) == ERROR_SUCCESS; +} + +} // namespace sandbox |