You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chromium/SOURCES/flatpak-Expose-Widevine-int...

327 lines
13 KiB

From 266e6fc37326e45402f826b282b0e0c461614905 Mon Sep 17 00:00:00 2001
From: Ryan Gonzalez <rymg19@gmail.com>
Date: Tue, 17 Nov 2020 13:00:39 -0600
Subject: [PATCH] flatpak: Expose Widevine into the sandbox
---
.../zygote_host/zygote_host_impl_linux.cc | 54 +++++++++++++-
sandbox/linux/services/flatpak_sandbox.cc | 74 ++++++++++++++-----
sandbox/linux/services/flatpak_sandbox.h | 27 ++++++-
3 files changed, 131 insertions(+), 24 deletions(-)
diff --git a/content/browser/zygote_host/zygote_host_impl_linux.cc b/content/browser/zygote_host/zygote_host_impl_linux.cc
index 00f6ff8e13af5..cf3019e26bbf2 100644
--- a/content/browser/zygote_host/zygote_host_impl_linux.cc
+++ b/content/browser/zygote_host/zygote_host_impl_linux.cc
@@ -9,7 +9,10 @@
#include <sys/types.h>
#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/nix/xdg_util.h"
+#include "base/path_service.h"
#include "base/posix/unix_domain_socket.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
@@ -17,9 +20,12 @@
#include "base/strings/string_number_conversions.h"
#include "base/types/fixed_array.h"
#include "build/build_config.h"
+#include "chrome/common/chrome_paths.h" // nogncheck
#include "content/common/zygote/zygote_commands_linux.h"
#include "content/common/zygote/zygote_communication_linux.h"
#include "content/common/zygote/zygote_handle_impl_linux.h"
+#include "content/public/common/cdm_info.h"
+#include "content/public/common/content_client.h"
#include "content/public/common/zygote/zygote_handle.h"
#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/flatpak_sandbox.h"
@@ -28,6 +34,7 @@
#include "sandbox/linux/suid/common/sandbox.h"
#include "sandbox/policy/linux/sandbox_linux.h"
#include "sandbox/policy/switches.h"
+#include "third_party/widevine/cdm/buildflags.h" // nogncheck
#if BUILDFLAG(IS_CHROMEOS)
#include "content/common/zygote/zygote_communication_linux.h"
@@ -192,8 +199,51 @@ pid_t ZygoteHostImpl::LaunchZygote(
if (is_sandboxed_zygote && use_namespace_sandbox_) {
process = sandbox::NamespaceSandbox::LaunchProcess(*cmd_line, options);
} else if (is_sandboxed_zygote && use_flatpak_sandbox_) {
- process = sandbox::FlatpakSandbox::GetInstance()->LaunchProcess(*cmd_line,
- options);
+ sandbox::FlatpakSandbox::SpawnOptions spawn_options;
+
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ // Expose the CDM paths into the sandbox. This is similar to PreSandboxInit
+ // in content_main_runner_impl.cc.
+ std::vector<CdmInfo> cdms;
+ GetContentClient()->AddContentDecryptionModules(&cdms, nullptr);
+ for (const auto& cdm : cdms) {
+ if (!spawn_options.ExposePathRo(cdm.path)) {
+ LOG(ERROR) << "Failed to expose CDM module";
+ }
+ }
+#endif
+
+#if BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
+ // Make sure we also expose the full Widevine CDM folder so it can be
+ // detected.
+ // TODO: Remove the explicit dependencies on chrome::.
+ base::FilePath widevine_cdm_path;
+ if (!base::PathService::Get(chrome::DIR_COMPONENT_UPDATED_WIDEVINE_CDM,
+ &widevine_cdm_path)) {
+ LOG(ERROR) << "Failed to get Widevine CDM folder for sandbox forwarding";
+ }
+
+ LOG(INFO) << "Widevine CDM path IS: " << widevine_cdm_path;
+
+ if (!widevine_cdm_path.empty() && base::PathExists(widevine_cdm_path)) {
+ if (!spawn_options.ExposePathRo(widevine_cdm_path)) {
+ LOG(ERROR) << "Failed to expose updated Widevine CDM path";
+ }
+ }
+
+ // The Widevine data is found relative to $XDG_CONFIG_HOME, which is not set
+ // by default when running a sandboxed process.
+ auto env = base::Environment::Create();
+ base::FilePath xdgConfigHome = base::nix::GetXDGDirectory(
+ env.get(), base::nix::kXdgConfigHomeEnvVar, nullptr);
+ if (!xdgConfigHome.empty()) {
+ options.environment[base::nix::kXdgConfigHomeEnvVar] =
+ xdgConfigHome.value();
+ }
+#endif
+
+ process = sandbox::FlatpakSandbox::GetInstance()->LaunchProcess(
+ *cmd_line, options, spawn_options);
} else {
process = base::LaunchProcess(*cmd_line, options);
}
diff --git a/sandbox/linux/services/flatpak_sandbox.cc b/sandbox/linux/services/flatpak_sandbox.cc
index 31229fdf59127..cabda783879e6 100644
--- a/sandbox/linux/services/flatpak_sandbox.cc
+++ b/sandbox/linux/services/flatpak_sandbox.cc
@@ -4,6 +4,7 @@
#include "sandbox/linux/services/flatpak_sandbox.h"
+#include <fcntl.h>
#include <signal.h>
#include <sstream>
#include <string>
@@ -92,6 +93,18 @@ enum FlatpakSpawnSandboxFlags {
kFlatpakSpawnSandbox_ShareA11yBus = 1 << 4,
};
+bool FlatpakSandbox::SpawnOptions::ExposePathRo(base::FilePath path) {
+ base::ScopedFD fd(
+ HANDLE_EINTR(open(path.value().c_str(), O_PATH | O_NOFOLLOW)));
+ if (!fd.is_valid()) {
+ PLOG(ERROR) << "Failed to expose path " << path;
+ return false;
+ }
+
+ sandbox_expose_ro.push_back(std::move(fd));
+ return true;
+}
+
FlatpakSandbox::FlatpakSandbox()
: bus_thread_("FlatpakPortalBus"), process_info_cv_(&process_info_lock_) {}
@@ -168,8 +181,9 @@ bool FlatpakSandbox::IsPidSandboxed(base::ProcessId relative_pid) {
base::Process FlatpakSandbox::LaunchProcess(
const base::CommandLine& cmdline,
- const base::LaunchOptions& launch_options) {
- base::ProcessId external_pid = Spawn(cmdline, launch_options);
+ const base::LaunchOptions& launch_options,
+ const SpawnOptions& spawn_options /*= {}*/) {
+ base::ProcessId external_pid = Spawn(cmdline, launch_options, spawn_options);
if (external_pid == base::kNullProcessId) {
return base::Process();
}
@@ -363,9 +377,9 @@ void FlatpakSandbox::OnSpawnExitedSignal(dbus::Signal* signal) {
process_info_cv_.Broadcast();
}
-base::ProcessId FlatpakSandbox::Spawn(
- const base::CommandLine& cmdline,
- const base::LaunchOptions& launch_options) {
+base::ProcessId FlatpakSandbox::Spawn(const base::CommandLine& cmdline,
+ const base::LaunchOptions& launch_options,
+ const SpawnOptions& spawn_options) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
base::ScopedAllowBaseSyncPrimitives allow_wait;
@@ -391,24 +405,26 @@ base::ProcessId FlatpakSandbox::Spawn(
FROM_HERE,
base::BindOnce(&FlatpakSandbox::SpawnOnBusThread, base::Unretained(this),
base::Unretained(&external_pid), base::Unretained(&event),
- cmdline, launch_options));
+ base::Unretained(&cmdline),
+ base::Unretained(&launch_options),
+ base::Unretained(&spawn_options)));
event.Wait();
return external_pid;
}
-void FlatpakSandbox::SpawnOnBusThread(
- base::ProcessId* out_external_pid,
- base::WaitableEvent* event,
- const base::CommandLine& cmdline,
- const base::LaunchOptions& launch_options) {
+void FlatpakSandbox::SpawnOnBusThread(base::ProcessId* out_external_pid,
+ base::WaitableEvent* event,
+ const base::CommandLine* cmdline,
+ const base::LaunchOptions* launch_options,
+ const SpawnOptions* spawn_options) {
dbus::ObjectProxy* object_proxy = GetPortalObjectProxy();
dbus::MethodCall method_call(kFlatpakPortalInterfaceName, "Spawn");
dbus::MessageWriter writer(&method_call);
const base::FilePath& current_directory =
- !launch_options.current_directory.empty()
- ? launch_options.current_directory
+ !launch_options->current_directory.empty()
+ ? launch_options->current_directory
// Change to /app since it's guaranteed to always be present in
// the sandbox.
: kFlatpakAppPath;
@@ -417,7 +433,7 @@ void FlatpakSandbox::SpawnOnBusThread(
dbus::MessageWriter argv_writer(nullptr);
writer.OpenArray("ay", &argv_writer);
- for (const std::string& arg : cmdline.argv()) {
+ for (const std::string& arg : cmdline->argv()) {
WriteStringAsByteArray(&argv_writer, arg);
}
@@ -439,7 +455,7 @@ void FlatpakSandbox::SpawnOnBusThread(
WriteFdPairMap(&fds_writer, STDOUT_FILENO, STDOUT_FILENO);
WriteFdPairMap(&fds_writer, STDERR_FILENO, STDERR_FILENO);
- for (const auto& pair : launch_options.fds_to_remap) {
+ for (const auto& pair : launch_options->fds_to_remap) {
WriteFdPairMap(&fds_writer, pair.first, pair.second);
}
@@ -448,7 +464,7 @@ void FlatpakSandbox::SpawnOnBusThread(
dbus::MessageWriter env_writer(nullptr);
writer.OpenArray("{ss}", &env_writer);
- for (const auto& pair : launch_options.environment) {
+ for (const auto& pair : launch_options->environment) {
dbus::MessageWriter entry_writer(nullptr);
env_writer.OpenDictEntry(&entry_writer);
@@ -472,11 +488,11 @@ void FlatpakSandbox::SpawnOnBusThread(
#else
#endif
- if (launch_options.clear_environment) {
+ if (launch_options->clear_environment) {
spawn_flags |= kFlatpakSpawn_ClearEnvironment;
}
- if (launch_options.kill_on_parent_death) {
+ if (launch_options->kill_on_parent_death) {
spawn_flags |= kFlatpakSpawn_WatchBus;
}
@@ -485,6 +501,28 @@ void FlatpakSandbox::SpawnOnBusThread(
dbus::MessageWriter options_writer(nullptr);
writer.OpenArray("{sv}", &options_writer);
+ if (!spawn_options->sandbox_expose_ro.empty()) {
+ dbus::MessageWriter entry_writer(nullptr);
+ options_writer.OpenDictEntry(&entry_writer);
+
+ entry_writer.AppendString("sandbox-expose-fd-ro");
+
+ dbus::MessageWriter variant_writer(nullptr);
+ entry_writer.OpenVariant("ah", &variant_writer);
+
+ dbus::MessageWriter fds_writer(nullptr);
+ variant_writer.OpenArray("h", &fds_writer);
+
+ for (const base::ScopedFD& fd : spawn_options->sandbox_expose_ro) {
+ CHECK(fd.is_valid()) << "Invalid spawn expose fd";
+ fds_writer.AppendFileDescriptor(fd.get());
+ }
+
+ variant_writer.CloseContainer(&fds_writer);
+ entry_writer.CloseContainer(&variant_writer);
+ options_writer.CloseContainer(&entry_writer);
+ }
+
if (sandbox_flags != 0) {
dbus::MessageWriter entry_writer(nullptr);
options_writer.OpenDictEntry(&entry_writer);
diff --git a/sandbox/linux/services/flatpak_sandbox.h b/sandbox/linux/services/flatpak_sandbox.h
index 167bbc85945ad..de8e7165b4573 100644
--- a/sandbox/linux/services/flatpak_sandbox.h
+++ b/sandbox/linux/services/flatpak_sandbox.h
@@ -9,6 +9,8 @@
#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
#include "base/no_destructor.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
@@ -34,6 +36,20 @@ namespace sandbox {
// it is known inside the sandbox's PID namespace.
class SANDBOX_EXPORT FlatpakSandbox {
public:
+ class SpawnOptions {
+ public:
+ SpawnOptions() = default;
+ SpawnOptions(const SpawnOptions& other) = delete;
+ SpawnOptions(SpawnOptions&& other) = delete;
+
+ bool ExposePathRo(base::FilePath path);
+
+ private:
+ friend class FlatpakSandbox;
+
+ std::vector<base::ScopedFD> sandbox_expose_ro;
+ };
+
static FlatpakSandbox* GetInstance();
// Represents the level of sandboxing inside a Flatpak. kNone means this is
@@ -55,7 +71,8 @@ class SANDBOX_EXPORT FlatpakSandbox {
// GetRelativePid. This is the reason why a vanilla ProcessId is returned
// rather than a base::Process instance.
base::Process LaunchProcess(const base::CommandLine& cmdline,
- const base::LaunchOptions& launch_options);
+ const base::LaunchOptions& launch_options,
+ const SpawnOptions& spawn_options = {});
// Indefinitely waits for the given process and fills the exit code pointer
// if given and non-null. Returns false on wait failure.
@@ -84,11 +101,13 @@ class SANDBOX_EXPORT FlatpakSandbox {
void OnSpawnExitedSignal(dbus::Signal* signal);
base::ProcessId Spawn(const base::CommandLine& cmdline,
- const base::LaunchOptions& launch_options);
+ const base::LaunchOptions& launch_options,
+ const SpawnOptions& spawn_options);
void SpawnOnBusThread(base::ProcessId* out_external_pid,
base::WaitableEvent* event,
- const base::CommandLine& cmdline,
- const base::LaunchOptions& launch_options);
+ const base::CommandLine* cmdline,
+ const base::LaunchOptions* launch_options,
+ const SpawnOptions* spawn_options);
void OnSpawnResponse(base::ProcessId* out_external_pid,
base::WaitableEvent* event,
dbus::Response* response,
--
2.47.1