Bug 1640345 - Add a hidden pref to prevent sandboxed content processes from connecting to the X server. r=gcp

This adds the boolean pref security.sandbox.content.headless (on Linux
only) which does two things:

1. Sets the MOZ_HEADLESS env var for content processes, so that they
don't initialize GTK and don't connect to the X server.

2. Disallows brokered access to parts of the filesystem used only for
graphics -- most critically connecting to the X11 socket itself, but
also opening GPU device nodes and the parts of sysfs used by Mesa, for
example.

This is experimental; use at your own risk.

Setting this pref will break native widgets, so it's also necessary to
set widget.disable-native-theme-for-content

Additionally, it breaks Flash and WebGL; see bug 1638466 for the latter.

Differential Revision: https://phabricator.services.mozilla.com/D81425
This commit is contained in:
Jed Davis 2020-07-01 21:10:36 +00:00
parent 30edd06026
commit 3bfc3ec49f
3 changed files with 67 additions and 33 deletions

View File

@ -8892,6 +8892,18 @@
mirror: always
#endif
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
# Run content processes in headless mode and disallow connections to
# the X server. Experimental; breaks WebGL and Flash, and requires
# `widget.disable-native-theme-for-content`. Changing it requires a
# restart because sandbox policy information dependent on it is cached.
# See bug 1640345 for details.
- name: security.sandbox.content.headless
type: bool
value: false
mirror: once
#endif
# When comparing schemes, if this pref is set, view-source URIs are reachable
# from same-protocol (so e.g. file: can link to view-source:file). This is
# required for reftests.

View File

