[go: nahoru, domu]

blob: e4fa88ae0fd9c516423bc2691b860e2fc16cd4c4 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// 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_hook_linux.h"
#include <dlfcn.h>
#include <optional>
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "sandbox/linux/syscall_broker/broker_command.h"
#include "sandbox/linux/syscall_broker/broker_file_permission.h"
#include "sandbox/policy/features.h"
using sandbox::syscall_broker::BrokerFilePermission;
using sandbox::syscall_broker::MakeBrokerCommandSet;
namespace network {
sandbox::syscall_broker::BrokerCommandSet GetNetworkBrokerCommandSet() {
return MakeBrokerCommandSet({
sandbox::syscall_broker::COMMAND_ACCESS,
sandbox::syscall_broker::COMMAND_MKDIR,
sandbox::syscall_broker::COMMAND_OPEN,
sandbox::syscall_broker::COMMAND_READLINK,
sandbox::syscall_broker::COMMAND_RENAME,
sandbox::syscall_broker::COMMAND_RMDIR,
sandbox::syscall_broker::COMMAND_STAT,
sandbox::syscall_broker::COMMAND_UNLINK,
sandbox::syscall_broker::COMMAND_INOTIFY_ADD_WATCH,
});
}
std::vector<BrokerFilePermission> GetNetworkFilePermissions(
std::vector<std::string> network_context_parent_dirs) {
if (!base::FeatureList::IsEnabled(
sandbox::policy::features::kNetworkServiceFileAllowlist)) {
return {BrokerFilePermission::AllPermissions("/"),
BrokerFilePermission::AllPermissionsRecursive("/")};
}
const std::array<base::FilePath, 5> system_config_files = {
base::FilePath("/etc/hosts"), base::FilePath("/etc/resolv.conf"),
base::FilePath("/etc/nsswitch.conf"), base::FilePath("/etc/host.conf"),
base::FilePath("/etc/gai.conf")};
// Each system config file needs read permissions and watch permissions, and
// read and watch permissions for its symlink target, if any. This is up to
// 4 permissions.
constexpr size_t kMaxPermissionsPerSystemConfigFile = 4;
std::vector<BrokerFilePermission> perms;
perms.reserve(system_config_files.size() *
kMaxPermissionsPerSystemConfigFile +
network_context_parent_dirs.size());
for (const base::FilePath& system_config_file : system_config_files) {
perms.push_back(BrokerFilePermission::InotifyAddWatchWithIntermediateDirs(
system_config_file.value()));
perms.push_back(BrokerFilePermission::ReadOnly(system_config_file.value()));
std::optional<base::FilePath> target_path =
base::ReadSymbolicLinkAbsolute(system_config_file);
if (!target_path.has_value()) {
continue;
}
VLOG(1) << "Adding permissions for symlink: " << target_path->value();
perms.push_back(BrokerFilePermission::InotifyAddWatchWithIntermediateDirs(
target_path->value()));
perms.push_back(BrokerFilePermission::ReadOnly(target_path->value()));
}
for (std::string dir_str : network_context_parent_dirs) {
if (*dir_str.rbegin() != '/') {
dir_str += "/";
}
VLOG(1) << "Granting ReadWriteCreateRecursive permissions to " << dir_str;
perms.push_back(
BrokerFilePermission::ReadWriteCreateRecursive(std::move(dir_str)));
}
return perms;
}
#if BUILDFLAG(IS_CHROMEOS)
void LoadNetworkLibraries() {
const std::string libraries[]{
// On ChromeOS DNS resolution will occur in process, so load the libraries
// now. Note that depending on the glibc version, these libraries may have
// been built directly into libc.so, so it's not an error if they fail to
// load.
"libnss_files.so.2", "libnss_dns.so.2"};
for (const auto& library_name : libraries) {
if (!dlopen(library_name.c_str(),
RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE)) {
VLOG(1) << "LoadNetworkLibraries() dlopen() of " << library_name
<< " failed with error: " << dlerror();
}
}
}
#endif // BUILDFLAG(IS_CHROMEOS)
bool NetworkPreSandboxHook(std::vector<std::string> network_context_parent_dirs,
sandbox::policy::SandboxLinux::Options options) {
#if BUILDFLAG(IS_CHROMEOS)
LoadNetworkLibraries();
#endif
auto* instance = sandbox::policy::SandboxLinux::GetInstance();
VLOG(1) << "Using network service sandbox.";
instance->StartBrokerProcess(
GetNetworkBrokerCommandSet(),
GetNetworkFilePermissions(std::move(network_context_parent_dirs)),
sandbox::policy::SandboxLinux::PreSandboxHook(), options);
return true;
}
} // namespace network