Backed out changeset d50d7e88f35e (bug 1012951) for LSan failures

This commit is contained in:
Ed Morley 2014-07-30 16:49:43 +01:00
parent d8e2768ac7
commit aa4fee503c
8 changed files with 74 additions and 321 deletions

View File

@ -3844,7 +3844,6 @@ MOZ_PAY=
MOZ_AUDIO_CHANNEL_MANAGER=
NSS_NO_LIBPKIX=
MOZ_CONTENT_SANDBOX=
MOZ_GMP_SANDBOX=
JSGC_USE_EXACT_ROOTING=1
JSGC_GENERATIONAL=
@ -6406,28 +6405,6 @@ fi
AC_SUBST(MOZ_CONTENT_SANDBOX)
dnl ========================================================
dnl = Gecko Media Plugin sandboxing
dnl ========================================================
case $OS_TARGET in
WINNT)
MOZ_GMP_SANDBOX=1
;;
Linux)
case $CPU_ARCH in
x86_64|x86)
MOZ_GMP_SANDBOX=1
;;
esac
;;
esac
if test -n "$MOZ_GMP_SANDBOX"; then
AC_DEFINE(MOZ_GMP_SANDBOX)
fi
AC_SUBST(MOZ_GMP_SANDBOX)
dnl ========================================================
dnl =
dnl = Module specific options

View File