@ -12,10 +12,11 @@
#include "mozilla/Array.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "mozilla/SandboxLaunch.h"
#include "mozilla/SandboxSettings.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/SandboxLaunch.h"
#include "mozilla/dom/ContentChild.h"
#include "nsPrintfCString.h"
#include "nsString.h"
@ -291,16 +292,21 @@ static void AddDynamicPathList(SandboxBroker::Policy* policy,
}
void SandboxBrokerPolicyFactory::InitContentPolicy() {
const bool headless =
StaticPrefs::security_sandbox_content_headless_AtStartup();
// Policy entries that are the same in every process go here, and
// are cached over the lifetime of the factory.
SandboxBroker::Policy* policy = new SandboxBroker::Policy;
// Write permssions
//
// Bug 1308851: NVIDIA proprietary driver when using WebGL
policy->AddFilePrefix(rdwr, "/dev", "nvidia");
if (!headless) {
// Bug 1308851: NVIDIA proprietary driver when using WebGL
policy->AddFilePrefix(rdwr, "/dev", "nvidia");
// Bug 1312678: radeonsi/Intel with DRI when using WebGL
policy->AddDir(rdwr, "/dev/dri");
// Bug 1312678: Mesa with DRI when using WebGL
policy->AddDir(rdwr, "/dev/dri");
}
// Bug 1575985: WASM library sandbox needs RW access to /dev/null
policy->AddPath(rdwr, "/dev/null");
@ -326,12 +332,16 @@ void SandboxBrokerPolicyFactory::InitContentPolicy() {
policy->AddDir(rdonly, "/run/host/user-fonts");
policy->AddDir(rdonly, "/var/cache/fontconfig");
AddMesaSysfsPaths(policy);
if (!headless) {
AddMesaSysfsPaths(policy);
}
AddLdconfigPaths(policy);
AddLdLibraryEnvPaths(policy);
// Bug 1385715: NVIDIA PRIME support
policy->AddPath(rdonly, "/proc/modules");
if (!headless) {
// Bug 1385715: NVIDIA PRIME support
policy->AddPath(rdonly, "/proc/modules");
}
// Allow access to XDG_CONFIG_PATH and XDG_CONFIG_DIRS
if (const auto xdgConfigPath = PR_GetEnv("XDG_CONFIG_PATH")) {
@ -484,28 +494,30 @@ void SandboxBrokerPolicyFactory::InitContentPolicy() {
}
#endif
// Allow Primus to contact the Bumblebee daemon to manage GPU
// switching on NVIDIA Optimus systems.
const char* bumblebeeSocket = PR_GetEnv("BUMBLEBEE_SOCKET");
if (bumblebeeSocket == nullptr) {
bumblebeeSocket = "/var/run/bumblebee.socket";
}
policy->AddPath(SandboxBroker::MAY_CONNECT, bumblebeeSocket);
if (!headless) {
// Allow Primus to contact the Bumblebee daemon to manage GPU
// switching on NVIDIA Optimus systems.
const char* bumblebeeSocket = PR_GetEnv("BUMBLEBEE_SOCKET");
if (bumblebeeSocket == nullptr) {
bumblebeeSocket = "/var/run/bumblebee.socket";
}
policy->AddPath(SandboxBroker::MAY_CONNECT, bumblebeeSocket);
#if defined(MOZ_WIDGET_GTK)
// Allow local X11 connections, for Primus and VirtualGL to contact
// the secondary X server. No exception for Wayland.
// Allow local X11 connections, for Primus and VirtualGL to contact
// the secondary X server. No exception for Wayland.
# if defined(MOZ_WAYLAND)
if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X");
}
if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X");
}
# else
policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X");
policy->AddPrefix(SandboxBroker::MAY_CONNECT, "/tmp/.X11-unix/X");
# endif
if (const auto xauth = PR_GetEnv("XAUTHORITY")) {
policy->AddPath(rdonly, xauth);
}
if (const auto xauth = PR_GetEnv("XAUTHORITY")) {
policy->AddPath(rdonly, xauth);
}
#endif
}
// Read any extra paths that will get write permissions,
// configured by the user or distro
@ -606,7 +618,7 @@ void SandboxBrokerPolicyFactory::InitContentPolicy() {
// Bug 1434711 - AMDGPU-PRO crashes if it can't read it's marketing ids
// and various other things
if (HasAtiDrivers()) {
if (!headless && HasAtiDrivers()) {
policy->AddDir(rdonly, "/opt/amdgpu/share");
policy->AddPath(rdonly, "/sys/module/amdgpu");
// AMDGPU-PRO's MESA version likes to readlink a lot of things here

View File

@ -33,6 +33,7 @@
#include "mozilla/SandboxSettings.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/Unused.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
@ -170,14 +171,16 @@ static bool ContentNeedsSysVIPC() {
}
#endif
// Bug 1438391: VirtualGL uses SysV shm for images and configuration.
if (PR_GetEnv("VGL_ISACTIVE") != nullptr) {
return true;
}
if (!StaticPrefs::security_sandbox_content_headless_AtStartup()) {
// Bug 1438391: VirtualGL uses SysV shm for images and configuration.
if (PR_GetEnv("VGL_ISACTIVE") != nullptr) {
return true;
}
// The fglrx (ATI Catalyst) GPU drivers use SysV IPC.
if (HasAtiDrivers()) {
return true;
// The fglrx (ATI Catalyst) GPU drivers use SysV IPC.
if (HasAtiDrivers()) {
return true;
}
}
return false;
@ -293,6 +296,10 @@ void SandboxLaunchPrepare(GeckoProcessType aType,
} else {
flags |= CLONE_NEWIPC;
}
if (StaticPrefs::security_sandbox_content_headless_AtStartup()) {
aOptions->env_map["MOZ_HEADLESS"] = "1";
}
}
// Anything below this requires unprivileged user namespaces.
@ -317,11 +324,14 @@ void SandboxLaunchPrepare(GeckoProcessType aType,
case GeckoProcessType_Content:
if (level >= 4) {
canChroot = true;
// Unshare network namespace if allowed by graphics; see
// function definition above for details. (The display
// local-ness is cached because it won't change.)
static const bool canCloneNet =
IsDisplayLocal() && !PR_GetEnv("RENDERDOC_CAPTUREOPTS");
StaticPrefs::security_sandbox_content_headless_AtStartup() ||
(IsDisplayLocal() && !PR_GetEnv("RENDERDOC_CAPTUREOPTS"));
if (canCloneNet) {
flags |= CLONE_NEWNET;
}