123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- // 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/environment.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/logging.h"
- #include "base/path_service.h"
- #include "base/strings/string_piece.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 asoundrc =
- home_dir.Append(FILE_PATH_LITERAL(".asoundrc"));
- const std::string read_only_filenames[]{"/etc/asound.conf", "/proc/cpuinfo",
- "/etc/group", "/etc/nsswitch.conf",
- asoundrc.value()};
- for (const auto& filename : read_only_filenames)
- 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 dev_aload_path[] =
- FILE_PATH_LITERAL("/dev/aloadC");
- for (int i = 0; i <= 31; ++i) {
- permissions->push_back(BrokerFilePermission::ReadWrite(
- base::StringPrintf("%s%d", dev_aload_path, i)));
- }
- }
- #endif
- #if defined(USE_PULSEAUDIO)
- // Utility function used to grant permissions on paths used by PulseAudio which
- // are specified through environment variables. |recursive_only| is used to
- // determine if the path itself should be allowed access or only its content.
- void AllowAccessToEnvSpecifiedPath(
- base::StringPiece variable_name,
- std::vector<BrokerFilePermission>* permissions,
- bool recursive_only) {
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- std::string path_value;
- if (!env->GetVar(variable_name, &path_value))
- return;
- const base::FilePath pa_config_path(path_value);
- if (pa_config_path.empty())
- return;
- if (!recursive_only) {
- permissions->push_back(BrokerFilePermission::ReadWriteCreate(
- pa_config_path.StripTrailingSeparators().value()));
- }
- permissions->push_back(BrokerFilePermission::ReadWriteCreateRecursive(
- pa_config_path.AsEndingWithSeparator().value()));
- }
- void AddPulseAudioFilePermissions(
- std::vector<BrokerFilePermission>* permissions) {
- base::FilePath home_dir;
- base::PathService::Get(base::DIR_HOME, &home_dir);
- const base::FilePath xauthority_path =
- 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 read_only_filenames[]{
- "/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", xauthority_path.value()};
- for (const auto& filename : read_only_filenames)
- permissions->push_back(BrokerFilePermission::ReadOnly(filename));
- // In certain situations, pulse runs stat() on the home directory.
- permissions->push_back(
- BrokerFilePermission::StatOnlyWithIntermediateDirs(home_dir.value()));
- permissions->push_back(
- BrokerFilePermission::ReadOnlyRecursive("/etc/pulse/"));
- // At times, Pulse tries to create the directory even if the directory already
- // exists and fails if the mkdir() operation returns anything other than
- // "success" or "exists".
- const char* pulse_home_dirs[] = {".pulse", ".config/pulse"};
- for (const char* pulse_home_dir : pulse_home_dirs) {
- const base::FilePath pulse_home_path = home_dir.Append(pulse_home_dir);
- permissions->push_back(
- BrokerFilePermission::ReadWriteCreate(pulse_home_path.value()));
- permissions->push_back(BrokerFilePermission::ReadWriteCreateRecursive(
- pulse_home_path.AsEndingWithSeparator().value()));
- }
- // Pulse might also need to create directories in tmp of the form
- // "/tmp/pulse-<random string>".
- permissions->push_back(
- BrokerFilePermission::ReadWriteCreateRecursive("/tmp/"));
- const char* env_tmp_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
- for (const char* env_tmp_path : env_tmp_paths) {
- AllowAccessToEnvSpecifiedPath(env_tmp_path, permissions,
- /*recursive_only=*/true);
- }
- // Read up the Pulse paths specified via environment variable and allow for
- // read/write/create recursively on the directory.
- const char* env_pulse_paths[] = {"PULSE_CONFIG_PATH", "PULSE_RUNTIME_PATH",
- "PULSE_STATE_PATH"};
- for (const char* env_pulse_path : env_pulse_paths) {
- AllowAccessToEnvSpecifiedPath(env_pulse_path, permissions,
- /*recursive_only=*/false);
- }
- const char* run_user_paths[] = {"/run/user", "/var/run/user"};
- for (const char* run_user_path : run_user_paths) {
- const std::string path =
- base::StringPrintf("%s/%d", run_user_path, getuid());
- permissions->push_back(BrokerFilePermission::ReadWriteCreate(path));
- permissions->push_back(
- BrokerFilePermission::ReadWriteCreate(path + "/pulse"));
- permissions->push_back(
- BrokerFilePermission::ReadWriteCreateRecursive(path + "/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 libraries[]{"libasound.so.2", "libpulse.so.0",
- "libnss_files.so.2", "libnss_compat.so.2"};
- for (const auto& library_name : libraries) {
- 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(sandbox::policy::SandboxLinux::Options options) {
- LoadAudioLibraries();
- auto* instance = sandbox::policy::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(),
- sandbox::policy::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
|