Commit 8501acdf authored by James Forshaw's avatar James Forshaw Committed by Commit Bot

Added AppContainerProfile implementation

This CL contains the implementation of the AppContainerProfile and
associated tests.

Bug: 760977
Cq-Include-Trybots: master.tryserver.chromium.win:win10_chromium_x64_rel_ng
Change-Id: I40e8a5b858ca9ad1f0aa28f9165fbb6bbb1485a8
Reviewed-on: https://chromium-review.googlesource.com/712176Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Commit-Queue: James Forshaw <forshaw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509526}
parent 5763e1d7
...@@ -12,6 +12,8 @@ static_library("sandbox") { ...@@ -12,6 +12,8 @@ static_library("sandbox") {
sources = [ sources = [
"src/acl.cc", "src/acl.cc",
"src/acl.h", "src/acl.h",
"src/app_container_profile.cc",
"src/app_container_profile.h",
"src/broker_services.cc", "src/broker_services.cc",
"src/broker_services.h", "src/broker_services.h",
"src/crosscall_client.h", "src/crosscall_client.h",
...@@ -295,6 +297,7 @@ test("sbox_validation_tests") { ...@@ -295,6 +297,7 @@ test("sbox_validation_tests") {
test("sbox_unittests") { test("sbox_unittests") {
sources = [ sources = [
"src/app_container_unittest.cc",
"src/interception_unittest.cc", "src/interception_unittest.cc",
"src/ipc_unittest.cc", "src/ipc_unittest.cc",
"src/job_unittest.cc", "src/job_unittest.cc",
......
// 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"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_handle.h"
#include "sandbox/win/src/app_container_profile.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
scoped_refptr<AppContainerProfile> AppContainerProfile::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 AppContainerProfile(Sid(package_sid));
}
// static
scoped_refptr<AppContainerProfile> AppContainerProfile::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 AppContainerProfile(Sid(package_sid));
}
// static
bool AppContainerProfile::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));
}
AppContainerProfile::AppContainerProfile(const Sid& package_sid)
: ref_count_(0),
package_sid_(package_sid),
enable_low_privilege_app_container_(false) {}
AppContainerProfile::~AppContainerProfile() {}
void AppContainerProfile::AddRef() {
::InterlockedIncrement(&ref_count_);
}
void AppContainerProfile::Release() {
LONG ref_count = ::InterlockedDecrement(&ref_count_);
if (ref_count == 0) {
delete this;
}
}
bool AppContainerProfile::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 AppContainerProfile::GetFolderPath(base::FilePath* file_path) {
static GetAppContainerFolderPathFunc* get_app_container_folder_path =
reinterpret_cast<GetAppContainerFolderPathFunc*>(GetProcAddress(
GetModuleHandle(L"userenv"), "GetAppContainerFolderPath"));
if (!get_app_container_folder_path)
return false;
base::string16 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;
}
bool AppContainerProfile::GetPipePath(const wchar_t* pipe_name,
base::FilePath* pipe_path) {
base::string16 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;
}
bool AppContainerProfile::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;
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 AppContainerProfile::AddCapability(const wchar_t* capability_name) {
return AddCapability(Sid::FromNamedCapability(capability_name));
}
bool AppContainerProfile::AddCapability(WellKnownCapabilities capability) {
return AddCapability(Sid::FromKnownCapability(capability));
}
bool AppContainerProfile::AddCapability(const Sid& capability_sid) {
if (!capability_sid.IsValid())
return false;
capabilities_.push_back(capability_sid);
return true;
}
Sid AppContainerProfile::GetPackageSid() const {
return package_sid_;
}
void AppContainerProfile::SetEnableLowPrivilegeAppContainer(bool enable) {
enable_low_privilege_app_container_ = enable;
}
bool AppContainerProfile::GetEnableLowPrivilegeAppContainer() {
return enable_low_privilege_app_container_;
}
std::unique_ptr<SecurityCapabilities>
AppContainerProfile::GetSecurityCapabilities() {
return std::unique_ptr<SecurityCapabilities>(
new SecurityCapabilities(package_sid_, capabilities_));
}
bool AppContainerProfile::BuildLowBoxToken(base::win::ScopedHandle* token) {
return CreateLowBoxToken(nullptr, IMPERSONATION,
GetSecurityCapabilities().get(), nullptr, 0,
token) == ERROR_SUCCESS;
}
} // namespace sandbox
// 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.
#ifndef SANDBOX_SRC_APP_CONTAINER_PROFILE_H_
#define SANDBOX_SRC_APP_CONTAINER_PROFILE_H_
#include <windows.h>
#include <accctrl.h>
#include <memory>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/win/scoped_handle.h"
#include "sandbox/win/src/security_capabilities.h"
#include "sandbox/win/src/sid.h"
namespace sandbox {
class AppContainerProfile {
public:
// Increments the reference count of this object. The reference count must
// be incremented if this interface is given to another component.
void AddRef();
// Decrements the reference count of this object. When the reference count
// is zero the object is automatically destroyed.
// Indicates that the caller is done with this interface. After calling
// release no other method should be called.
void Release();
// Get a handle to a registry key for this package.
bool GetRegistryLocation(REGSAM desired_access, base::win::ScopedHandle* key);
// Get a folder path to a location for this package.
bool GetFolderPath(base::FilePath* file_path);
// Get a pipe name usable by this AC.
bool GetPipePath(const wchar_t* pipe_name, base::FilePath* pipe_path);
// Get the package SID for this AC.
Sid GetPackageSid() const;
// Do an access check based on this profile for a named object. If method
// returns true then access_status reflects whether access was granted and
// granted_access gives the final access rights. The object_type can be one of
// SE_FILE_OBJECT, SE_REGISTRY_KEY, SE_REGISTRY_WOW64_32KEY. See
// ::GetNamedSecurityInfo for more information about how the enumeration is
// used and what format object_name needs to be.
bool AccessCheck(const wchar_t* object_name,
SE_OBJECT_TYPE object_type,
DWORD desired_access,
DWORD* granted_access,
BOOL* access_status);
// Adds a capability by name to this profile.
bool AddCapability(const wchar_t* capability_name);
// Adds a capability from a known list.
bool AddCapability(WellKnownCapabilities capability);
// Adds a capability from a SID
bool AddCapability(const Sid& capability_sid);
// Enable Low Privilege AC.
void SetEnableLowPrivilegeAppContainer(bool enable);
bool GetEnableLowPrivilegeAppContainer();
// Get a allocated SecurityCapabilities object for this App Container.
std::unique_ptr<SecurityCapabilities> GetSecurityCapabilities();
// Creates a new AppContainerProfile object. This will create a new profile
// if it doesn't already exist. The profile must be deleted manually using
// the Delete method if it's no longer required.
static scoped_refptr<AppContainerProfile> Create(const wchar_t* package_name,
const wchar_t* display_name,
const wchar_t* description);
// Opens an AppContainerProfile object. No checks will be made on
// whether the package exists or not.
static scoped_refptr<AppContainerProfile> Open(const wchar_t* package_name);
// Delete a profile based on name. Returns true if successful, or if the
// package doesn't already exist.
static bool Delete(const wchar_t* package_name);
private:
AppContainerProfile(const Sid& package_sid);
~AppContainerProfile();
bool BuildLowBoxToken(base::win::ScopedHandle* token);
// Standard object-lifetime reference counter.
volatile LONG ref_count_;
Sid package_sid_;
bool enable_low_privilege_app_container_;
std::vector<Sid> capabilities_;
DISALLOW_COPY_AND_ASSIGN(AppContainerProfile);
};
} // namespace sandbox
#endif // SANDBOX_SRC_APP_CONTAINER_PROFILE_H_
This diff is collapsed.
...@@ -9,11 +9,12 @@ ...@@ -9,11 +9,12 @@
#include <vector> #include <vector>
#include "base/macros.h"
#include "sandbox/win/src/sid.h" #include "sandbox/win/src/sid.h"
namespace sandbox { namespace sandbox {
struct SecurityCapabilities : public SECURITY_CAPABILITIES { class SecurityCapabilities final : public SECURITY_CAPABILITIES {
public: public:
explicit SecurityCapabilities(const Sid& package_sid); explicit SecurityCapabilities(const Sid& package_sid);
SecurityCapabilities(const Sid& package_sid, SecurityCapabilities(const Sid& package_sid,
...@@ -24,6 +25,8 @@ struct SecurityCapabilities : public SECURITY_CAPABILITIES { ...@@ -24,6 +25,8 @@ struct SecurityCapabilities : public SECURITY_CAPABILITIES {
std::vector<Sid> capabilities_; std::vector<Sid> capabilities_;
std::vector<SID_AND_ATTRIBUTES> capability_sids_; std::vector<SID_AND_ATTRIBUTES> capability_sids_;
Sid package_sid_; Sid package_sid_;
DISALLOW_COPY_AND_ASSIGN(SecurityCapabilities);
}; };
} // namespace sandbox } // namespace sandbox
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment