blob: bcda6c081f312de17ff2d1fa4bc6f69771490f12 [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/audio/audio_sandbox_hook_linux.h"
#include <dlfcn.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "sandbox/linux/syscall_broker/broker_command.h"
#include "sandbox/linux/syscall_broker/broker_file_permission.h"
using sandbox::syscall_broker::BrokerFilePermission;
using sandbox::syscall_broker::MakeBrokerCommandSet;
namespace audio {
namespace {
#if defined(USE_ALSA)
void AddAlsaFilePermissions(std::vector<BrokerFilePermission>* permissions) {
base::FilePath home_dir;
base::PathService::Get(base::DIR_HOME, &home_dir);
const base::FilePath kAsoundrc =
home_dir.Append(FILE_PATH_LITERAL(".asoundrc"));
const std::string kReadOnlyFilenames[]{"/etc/asound.conf", "/proc/cpuinfo",
"/etc/group", "/etc/nsswitch.conf",
kAsoundrc.value()};
for (const auto& filename : kReadOnlyFilenames)
permissions->push_back(BrokerFilePermission::ReadOnly(filename));
permissions->push_back(
BrokerFilePermission::ReadOnlyRecursive("/usr/share/alsa/"));
permissions->push_back(
BrokerFilePermission::ReadWriteCreateRecursive("/dev/snd/"));
static const base::FilePath::CharType kDevAloadPath[] =
FILE_PATH_LITERAL("/dev/aloadC");
for (int i = 0; i <= 31; ++i) {
permissions->push_back(BrokerFilePermission::ReadWrite(
base::StringPrintf("%s%d", kDevAloadPath, i)));
}
}
#endif
#if defined(USE_PULSEAUDIO)
void AddPulseAudioFilePermissions(
std::vector<BrokerFilePermission>* permissions) {
base::FilePath home_dir;
base::PathService::Get(base::DIR_HOME, &home_dir);
const base::FilePath kXauthorityPath =
home_dir.Append(FILE_PATH_LITERAL(".Xauthority"));
// Calling read() system call on /proc/self/exe returns broker process' path,
// and it's used by pulse audio for creating a new context.
const std::string kReadOnlyFilenames[]{
"/etc/machine-id", "/proc/self/exe",
"/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache",
"/usr/lib/x86_64-linux-gnu/gconv/gconv-modules", kXauthorityPath.value()};
for (const auto& filename : kReadOnlyFilenames)
permissions->push_back(BrokerFilePermission::ReadOnly(filename));
const base::FilePath kPulsePath =
home_dir.Append(FILE_PATH_LITERAL(".pulse/"));
const base::FilePath kConfigPulsePath =
home_dir.Append(FILE_PATH_LITERAL(".config/pulse/"));
const std::string kReadOnlyRecursivePaths[]{"/etc/pulse/", kPulsePath.value(),
kConfigPulsePath.value()};
for (const auto& path : kReadOnlyRecursivePaths)
permissions->push_back(BrokerFilePermission::ReadOnlyRecursive(path));
const std::string kRunUserPath = base::StringPrintf("/run/user/%d", getuid());
permissions->push_back(BrokerFilePermission::ReadWriteCreate(kRunUserPath));
permissions->push_back(
BrokerFilePermission::ReadWriteCreate(kRunUserPath + "/pulse"));
permissions->push_back(
BrokerFilePermission::ReadWriteCreateRecursive(kRunUserPath + "/pulse/"));
}
#endif
std::vector<BrokerFilePermission> GetAudioFilePermissions() {
std::vector<BrokerFilePermission> permissions{
BrokerFilePermission::ReadOnly("/dev/urandom"),
BrokerFilePermission::ReadOnly("/sys/devices/system/cpu"),
BrokerFilePermission::ReadOnlyRecursive("/usr/share/locale/"),
BrokerFilePermission::ReadWriteCreateRecursive("/dev/shm/")};
#if defined(USE_PULSEAUDIO)
AddPulseAudioFilePermissions(&permissions);
#endif
#if defined(USE_ALSA)
AddAlsaFilePermissions(&permissions);
#endif
return permissions;
}
void LoadAudioLibraries() {
const std::string kLibraries[]{"libasound.so.2", "libpulse.so.0",
"libnss_files.so.2"};
for (const auto& library_name : kLibraries) {
if (nullptr ==
dlopen(library_name.c_str(), RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE)) {
LOG(WARNING) << "dlopen: failed to open " << library_name
<< " with error: " << dlerror();
}
}
}
} // namespace
bool AudioPreSandboxHook(service_manager::SandboxLinux::Options options) {
LoadAudioLibraries();
auto* instance = service_manager::SandboxLinux::GetInstance();
instance->StartBrokerProcess(MakeBrokerCommandSet({
sandbox::syscall_broker::COMMAND_ACCESS,
#if defined(USE_PULSEAUDIO)
sandbox::syscall_broker::COMMAND_MKDIR,
#endif
sandbox::syscall_broker::COMMAND_OPEN,
sandbox::syscall_broker::COMMAND_READLINK,
sandbox::syscall_broker::COMMAND_STAT,
sandbox::syscall_broker::COMMAND_UNLINK,
}),
GetAudioFilePermissions(),
service_manager::SandboxLinux::PreSandboxHook(),
options);
// TODO(https://crbug.com/850878) enable namespace sandbox. Currently, if
// enabled, connect() on pulse native socket fails with ENOENT (called from
// pa_context_connect).
return true;
}
} // namespace audio