@ -26,8 +26,6 @@ using mozilla::dom::CrashReporterChild;
#if defined(XP_WIN)
#define TARGET_SANDBOX_EXPORTS
#include "mozilla/sandboxTarget.h"
#elif defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
#include "mozilla/Sandbox.h"
#endif
namespace mozilla {
@ -100,13 +98,6 @@ GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
nsAutoCString nativePath;
libFile->GetNativePath(nativePath);
#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.
mozilla::SetMediaPluginSandbox(nativePath.get());
#endif
mLib = PR_LoadLibrary(nativePath.get());
if (!mLib) {
return false;

View File

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

View File

@ -19,7 +19,6 @@
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include "mozilla/Atomics.h"
#include "mozilla/NullPtr.h"
@ -37,8 +36,10 @@
#include <android/log.h>
#endif
#if defined(MOZ_CONTENT_SANDBOX)
#include "linux_seccomp.h"
#include "SandboxFilter.h"
#endif
#ifdef MOZ_LOGGING
#define FORCE_PR_LOG 1
@ -59,14 +60,6 @@ static PRLogModuleInfo* gSeccompSandboxLog;
#define LOG_ERROR(args...)
#endif
#ifdef MOZ_GMP_SANDBOX
// For media plugins, we can start the sandbox before we dlopen the
// module, so we have to pre-open the file and simulate the sandboxed
// open().
static int gMediaPluginFileDesc = -1;
static nsCString gMediaPluginFilePath;
#endif
/**
* 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
@ -144,27 +137,6 @@ Reporter(int nr, siginfo_t *info, void *void_context)
args[4] = SECCOMP_PARM5(ctx);
args[5] = SECCOMP_PARM6(ctx);
#ifdef MOZ_GMP_SANDBOX
if (syscall_nr == __NR_open && !gMediaPluginFilePath.IsEmpty()) {
const char *path = reinterpret_cast<const char*>(args[0]);
int flags = int(args[1]);
if ((flags & O_ACCMODE) != O_RDONLY) {
LOG_ERROR("non-read-only open of file %s attempted (flags=0%o)",
path, flags);
} else if (strcmp(path, gMediaPluginFilePath.get()) != 0) {
LOG_ERROR("attempt to open file %s which is not the media plugin %s",
path, gMediaPluginFilePath.get());
} else if (gMediaPluginFileDesc == -1) {
LOG_ERROR("multiple opens of media plugin file unimplemented");
} else {
SECCOMP_RESULT(ctx) = gMediaPluginFileDesc;
gMediaPluginFileDesc = -1;
return;
}
}
#endif
LOG_ERROR("seccomp sandbox violation: pid %d, syscall %lu, args %lu %lu %lu"
" %lu %lu %lu. Killing process.", pid, syscall_nr,
args[0], args[1], args[2], args[3], args[4], args[5]);
@ -282,7 +254,8 @@ SetThreadSandbox()
{
bool didAnything = false;
if (prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX") == nullptr &&
prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
if (InstallSyscallFilter(sSetSandboxFilter) == 0) {
didAnything = true;
}
@ -312,19 +285,19 @@ SetThreadSandboxHandler(int signum)
}
static void
BroadcastSetThreadSandbox(SandboxType aType)
BroadcastSetThreadSandbox()
{
int signum;
pid_t pid, tid, myTid;
pid_t pid, tid;
DIR *taskdp;
struct dirent *de;
SandboxFilter filter(&sSetSandboxFilter, aType,
PR_GetEnv("MOZ_SANDBOX_VERBOSE"));
SandboxFilter filter(&sSetSandboxFilter,
PR_GetEnv("MOZ_CONTENT_SANDBOX_VERBOSE"));
static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
"mozilla::Atomic<int> isn't represented by an int");
MOZ_ASSERT(NS_IsMainThread());
pid = getpid();
myTid = syscall(__NR_gettid);
taskdp = opendir("/proc/self/task");
if (taskdp == nullptr) {
LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
@ -357,9 +330,9 @@ BroadcastSetThreadSandbox(SandboxType aType)
// Not a task ID.
continue;
}
if (tid == myTid) {
// Drop this thread's privileges last, below, so we can
// continue to signal other threads.
if (tid == pid) {
// Drop the main thread's privileges last, below, so
// we can continue to signal other threads.
continue;
}
// Reset the futex cell and signal.
@ -452,9 +425,14 @@ IsSandboxingSupported(void)
return prctl(PR_GET_SECCOMP) != -1;
}
// Common code for sandbox startup.
static void
SetCurrentProcessSandbox(SandboxType aType)
/**
* Starts the seccomp sandbox for this process and sets user/group-based privileges.
* Should be called only once, and before any potentially harmful content is loaded.
*
* Should normally make the process exit on failure.
*/
void
SetCurrentProcessSandbox()
{
#if !defined(ANDROID) && defined(PR_LOGGING)
if (!gSeccompSandboxLog) {
@ -468,60 +446,10 @@ SetCurrentProcessSandbox(SandboxType aType)
}
if (IsSandboxingSupported()) {
BroadcastSetThreadSandbox(aType);
BroadcastSetThreadSandbox();
}
}
#ifdef MOZ_CONTENT_SANDBOX
/**
* Starts the seccomp sandbox for a content process. Should be called
* only once, and before any potentially harmful content is loaded.
*
* Will normally make the process exit on failure.
*/
void
SetContentProcessSandbox()
{
if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
return;
}
SetCurrentProcessSandbox(kSandboxContentProcess);
}
#endif // MOZ_CONTENT_SANDBOX
#ifdef MOZ_GMP_SANDBOX
/**
* Starts the seccomp sandbox for a media plugin process. Should be
* called only once, and before any potentially harmful content is
* loaded -- including the plugin itself, if it's considered untrusted.
*
* The file indicated by aFilePath, if non-null, can be open()ed once
* read-only after the sandbox starts; it should be the .so file
* implementing the not-yet-loaded plugin.
*
* Will normally make the process exit on failure.
*/
void
SetMediaPluginSandbox(const char *aFilePath)
{
if (PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
return;
}
if (aFilePath) {
gMediaPluginFilePath.Assign(aFilePath);
gMediaPluginFileDesc = open(aFilePath, O_RDONLY | O_CLOEXEC);
if (gMediaPluginFileDesc == -1) {
LOG_ERROR("failed to open plugin file %s: %s", aFilePath, strerror(errno));
MOZ_CRASH();
}
}
// Finally, start the sandbox.
SetCurrentProcessSandbox(kSandboxMediaPlugin);
}
#endif // MOZ_GMP_SANDBOX
} // namespace mozilla

View File

@ -9,12 +9,7 @@
namespace mozilla {
#ifdef MOZ_CONTENT_SANDBOX
void SetContentProcessSandbox();
#endif
#ifdef MOZ_GMP_SANDBOX
void SetMediaPluginSandbox(const char *aFilePath);
#endif
void SetCurrentProcessSandbox();
} // namespace mozilla

View File

