Bug 1043733 - Require sandboxing to load Gecko Media Plugins on Linux. r=jesup r=kang

Also refactors how sandbox support and disabling are handled, and allows
simulating a lack of sandbox support with an env var (for testing
without rebuilding a kernel).
This commit is contained in:
Jed Davis 2014-08-12 21:28:27 -07:00
parent cf9ebe3f4b
commit de2880107d
5 changed files with 86 additions and 31 deletions

View File

@ -157,6 +157,7 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
// Enable sandboxing here -- we know the plugin file's path, but
// this process's execution hasn't been affected by its content yet.
MOZ_ASSERT(mozilla::CanSandboxMediaPlugin());
mozilla::SetMediaPluginSandbox(nativePath.get());
#endif

View File

@ -20,6 +20,9 @@
#include "GMPDecryptorParent.h"
#include "GMPAudioDecoderParent.h"
#include "runnable_utils.h"
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
#include "mozilla/Sandbox.h"
#endif
namespace mozilla {
@ -453,6 +456,11 @@ NS_IMETHODIMP
GeckoMediaPluginService::AddPluginDirectory(const nsAString& aDirectory)
{
MOZ_ASSERT(NS_IsMainThread());
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!mozilla::CanSandboxMediaPlugin()) {
return NS_ERROR_NOT_AVAILABLE;
}
#endif
nsCOMPtr<nsIThread> thread;
nsresult rv = GetThread(getter_AddRefs(thread));
if (NS_FAILED(rv)) {

View File

@ -922,7 +922,9 @@ ContentChild::RecvSetProcessSandbox()
// at some point; see bug 880808.
#if defined(MOZ_CONTENT_SANDBOX)
#if defined(XP_LINUX)
SetContentProcessSandbox();
if (CanSandboxContentProcess()) {
SetContentProcessSandbox();
}
#elif defined(XP_WIN)
mozilla::SandboxTarget::Instance()->StartSandbox();
#endif

View File

@ -58,6 +58,40 @@ static int gMediaPluginFileDesc = -1;
static const char *gMediaPluginFilePath;
#endif
struct SandboxFlags {
bool isSupported;
#ifdef MOZ_CONTENT_SANDBOX
bool isDisabledForContent;
#endif
#ifdef MOZ_GMP_SANDBOX
bool isDisabledForGMP;
#endif
SandboxFlags() {
// Allow simulating the absence of seccomp-bpf support, for testing.
if (getenv("MOZ_FAKE_NO_SANDBOX")) {
isSupported = false;
} else {
// Determine whether seccomp-bpf is supported by trying to
// enable it with an invalid pointer for the filter. This will
// fail with EFAULT if supported and EINVAL if not, without
// changing the process's state.
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr) != -1) {
MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr) didn't fail");
}
isSupported = errno == EFAULT;
}
#ifdef MOZ_CONTENT_SANDBOX
isDisabledForContent = getenv("MOZ_DISABLE_CONTENT_SANDBOX");
#endif
#ifdef MOZ_GMP_SANDBOX
isDisabledForGMP = getenv("MOZ_DISABLE_GMP_SANDBOX");
#endif
}
};
static const SandboxFlags gSandboxFlags;
/**
* Log JS stack info in the same place as the sandbox violation
* message. Useful in case the responsible code is JS and all we have
@ -224,20 +258,23 @@ InstallSyscallReporter(void)
* to pass a bpf program (in our case, it contains a syscall
* whitelist).
*
* @return 0 on success, 1 on failure.
* Reports failure by crashing.
*
* @see sock_fprog (the seccomp_prog).
*/
static int
static void
InstallSyscallFilter(const sock_fprog *prog)
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
return 1;
LOG_ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %s", strerror(errno));
MOZ_CRASH("prctl(PR_SET_NO_NEW_PRIVS)");
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)prog, 0, 0)) {
return 1;
LOG_ERROR("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) failed: %s",
strerror(errno));
MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
}
return 0;
}
// Use signals for permissions that need to be set per-thread.
@ -268,22 +305,16 @@ FindFreeSignalNumber()
return 0;
}
// Returns true if sandboxing was enabled, or false if sandboxing
// already was enabled. Crashes if sandboxing could not be enabled.
static bool
SetThreadSandbox()
{
bool didAnything = false;
if (prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
if (InstallSyscallFilter(sSetSandboxFilter) == 0) {
didAnything = true;
}
/*
* Bug 880797: when all B2G devices are required to support
* seccomp-bpf, this should exit/crash if InstallSyscallFilter
* returns nonzero (ifdef MOZ_WIDGET_GONK).
*/
InstallSyscallFilter(sSetSandboxFilter);
return true;
}
return didAnything;
return false;
}
static void
@ -435,14 +466,6 @@ BroadcastSetThreadSandbox(SandboxType aType)
SetThreadSandbox();
}
// This function can overapproximate (i.e., return true even if
// sandboxing isn't supported, but not the reverse). See bug 993145.
static bool
IsSandboxingSupported(void)
{
return prctl(PR_GET_SECCOMP) != -1;
}
// Common code for sandbox startup.
static void
SetCurrentProcessSandbox(SandboxType aType)
@ -451,9 +474,7 @@ SetCurrentProcessSandbox(SandboxType aType)
LOG_ERROR("install_syscall_reporter() failed\n");
}
if (IsSandboxingSupported()) {
BroadcastSetThreadSandbox(aType);
}
BroadcastSetThreadSandbox(aType);
}
#ifdef MOZ_CONTENT_SANDBOX
@ -466,12 +487,18 @@ SetCurrentProcessSandbox(SandboxType aType)
void
SetContentProcessSandbox()
{
if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
if (gSandboxFlags.isDisabledForContent) {
return;
}
SetCurrentProcessSandbox(kSandboxContentProcess);
}
bool
CanSandboxContentProcess()
{
return gSandboxFlags.isSupported || gSandboxFlags.isDisabledForContent;
}
#endif // MOZ_CONTENT_SANDBOX
#ifdef MOZ_GMP_SANDBOX
@ -489,7 +516,7 @@ SetContentProcessSandbox()
void
SetMediaPluginSandbox(const char *aFilePath)
{
if (PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
if (gSandboxFlags.isDisabledForGMP) {
return;
}
@ -504,6 +531,12 @@ SetMediaPluginSandbox(const char *aFilePath)
// Finally, start the sandbox.
SetCurrentProcessSandbox(kSandboxMediaPlugin);
}
bool
CanSandboxMediaPlugin()
{
return gSandboxFlags.isSupported || gSandboxFlags.isDisabledForGMP;
}
#endif // MOZ_GMP_SANDBOX
} // namespace mozilla

View File

@ -9,14 +9,25 @@
namespace mozilla {
// The Set*Sandbox() functions must not be called if the corresponding
// CanSandbox*() function has returned false; if sandboxing is
// attempted, any failure to enable it is fatal.
//
// If sandboxing is disabled for a process type with the corresponding
// environment variable, Set*Sandbox() does nothing and CanSandbox*()
// returns true.
#ifdef MOZ_CONTENT_SANDBOX
// Disabled by setting env var MOZ_DISABLE_CONTENT_SANDBOX.
bool CanSandboxContentProcess();
void SetContentProcessSandbox();
#endif
#ifdef MOZ_GMP_SANDBOX
// Disabled by setting env var MOZ_DISABLE_GMP_SANDBOX.
bool CanSandboxMediaPlugin();
void SetMediaPluginSandbox(const char *aFilePath);
#endif
} // namespace mozilla
#endif // mozilla_Sandbox_h