blob: d0613e238a4137faa66c015a417209bac33761ab [file] [log] [blame]
// Copyright 2018 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 "services/network/network_sandbox_win.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.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))
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) {
return false;
}
return true;
}
} // namespace network