Commit 5d609c9c authored by Will Harris's avatar Will Harris Committed by Commit Bot

Change network process sandbox to apply default mitigations.

No sandbox isolation policies are being applied, but the default
process mitigations will now be in place when the sandbox is
enabled. The sandbox will be enabled by feature flag.

Before:

DEP (permanent)
ASLR (high entropy)
CF Guard

After (when enabled):

DEP (permanent)
ASLR (high entropy)
Dynamic code prohibited
Strict handle checks
Extension points disabled
CF Guard
Signatures restricted (Microsoft only)
Non-system fonts disabled
Images restricted (remote images, low mandatory label images)

This also adds 4Gb job process limit.

BUG=841001,920727

Change-Id: I9dc1213615e621a321b3da42772fa68d5bea3394
Reviewed-on: https://chromium-review.googlesource.com/c/1481658
Commit-Queue: Will Harris <wfh@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636192}
parent da0dacbb
......@@ -111,6 +111,10 @@ class UtilitySandboxedProcessLauncherDelegate
// Default policy is disabled for audio process to allow audio drivers
// to read device properties (https://crbug.com/883326).
return true;
case service_manager::SANDBOX_TYPE_NETWORK:
// Default policy is disabled for network process to allow incremental
// sandbox mitigations to be applied via experiments.
return true;
case service_manager::SANDBOX_TYPE_XRCOMPOSITING:
return base::FeatureList::IsEnabled(
service_manager::features::kXRSandbox);
......@@ -126,7 +130,7 @@ class UtilitySandboxedProcessLauncherDelegate
bool PreSpawnTarget(sandbox::TargetPolicy* policy) override {
if (sandbox_type_ == service_manager::SANDBOX_TYPE_NETWORK)
return network::NetworkPreSpawnTarget(policy);
return network::NetworkPreSpawnTarget(policy, cmd_line_);
if (sandbox_type_ == service_manager::SANDBOX_TYPE_AUDIO)
return audio::AudioPreSpawnTarget(policy);
......
......@@ -4,159 +4,24 @@
#include "services/network/network_sandbox_win.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "sandbox/win/src/sandbox_types.h"
#include "services/service_manager/sandbox/win/sandbox_win.h"
// NOTE: changes to this code need to be reviewed by the security team.
namespace network {
namespace {
bool EnumHardDrives(std::vector<std::wstring>* drive_paths) {
drive_paths->clear();
wchar_t volume_name[MAX_PATH];
// INVALID_HANDLE_VALUE alert!
HANDLE volume = ::FindFirstVolumeW(volume_name, ARRAYSIZE(volume_name));
if (volume == INVALID_HANDLE_VALUE) {
// This should never happen. Unexpected failure, no volumes found.
NOTREACHED();
return false;
}
wchar_t device_name[MAX_PATH];
do {
// Example volume name returned:
// "\\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}\"
size_t length = ::wcsnlen(volume_name, ARRAYSIZE(volume_name));
if (length < 5 || volume_name[0] != L'\\' || volume_name[1] != L'\\' ||
volume_name[2] != L'?' || volume_name[3] != L'\\' ||
volume_name[length - 1] != L'\\') {
// Bad path returned. Very unexpected.
continue;
}
// QueryDosDevice doesn't take a trailing backslash.
volume_name[length - 1] = L'\0';
DWORD device_name_length =
::QueryDosDeviceW(&volume_name[4], device_name, ARRAYSIZE(device_name));
volume_name[length - 1] = L'\\';
if (!device_name_length)
continue;
// Example device name returned: "\Device\HarddiskVolume2"
// Ignore any volumes that aren't hard disks (e.g. CdRom, etc).
if (::wcsncmp(device_name, L"\\Device\\Harddisk",
::wcslen(L"\\Device\\Harddisk"))) {
continue;
}
// Now get the path(s) for the given hard disk volume.
bool success = false;
DWORD char_count = MAX_PATH;
std::vector<wchar_t> path_names_buffer;
while (!success) {
path_names_buffer.resize(char_count * sizeof(wchar_t));
success = ::GetVolumePathNamesForVolumeNameW(
volume_name, path_names_buffer.data(), char_count, &char_count);
if (!success && ::GetLastError() != ERROR_MORE_DATA)
break;
}
if (!success)
continue;
// |buffer| is filled with a list of strings, separated by null
// characters. Double null ends list.
// Note: usually the very first string will be the drive letter sought,
// and is often the only string in the list. Some volumes have
// no drive letter assigned at all - not interested here.
size_t volume_path_index = 0;
size_t path_length = ::wcslen(&path_names_buffer[volume_path_index]);
while (path_length > 0) {
// Only collect drive letters, not mounted folder paths.
// Do dumb check instead of calls to GetFileAttributes().
if (path_length == 3 &&
path_names_buffer[volume_path_index + 1] == L':' &&
path_names_buffer[volume_path_index + 2] == L'\\') {
drive_paths->emplace_back(&path_names_buffer[volume_path_index]);
}
volume_path_index += path_length + 1;
path_length = ::wcslen(&path_names_buffer[volume_path_index]);
}
} while (::FindNextVolumeW(volume, volume_name, ARRAYSIZE(volume_name)));
::FindVolumeClose(volume);
return true;
}
} // namespace
//------------------------------------------------------------------------------
// Public network service sandbox configuration extension functions.
//------------------------------------------------------------------------------
/*
Default policy:
lockdown_level_(sandbox::USER_LOCKDOWN),
initial_level_(sandbox::USER_RESTRICTED_SAME_ACCESS),
job_level_(sandbox::JOB_LOCKDOWN),
integrity_level_(sandbox::INTEGRITY_LEVEL_LOW),
delayed_integrity_level_(sandbox::INTEGRITY_LEVEL_UNTRUSTED),
*/
/*
Network cache: %UserDataDir%\\Default\\*
(E.g. c:\Temp\UserDataDir\Default\Cache to
c:\Temp\UserDataDir\Default\old_Cache_000)
DNS config registry access:
---------------------------
HKEY_LOCAL_MACHINE
kTcpipPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
kTcpip6Path = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
kDnscachePath = L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters";
kPolicyPath = L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient";
kPrimaryDnsSuffixPath = L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient";
kNRPTPath = L"SOFTWARE\\Policies\\Microsoft\\Windows
NT\\DNSClient\\DnsPolicyConfig";
Priviliged API GetAdaptorsAddresses()
*/
bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy) {
// Token Level (affects system network APIs)
policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
sandbox::USER_LIMITED);
// File
std::vector<std::wstring> drives;
if (!EnumHardDrives(&drives))
// Right now, this policy is essentially unsandboxed, but with default process
// mitigations applied. This will be tighted up in future releases.
bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy,
const base::CommandLine& cmd_line) {
sandbox::ResultCode result = policy->SetTokenLevel(sandbox::USER_UNPROTECTED,
sandbox::USER_UNPROTECTED);
if (result != sandbox::ResultCode::SBOX_ALL_OK)
return false;
for (auto path : drives) {
path.append(L"*");
if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
sandbox::TargetPolicy::FILES_ALLOW_ANY,
path.c_str()) != sandbox::SBOX_ALL_OK) {
return false;
}
}
// Registry
if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
sandbox::TargetPolicy::REG_ALLOW_READONLY,
L"HKEY_LOCAL_MACHINE\\*") != sandbox::SBOX_ALL_OK ||
policy->AddRule(sandbox::TargetPolicy::SUBSYS_REGISTRY,
sandbox::TargetPolicy::REG_ALLOW_READONLY,
L"HKEY_CURRENT_USER\\*") != sandbox::SBOX_ALL_OK) {
result = service_manager::SandboxWin::SetJobLevel(
cmd_line, sandbox::JOB_UNPROTECTED, 0, policy);
if (result != sandbox::ResultCode::SBOX_ALL_OK)
return false;
}
return true;
}
......
......@@ -19,7 +19,8 @@ namespace network {
// PreSpawnTarget extension.
COMPONENT_EXPORT(NETWORK_SERVICE)
bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy);
bool NetworkPreSpawnTarget(sandbox::TargetPolicy* policy,
const base::CommandLine& cmd_line);
} // namespace network
......
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