@ -14,26 +14,49 @@
#include "mozilla/NullPtr.h"
#include <errno.h>
#include <linux/ipc.h>
#include <linux/net.h>
#include <linux/prctl.h>
#include <linux/sched.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <linux/net.h>
#include <linux/ipc.h>
namespace mozilla {
class SandboxFilterImpl : public SandboxAssembler
{
void Build();
public:
virtual void Build() = 0;
virtual ~SandboxFilterImpl() { }
SandboxFilterImpl() {
Build();
Finish();
}
};
// Some helper macros to make the code that builds the filter more
// readable, and to help deal with differences among architectures.
SandboxFilter::SandboxFilter(const sock_fprog** aStored, bool aVerbose)
: mStored(aStored)
{
MOZ_ASSERT(*mStored == nullptr);
std::vector<struct sock_filter> filterVec;
{
SandboxFilterImpl impl;
impl.Compile(&filterVec, aVerbose);
}
mProg = new sock_fprog;
mProg->len = filterVec.size();
mProg->filter = mFilter = new sock_filter[mProg->len];
for (size_t i = 0; i < mProg->len; ++i) {
mFilter[i] = filterVec[i];
}
*mStored = mProg;
}
SandboxFilter::~SandboxFilter()
{
*mStored = nullptr;
delete[] mFilter;
delete mProg;
}
void
SandboxFilterImpl::Build() {
#define SYSCALL_EXISTS(name) (defined(__NR_##name))
#define SYSCALL(name) (Condition(__NR_##name))
@ -46,40 +69,32 @@ public:
Condition(__NR_##name, arg, argValues); \
})
// Some architectures went through a transition from 32-bit to
// 64-bit off_t and had to version all the syscalls that referenced
// it; others (newer and/or 64-bit ones) didn't. Adjust the
// conditional as needed.
// Some architectures went through a transition from 32-bit to
// 64-bit off_t and had to version all the syscalls that referenced
// it; others (newer and/or 64-bit ones) didn't. Adjust the
// conditional as needed.
#if SYSCALL_EXISTS(stat64)
#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(versioned)
#else
#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(plain)
#endif
// i386 multiplexes all the socket-related interfaces into a single
// syscall.
// i386 multiplexes all the socket-related interfaces into a single
// syscall.
#if SYSCALL_EXISTS(socketcall)
#define SOCKETCALL(name, NAME) SYSCALL_WITH_ARG(socketcall, 0, SYS_##NAME)
#else
#define SOCKETCALL(name, NAME) SYSCALL(name)
#endif
// i386 multiplexes all the SysV-IPC-related interfaces into a single
// syscall.
// i386 multiplexes all the SysV-IPC-related interfaces into a single
// syscall.
#if SYSCALL_EXISTS(ipc)
#define SYSVIPCCALL(name, NAME) SYSCALL_WITH_ARG(ipc, 0, NAME)
#else
#define SYSVIPCCALL(name, NAME) SYSCALL(name)
#endif
#ifdef MOZ_CONTENT_SANDBOX
class SandboxFilterImplContent : public SandboxFilterImpl {
protected:
virtual void Build() MOZ_OVERRIDE;
};
void
SandboxFilterImplContent::Build() {
/* Most used system calls should be at the top of the whitelist
* for performance reasons. The whitelist BPF filter exits after
* processing any ALLOW_SYSCALL macro.
@ -310,150 +325,5 @@ SandboxFilterImplContent::Build() {
Allow(SYSCALL(exit_group));
Allow(SYSCALL(exit));
}
#endif // MOZ_CONTENT_SANDBOX
#ifdef MOZ_GMP_SANDBOX
class SandboxFilterImplGMP : public SandboxFilterImpl {
protected:
virtual void Build() MOZ_OVERRIDE;
};
void SandboxFilterImplGMP::Build() {
// As for content processes, check the most common syscalls first.
Allow(SYSCALL_WITH_ARG(clock_gettime, 0, CLOCK_MONOTONIC, CLOCK_REALTIME));
Allow(SYSCALL(futex));
Allow(SYSCALL(gettimeofday));
Allow(SYSCALL(poll));
Allow(SYSCALL(write));
Allow(SYSCALL(read));
Allow(SYSCALL(epoll_wait));
Allow(SOCKETCALL(recvmsg, RECVMSG));
Allow(SOCKETCALL(sendmsg, SENDMSG));
Allow(SYSCALL(time));
// Nothing after this line is performance-critical.
#if SYSCALL_EXISTS(mmap2)
Allow(SYSCALL(mmap2));
#else
Allow(SYSCALL(mmap));
#endif
Allow(SYSCALL_LARGEFILE(fstat, fstat64));
Allow(SYSCALL(munmap));
Allow(SYSCALL(gettid));
// The glibc source hasn't changed the thread creation clone flags
// since 2004, so this *should* be safe to hard-code. Bionic is
// different, but MOZ_GMP_SANDBOX isn't supported there yet.
//
// At minimum we should require CLONE_THREAD, so that a single
// SIGKILL from the parent will destroy all descendant tasks. In
// general, pinning down as much of the flags word as possible is a
// good idea, because it exposes a lot of subtle (and probably not
// well tested in all cases) kernel functionality.
//
// WARNING: s390 and cris pass the flags in a different arg -- see
// CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
// don't support seccomp-bpf on those archs yet.
static const int new_thread_flags = CLONE_VM | CLONE_FS | CLONE_FILES |
CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
Allow(SYSCALL_WITH_ARG(clone, 0, new_thread_flags));
Allow(SYSCALL_WITH_ARG(prctl, 0, PR_GET_SECCOMP, PR_SET_NAME));
#if SYSCALL_EXISTS(set_robust_list)
Allow(SYSCALL(set_robust_list));
#endif
// NSPR can call this when creating a thread, but it will accept a
// polite "no".
Deny(EACCES, SYSCALL(getpriority));
Allow(SYSCALL(mprotect));
Allow(SYSCALL_WITH_ARG(madvise, 2, MADV_DONTNEED));
#if SYSCALL_EXISTS(sigreturn)
Allow(SYSCALL(sigreturn));
#endif
Allow(SYSCALL(rt_sigreturn));
Allow(SYSCALL(restart_syscall));
Allow(SYSCALL(close));
// "Sleeping for 300 seconds" in debug crashes; possibly other uses.
Allow(SYSCALL(nanosleep));
// For the crash reporter:
#if SYSCALL_EXISTS(sigprocmask)
Allow(SYSCALL(sigprocmask));
#endif
Allow(SYSCALL(rt_sigprocmask));
#if SYSCALL_EXISTS(sigaction)
Allow(SYSCALL(sigaction));
#endif
Allow(SYSCALL(rt_sigaction));
Allow(SOCKETCALL(socketpair, SOCKETPAIR));
Allow(SYSCALL_WITH_ARG(tgkill, 0, uint32_t(getpid())));
Allow(SYSCALL_WITH_ARG(prctl, 0, PR_SET_DUMPABLE));
// Note for when GMP is supported on an ARM platform: Add whichever
// of the ARM-specific syscalls are needed for this type of process.
Allow(SYSCALL(epoll_ctl));
Allow(SYSCALL(exit));
Allow(SYSCALL(exit_group));
}
#endif // MOZ_GMP_SANDBOX
SandboxFilter::SandboxFilter(const sock_fprog** aStored, SandboxType aType,
bool aVerbose)
: mStored(aStored)
{
MOZ_ASSERT(*mStored == nullptr);
std::vector<struct sock_filter> filterVec;
SandboxFilterImpl *impl;
switch (aType) {
case kSandboxContentProcess:
#ifdef MOZ_CONTENT_SANDBOX
impl = new SandboxFilterImplContent();
#else
MOZ_CRASH("Content process sandboxing not supported in this build!");
#endif
break;
case kSandboxMediaPlugin:
#ifdef MOZ_GMP_SANDBOX
impl = new SandboxFilterImplGMP();
#else
MOZ_CRASH("Gecko Media Plugin process sandboxing not supported in this"
" build!");
#endif
break;
default:
MOZ_CRASH("Nonexistent sandbox type!");
}
impl->Build();
impl->Finish();
impl->Compile(&filterVec, aVerbose);
delete impl;
mProg = new sock_fprog;
mProg->len = filterVec.size();
mProg->filter = mFilter = new sock_filter[mProg->len];
for (size_t i = 0; i < mProg->len; ++i) {
mFilter[i] = filterVec[i];
}
*mStored = mProg;
}
SandboxFilter::~SandboxFilter()
{
*mStored = nullptr;
delete[] mFilter;
delete mProg;
}
}

View File

@ -11,25 +11,17 @@ struct sock_fprog;
struct sock_filter;
namespace mozilla {
enum SandboxType {
kSandboxContentProcess,
kSandboxMediaPlugin
};
class SandboxFilter {
sock_filter *mFilter;
sock_fprog *mProg;
const sock_fprog **mStored;
public:
class SandboxFilter {
sock_filter *mFilter;
sock_fprog *mProg;
const sock_fprog **mStored;
public:
// RAII: on construction, builds the filter and stores it in the
// provided variable (with optional logging); on destruction, frees
// the filter and nulls out the pointer.
SandboxFilter(const sock_fprog** aStored, SandboxType aBox,
bool aVerbose = false);
~SandboxFilter();
};
} // namespace mozilla
SandboxFilter(const sock_fprog** aStored, bool aVerbose = false);
~SandboxFilter();
};
}
#endif

View File

@ -6,7 +6,7 @@
if CONFIG['LIBXUL_SDK']:
error('toolkit.mozbuild is not compatible with --enable-libxul-sdk=')
if CONFIG['MOZ_CONTENT_SANDBOX'] or CONFIG['MOZ_GMP_SANDBOX']:
if CONFIG['MOZ_CONTENT_SANDBOX'] or (CONFIG['OS_ARCH'] == 'WINNT'):
add_tier_dir('sandbox', 'security/sandbox')
# Depends on NSS and NSPR, and must be built after sandbox or else B2G emulator