Bug 920372 - Use Chromium seccomp-bpf compiler to dynamically build sandbox program. r=kang

This commit is contained in:
Jed Davis 2014-05-20 18:37:53 -07:00
parent 3b103d307f
commit 3a308504da
6 changed files with 489 additions and 164 deletions

View File

@ -47,6 +47,9 @@
#include "prlog.h" #include "prlog.h"
#include "prenv.h" #include "prenv.h"
// See definition of SandboxDie, below.
#include "sandbox/linux/seccomp-bpf/die.h"
namespace mozilla { namespace mozilla {
#if defined(ANDROID) #if defined(ANDROID)
#define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args) #define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args)
@ -206,7 +209,7 @@ InstallSyscallReporter(void)
* @see sock_fprog (the seccomp_prog). * @see sock_fprog (the seccomp_prog).
*/ */
static int static int
InstallSyscallFilter(void) InstallSyscallFilter(const sock_fprog *prog)
{ {
#ifdef MOZ_DMD #ifdef MOZ_DMD
char* e = PR_GetEnv("DMD"); char* e = PR_GetEnv("DMD");
@ -221,9 +224,7 @@ InstallSyscallFilter(void)
return 1; return 1;
} }
const sock_fprog *filter = GetSandboxFilter(); if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)prog, 0, 0)) {
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)filter, 0, 0)) {
return 1; return 1;
} }
return 0; return 0;
@ -235,6 +236,8 @@ static mozilla::Atomic<int> sSetSandboxDone;
// about:memory has the first 3 RT signals. (We should allocate // about:memory has the first 3 RT signals. (We should allocate
// signals centrally instead of hard-coding them like this.) // signals centrally instead of hard-coding them like this.)
static const int sSetSandboxSignum = SIGRTMIN + 3; static const int sSetSandboxSignum = SIGRTMIN + 3;
// Pass the filter itself through a global.
static const sock_fprog *sSetSandboxFilter;
static bool static bool
SetThreadSandbox() SetThreadSandbox()
@ -243,7 +246,7 @@ SetThreadSandbox()
if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX") == nullptr && if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX") == nullptr &&
prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) { prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
if (InstallSyscallFilter() == 0) { if (InstallSyscallFilter(sSetSandboxFilter) == 0) {
didAnything = true; didAnything = true;
} }
/* /*
@ -277,6 +280,8 @@ BroadcastSetThreadSandbox()
pid_t pid, tid; pid_t pid, tid;
DIR *taskdp; DIR *taskdp;
struct dirent *de; struct dirent *de;
SandboxFilter filter(&sSetSandboxFilter,
PR_GetEnv("MOZ_CONTENT_SANDBOX_VERBOSE"));
static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int), static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
"mozilla::Atomic<int> isn't represented by an int"); "mozilla::Atomic<int> isn't represented by an int");
@ -425,3 +430,33 @@ SetCurrentProcessSandbox()
} // namespace mozilla } // namespace mozilla
// "Polyfill" for sandbox::Die, the real version of which requires
// Chromium's logging code.
namespace sandbox {
void
Die::SandboxDie(const char* msg, const char* file, int line)
{
LOG_ERROR("%s:%d: %s\n", file, line, msg);
_exit(127);
}
} // namespace sandbox
// Stubs for unreached logging calls from Chromium CHECK() macro.
#include "base/logging.h"
namespace logging {
LogMessage::LogMessage(const char *file, int line, int)
: line_(line), file_(file)
{
MOZ_CRASH("Unexpected call to logging::LogMessage::LogMessage");
}
LogMessage::~LogMessage() {
MOZ_CRASH("Unexpected call to logging::LogMessage::~LogMessage");
}
} // namespace logging

View File

@ -0,0 +1,150 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SandboxAssembler.h"
#include "linux_seccomp.h"
#include "mozilla/NullPtr.h"
#include <errno.h>
using namespace sandbox;
namespace mozilla {
SandboxAssembler::SandboxAssembler()
{
mTail = LoadSyscall(nullptr);
mTailAlt = nullptr;
mHead = LoadArch(JmpEq(SECCOMP_ARCH, mTail, RetKill()));
}
void
SandboxAssembler::AppendCheck(Instruction *aCheck,
Instruction *aNewTail,
Instruction *aNewTailAlt)
{
mCode.JoinInstructions(mTail, aCheck);
if (mTailAlt != nullptr) {
mCode.JoinInstructions(mTailAlt, aCheck);
}
mTail = aNewTail;
mTailAlt = aNewTailAlt;
}
void
SandboxAssembler::Handle(const Condition &aCond, Instruction *aResult)
{
Instruction *checkArg, *noMatch;
if (!aCond.mCheckingArg) {
checkArg = aResult;
noMatch = nullptr;
} else {
const int8_t arg = aCond.mArgChecked;
noMatch = LoadSyscall(nullptr);
Instruction *checkArgLo = noMatch;
// Loop backwards, prepending checks onto the no-match base case.
for (size_t i = aCond.mArgValues.size(); i > 0; --i) {
checkArgLo = JmpEq(aCond.mArgValues[i - 1], aResult, checkArgLo);
}
checkArgLo = LoadArgLo(arg, checkArgLo);
checkArg = LoadArgHi(arg, JmpEq(0, checkArgLo, RetKill()));
}
Instruction *check = JmpEq(aCond.mSyscallNr, checkArg, nullptr);
AppendCheck(check, check, noMatch);
}
void
SandboxAssembler::Finish()
{
AppendCheck(RetKill(), nullptr, nullptr);
}
void
SandboxAssembler::Compile(std::vector<struct sock_filter> *aProgram,
bool aPrint)
{
mCode.Compile(mHead, aProgram);
if (aPrint) {
mCode.PrintProgram(*aProgram);
}
}
SandboxAssembler::~SandboxAssembler()
{
// The CodeGen destructor will clean up the Instruction graph.
}
Instruction *
SandboxAssembler::LoadArch(Instruction *aNext)
{
return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
SECCOMP_ARCH_IDX,
aNext);
}
Instruction *
SandboxAssembler::LoadSyscall(Instruction *aNext)
{
return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
SECCOMP_NR_IDX,
aNext);
}
Instruction *
SandboxAssembler::LoadArgHi(int aArg, Instruction *aNext)
{
return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
SECCOMP_ARG_MSB_IDX(aArg),
aNext);
}
Instruction *
SandboxAssembler::LoadArgLo(int aArg, Instruction *aNext)
{
return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
SECCOMP_ARG_LSB_IDX(aArg),
aNext);
}
Instruction *
SandboxAssembler::JmpEq(uint32_t aValue, Instruction *aThen, Instruction *aElse)
{
return mCode.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K,
aValue, aThen, aElse);
}
Instruction *
SandboxAssembler::RetAllow()
{
return mCode.MakeInstruction(BPF_RET + BPF_K,
SECCOMP_RET_ALLOW,
nullptr);
}
Instruction *
SandboxAssembler::RetDeny(int aErrno)
{
return mCode.MakeInstruction(BPF_RET + BPF_K,
SECCOMP_RET_ERRNO + aErrno,
nullptr);
}
Instruction *
SandboxAssembler::RetKill()
{
return mCode.MakeInstruction(BPF_RET + BPF_K,
#ifdef MOZ_CONTENT_SANDBOX_REPORTER
SECCOMP_RET_TRAP,
#else
SECCOMP_RET_KILL,
#endif
nullptr);
}
} // namespace mozilla

View File

@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_SandboxAssembler_h
#define mozilla_SandboxAssembler_h
#include "sandbox/linux/seccomp-bpf/codegen.h"
#include <vector>
#include "mozilla/Assertions.h"
using namespace sandbox;
namespace mozilla {
class SandboxAssembler {
public:
SandboxAssembler();
~SandboxAssembler();
class Condition {
friend class SandboxAssembler;
uint32_t mSyscallNr;
bool mCheckingArg;
uint8_t mArgChecked;
// This class retains a copy of the array, because C++11
// initializer_list isn't supported on all relevant platforms.
std::vector<uint32_t> mArgValues;
public:
// Match any instance of the given syscall, with any arguments.
explicit Condition(uint32_t aSyscallNr)
: mSyscallNr(aSyscallNr)
, mCheckingArg(false)
{ }
// Match the syscall only if the given argument is one of the
// values in the array specified. (If the argument isn't
// representable as uint32, the process is killed or signaled, as
// appropriate.)
template<size_t n>
Condition(uint32_t aSyscallNr, uint8_t aArgChecked,
const uint32_t (&aArgValues)[n])
: mSyscallNr(aSyscallNr)
, mCheckingArg(true)
, mArgChecked(aArgChecked)
, mArgValues(aArgValues, aArgValues + n)
{
MOZ_ASSERT(aArgChecked < sNumArgs);
}
};
// Allow syscalls matching this condition, if no earlier condition matched.
void Allow(const Condition &aCond) {
Handle(aCond, RetAllow());
}
// Cause syscalls matching this condition to fail with the given error, if
// no earlier condition matched.
void Deny(int aErrno, const Condition &aCond) {
Handle(aCond, RetDeny(aErrno));
}
void Finish();
void Compile(std::vector<struct sock_filter> *aProgram,
bool aPrint = false);
private:
CodeGen mCode;
// The entry point of the filter program.
Instruction *mHead;
// Pointer to an instruction with a null successor which needs to be filled
// in with the rest of the program; see CodeGen::JoinInstructions.
Instruction *mTail;
// In some cases we will have two such instructions; this, if not null, is
// that. (If we have more complicated conditions in the future, this may
// need to be generalized into a vector<Instruction*>.)
Instruction *mTailAlt;
Instruction *RetAllow();
Instruction *RetDeny(int aErrno);
Instruction *RetKill();
Instruction *LoadArch(Instruction *aNext);
Instruction *LoadSyscall(Instruction *aNext);
Instruction *LoadArgHi(int aArg, Instruction *aNext);
Instruction *LoadArgLo(int aArg, Instruction *aNext);
Instruction *JmpEq(uint32_t aValue, Instruction *aThen, Instruction *aElse);
void AppendCheck(Instruction *aCheck,
Instruction *aNewTail,
Instruction *aNewTailAlt);
void Handle(const Condition &aCond, Instruction* aResult);
static const uint8_t sNumArgs = 6;
};
}
#endif

View File

@ -5,30 +5,76 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SandboxFilter.h" #include "SandboxFilter.h"
#include "SandboxAssembler.h"
#include "linux_seccomp.h" #include "linux_seccomp.h"
#include "linux_syscalls.h" #include "linux_syscalls.h"
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/NullPtr.h"
#include <errno.h> #include <errno.h>
#include <unistd.h>
namespace mozilla { namespace mozilla {
#define SYSCALL_EXISTS(name) defined(__NR_##name) class SandboxFilterImpl : public SandboxAssembler
{
void Build();
public:
SandboxFilterImpl() {
Build();
Finish();
}
};
static struct sock_filter seccomp_filter[] = { SandboxFilter::SandboxFilter(const sock_fprog** aStored, bool aVerbose)
VALIDATE_ARCHITECTURE, : mStored(aStored)
EXAMINE_SYSCALL, {
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))
#if defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
#define ARM_SYSCALL(name) (Condition(__ARM_NR_##name))
#endif
#define SYSCALL_WITH_ARG(name, arg, values...) ({ \
uint32_t argValues[] = { values }; \
Condition(__NR_##name, arg, argValues); \
})
// Some architectures went through a transition from 32-bit to // Some architectures went through a transition from 32-bit to
// 64-bit off_t and had to version all the syscalls that referenced // 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 // it; others (newer and/or 64-bit ones) didn't. Adjust the
// conditional as needed. // conditional as needed.
#if SYSCALL_EXISTS(stat64) #if SYSCALL_EXISTS(stat64)
#define ALLOW_SYSCALL_LARGEFILE(plain, versioned) ALLOW_SYSCALL(versioned) #define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(versioned)
#else #else
#define ALLOW_SYSCALL_LARGEFILE(plain, versioned) ALLOW_SYSCALL(plain) #define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(plain)
#endif #endif
/* Most used system calls should be at the top of the whitelist /* Most used system calls should be at the top of the whitelist
@ -48,237 +94,220 @@ static struct sock_filter seccomp_filter[] = {
* 'strace -c -p <child pid>' for most used web apps. * 'strace -c -p <child pid>' for most used web apps.
*/ */
ALLOW_SYSCALL(futex), Allow(SYSCALL(futex));
// FIXME, bug 920372: i386 multiplexes all the socket-related // FIXME, bug 920372: i386 multiplexes all the socket-related
// interfaces into a single syscall. We should check the selector. // interfaces into a single syscall. We should check the selector.
#if SYSCALL_EXISTS(socketcall) #if SYSCALL_EXISTS(socketcall)
ALLOW_SYSCALL(socketcall), Allow(SYSCALL(socketcall));
#else #else
ALLOW_SYSCALL(recvmsg), Allow(SYSCALL(recvmsg));
ALLOW_SYSCALL(sendmsg), Allow(SYSCALL(sendmsg));
#endif #endif
// mmap2 is a little different from most off_t users, because it's // mmap2 is a little different from most off_t users, because it's
// passed in a register (so it's a problem for even a "new" 32-bit // passed in a register (so it's a problem for even a "new" 32-bit
// arch) -- and the workaround, mmap2, passes a page offset instead. // arch) -- and the workaround, mmap2, passes a page offset instead.
#if SYSCALL_EXISTS(mmap2) #if SYSCALL_EXISTS(mmap2)
ALLOW_SYSCALL(mmap2), Allow(SYSCALL(mmap2));
#else #else
ALLOW_SYSCALL(mmap), Allow(SYSCALL(mmap));
#endif #endif
/* B2G specific high-frequency syscalls */ /* B2G specific high-frequency syscalls */
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK
ALLOW_SYSCALL(clock_gettime), Allow(SYSCALL(clock_gettime));
ALLOW_SYSCALL(epoll_wait), Allow(SYSCALL(epoll_wait));
ALLOW_SYSCALL(gettimeofday), Allow(SYSCALL(gettimeofday));
#endif #endif
ALLOW_SYSCALL(read), Allow(SYSCALL(read));
ALLOW_SYSCALL(write), Allow(SYSCALL(write));
// 32-bit lseek is used, at least on Android, to implement ANSI fseek. // 32-bit lseek is used, at least on Android, to implement ANSI fseek.
#if SYSCALL_EXISTS(_llseek) #if SYSCALL_EXISTS(_llseek)
ALLOW_SYSCALL(_llseek), Allow(SYSCALL(_llseek));
#endif #endif
ALLOW_SYSCALL(lseek), Allow(SYSCALL(lseek));
// Android also uses 32-bit ftruncate. // Android also uses 32-bit ftruncate.
ALLOW_SYSCALL(ftruncate), Allow(SYSCALL(ftruncate));
#if SYSCALL_EXISTS(ftruncate64) #if SYSCALL_EXISTS(ftruncate64)
ALLOW_SYSCALL(ftruncate64), Allow(SYSCALL(ftruncate64));
#endif #endif
/* ioctl() is for GL. Remove when GL proxy is implemented. /* ioctl() is for GL. Remove when GL proxy is implemented.
* Additionally ioctl() might be a place where we want to have * Additionally ioctl() might be a place where we want to have
* argument filtering */ * argument filtering */
ALLOW_SYSCALL(ioctl), Allow(SYSCALL(ioctl));
ALLOW_SYSCALL(close), Allow(SYSCALL(close));
ALLOW_SYSCALL(munmap), Allow(SYSCALL(munmap));
ALLOW_SYSCALL(mprotect), Allow(SYSCALL(mprotect));
ALLOW_SYSCALL(writev), Allow(SYSCALL(writev));
ALLOW_SYSCALL(clone), Allow(SYSCALL(clone));
ALLOW_SYSCALL(brk), Allow(SYSCALL(brk));
#if SYSCALL_EXISTS(set_thread_area) #if SYSCALL_EXISTS(set_thread_area)
ALLOW_SYSCALL(set_thread_area), Allow(SYSCALL(set_thread_area));
#endif #endif
ALLOW_SYSCALL(getpid), Allow(SYSCALL(getpid));
ALLOW_SYSCALL(gettid), Allow(SYSCALL(gettid));
ALLOW_SYSCALL(getrusage), Allow(SYSCALL(getrusage));
ALLOW_SYSCALL(madvise), Allow(SYSCALL(madvise));
ALLOW_SYSCALL(dup), Allow(SYSCALL(dup));
ALLOW_SYSCALL(nanosleep), Allow(SYSCALL(nanosleep));
ALLOW_SYSCALL(poll), Allow(SYSCALL(poll));
// select()'s arguments used to be passed by pointer as a struct. // select()'s arguments used to be passed by pointer as a struct.
#if SYSCALL_EXISTS(_newselect) #if SYSCALL_EXISTS(_newselect)
ALLOW_SYSCALL(_newselect), Allow(SYSCALL(_newselect));
#else #else
ALLOW_SYSCALL(select), Allow(SYSCALL(select));
#endif #endif
// Some archs used to have 16-bit uid/gid instead of 32-bit. // Some archs used to have 16-bit uid/gid instead of 32-bit.
#if SYSCALL_EXISTS(getuid32) #if SYSCALL_EXISTS(getuid32)
ALLOW_SYSCALL(getuid32), Allow(SYSCALL(getuid32));
ALLOW_SYSCALL(geteuid32), Allow(SYSCALL(geteuid32));
#else #else
ALLOW_SYSCALL(getuid), Allow(SYSCALL(getuid));
ALLOW_SYSCALL(geteuid), Allow(SYSCALL(geteuid));
#endif #endif
// Some newer archs (e.g., x64 and x32) have only rt_sigreturn, but // Some newer archs (e.g., x64 and x32) have only rt_sigreturn, but
// ARM has and uses both syscalls -- rt_sigreturn for SA_SIGINFO // ARM has and uses both syscalls -- rt_sigreturn for SA_SIGINFO
// handlers and classic sigreturn otherwise. // handlers and classic sigreturn otherwise.
#if SYSCALL_EXISTS(sigreturn) #if SYSCALL_EXISTS(sigreturn)
ALLOW_SYSCALL(sigreturn), Allow(SYSCALL(sigreturn));
#endif #endif
ALLOW_SYSCALL(rt_sigreturn), Allow(SYSCALL(rt_sigreturn));
ALLOW_SYSCALL_LARGEFILE(fcntl, fcntl64), Allow(SYSCALL_LARGEFILE(fcntl, fcntl64));
/* Must remove all of the following in the future, when no longer used */ /* Must remove all of the following in the future, when no longer used */
/* open() is for some legacy APIs such as font loading. */ /* open() is for some legacy APIs such as font loading. */
/* See bug 906996 for removing unlink(). */ /* See bug 906996 for removing unlink(). */
ALLOW_SYSCALL_LARGEFILE(fstat, fstat64), Allow(SYSCALL_LARGEFILE(fstat, fstat64));
ALLOW_SYSCALL_LARGEFILE(stat, stat64), Allow(SYSCALL_LARGEFILE(stat, stat64));
ALLOW_SYSCALL_LARGEFILE(lstat, lstat64), Allow(SYSCALL_LARGEFILE(lstat, lstat64));
// FIXME, bug 920372: see above. // FIXME, bug 920372: see above.
#if !SYSCALL_EXISTS(socketcall) #if !SYSCALL_EXISTS(socketcall)
ALLOW_SYSCALL(socketpair), Allow(SYSCALL(socketpair));
DENY_SYSCALL(socket, EACCES), Deny(EACCES, SYSCALL(socket));
#endif #endif
ALLOW_SYSCALL(open), Allow(SYSCALL(open));
ALLOW_SYSCALL(readlink), /* Workaround for bug 964455 */ Allow(SYSCALL(readlink)); /* Workaround for bug 964455 */
ALLOW_SYSCALL(prctl), Allow(SYSCALL(prctl));
ALLOW_SYSCALL(access), Allow(SYSCALL(access));
ALLOW_SYSCALL(unlink), Allow(SYSCALL(unlink));
ALLOW_SYSCALL(fsync), Allow(SYSCALL(fsync));
ALLOW_SYSCALL(msync), Allow(SYSCALL(msync));
/* Should remove all of the following in the future, if possible */ /* Should remove all of the following in the future, if possible */
ALLOW_SYSCALL(getpriority), Allow(SYSCALL(getpriority));
ALLOW_SYSCALL(sched_get_priority_min), Allow(SYSCALL(sched_get_priority_min));
ALLOW_SYSCALL(sched_get_priority_max), Allow(SYSCALL(sched_get_priority_max));
ALLOW_SYSCALL(setpriority), Allow(SYSCALL(setpriority));
// rt_sigprocmask is passed the sigset_t size. On older archs, // rt_sigprocmask is passed the sigset_t size. On older archs,
// sigprocmask is a compatibility shim that assumes the pre-RT size. // sigprocmask is a compatibility shim that assumes the pre-RT size.
#if SYSCALL_EXISTS(sigprocmask) #if SYSCALL_EXISTS(sigprocmask)
ALLOW_SYSCALL(sigprocmask), Allow(SYSCALL(sigprocmask));
#endif #endif
ALLOW_SYSCALL(rt_sigprocmask), Allow(SYSCALL(rt_sigprocmask));
// Used by profiler. Also used for raise(), which causes problems // Used by profiler. Also used for raise(), which causes problems
// with Android KitKat abort(); see bug 1004832. // with Android KitKat abort(); see bug 1004832.
ALLOW_SYSCALL(tgkill), Allow(SYSCALL(tgkill));
/* B2G specific low-frequency syscalls */ /* B2G specific low-frequency syscalls */
#ifdef MOZ_WIDGET_GONK #ifdef MOZ_WIDGET_GONK
#if !SYSCALL_EXISTS(socketcall) #if !SYSCALL_EXISTS(socketcall)
ALLOW_SYSCALL(sendto), Allow(SYSCALL(sendto));
ALLOW_SYSCALL(recvfrom), Allow(SYSCALL(recvfrom));
#endif #endif
ALLOW_SYSCALL_LARGEFILE(getdents, getdents64), Allow(SYSCALL_LARGEFILE(getdents, getdents64));
ALLOW_SYSCALL(epoll_ctl), Allow(SYSCALL(epoll_ctl));
ALLOW_SYSCALL(sched_yield), Allow(SYSCALL(sched_yield));
ALLOW_SYSCALL(sched_getscheduler), Allow(SYSCALL(sched_getscheduler));
ALLOW_SYSCALL(sched_setscheduler), Allow(SYSCALL(sched_setscheduler));
ALLOW_SYSCALL(sigaltstack), Allow(SYSCALL(sigaltstack));
#endif #endif
/* Always last and always OK calls */ /* Always last and always OK calls */
/* Architecture-specific very infrequently used syscalls */ /* Architecture-specific very infrequently used syscalls */
#if SYSCALL_EXISTS(sigaction) #if SYSCALL_EXISTS(sigaction)
ALLOW_SYSCALL(sigaction), Allow(SYSCALL(sigaction));
#endif #endif
ALLOW_SYSCALL(rt_sigaction), Allow(SYSCALL(rt_sigaction));
#ifdef ALLOW_ARM_SYSCALL #ifdef ARM_SYSCALL
ALLOW_ARM_SYSCALL(breakpoint), Allow(ARM_SYSCALL(breakpoint));
ALLOW_ARM_SYSCALL(cacheflush), Allow(ARM_SYSCALL(cacheflush));
ALLOW_ARM_SYSCALL(usr26), Allow(ARM_SYSCALL(usr26));
ALLOW_ARM_SYSCALL(usr32), Allow(ARM_SYSCALL(usr32));
ALLOW_ARM_SYSCALL(set_tls), Allow(ARM_SYSCALL(set_tls));
#endif #endif
/* restart_syscall is called internally, generally when debugging */ /* restart_syscall is called internally, generally when debugging */
ALLOW_SYSCALL(restart_syscall), Allow(SYSCALL(restart_syscall));
/* linux desktop is not as performance critical as B2G */ /* linux desktop is not as performance critical as B2G */
/* we can place desktop syscalls at the end */ /* we can place desktop syscalls at the end */
#ifndef MOZ_WIDGET_GONK #ifndef MOZ_WIDGET_GONK
ALLOW_SYSCALL(stat), Allow(SYSCALL(stat));
ALLOW_SYSCALL(getdents), Allow(SYSCALL(getdents));
ALLOW_SYSCALL(lstat), Allow(SYSCALL(lstat));
ALLOW_SYSCALL(mmap), Allow(SYSCALL(mmap));
ALLOW_SYSCALL(openat), Allow(SYSCALL(openat));
ALLOW_SYSCALL(fcntl), Allow(SYSCALL(fcntl));
ALLOW_SYSCALL(fstat), Allow(SYSCALL(fstat));
ALLOW_SYSCALL(readlink), Allow(SYSCALL(readlink));
ALLOW_SYSCALL(getsockname), Allow(SYSCALL(getsockname));
ALLOW_SYSCALL(getuid), Allow(SYSCALL(getuid));
ALLOW_SYSCALL(geteuid), Allow(SYSCALL(geteuid));
ALLOW_SYSCALL(mkdir), Allow(SYSCALL(mkdir));
ALLOW_SYSCALL(getcwd), Allow(SYSCALL(getcwd));
ALLOW_SYSCALL(readahead), Allow(SYSCALL(readahead));
ALLOW_SYSCALL(pread64), Allow(SYSCALL(pread64));
ALLOW_SYSCALL(statfs), Allow(SYSCALL(statfs));
ALLOW_SYSCALL(pipe), Allow(SYSCALL(pipe));
ALLOW_SYSCALL(getrlimit), Allow(SYSCALL(getrlimit));
ALLOW_SYSCALL(shutdown), Allow(SYSCALL(shutdown));
ALLOW_SYSCALL(getpeername), Allow(SYSCALL(getpeername));
ALLOW_SYSCALL(eventfd2), Allow(SYSCALL(eventfd2));
ALLOW_SYSCALL(clock_getres), Allow(SYSCALL(clock_getres));
ALLOW_SYSCALL(sysinfo), Allow(SYSCALL(sysinfo));
ALLOW_SYSCALL(getresuid), Allow(SYSCALL(getresuid));
ALLOW_SYSCALL(umask), Allow(SYSCALL(umask));
ALLOW_SYSCALL(getresgid), Allow(SYSCALL(getresgid));
ALLOW_SYSCALL(poll), Allow(SYSCALL(poll));
ALLOW_SYSCALL(getegid), Allow(SYSCALL(getegid));
ALLOW_SYSCALL(inotify_init1), Allow(SYSCALL(inotify_init1));
ALLOW_SYSCALL(wait4), Allow(SYSCALL(wait4));
ALLOW_SYSCALL(shmctl), Allow(SYSCALL(shmctl));
ALLOW_SYSCALL(set_robust_list), Allow(SYSCALL(set_robust_list));
ALLOW_SYSCALL(rmdir), Allow(SYSCALL(rmdir));
ALLOW_SYSCALL(recvfrom), Allow(SYSCALL(recvfrom));
ALLOW_SYSCALL(shmdt), Allow(SYSCALL(shmdt));
ALLOW_SYSCALL(pipe2), Allow(SYSCALL(pipe2));
ALLOW_SYSCALL(setsockopt), Allow(SYSCALL(setsockopt));
ALLOW_SYSCALL(shmat), Allow(SYSCALL(shmat));
ALLOW_SYSCALL(set_tid_address), Allow(SYSCALL(set_tid_address));
ALLOW_SYSCALL(inotify_add_watch), Allow(SYSCALL(inotify_add_watch));
ALLOW_SYSCALL(rt_sigprocmask), Allow(SYSCALL(rt_sigprocmask));
ALLOW_SYSCALL(shmget), Allow(SYSCALL(shmget));
ALLOW_SYSCALL(getgid), Allow(SYSCALL(getgid));
ALLOW_SYSCALL(utime), Allow(SYSCALL(utime));
ALLOW_SYSCALL(arch_prctl), Allow(SYSCALL(arch_prctl));
ALLOW_SYSCALL(sched_getaffinity), Allow(SYSCALL(sched_getaffinity));
/* We should remove all of the following in the future (possibly even more) */ /* We should remove all of the following in the future (possibly even more) */
ALLOW_SYSCALL(socket), Allow(SYSCALL(socket));
ALLOW_SYSCALL(chmod), Allow(SYSCALL(chmod));
ALLOW_SYSCALL(execve), Allow(SYSCALL(execve));
ALLOW_SYSCALL(rename), Allow(SYSCALL(rename));
ALLOW_SYSCALL(symlink), Allow(SYSCALL(symlink));
ALLOW_SYSCALL(connect), Allow(SYSCALL(connect));
ALLOW_SYSCALL(quotactl), Allow(SYSCALL(quotactl));
ALLOW_SYSCALL(kill), Allow(SYSCALL(kill));
ALLOW_SYSCALL(sendto), Allow(SYSCALL(sendto));
#endif #endif
/* nsSystemInfo uses uname (and we cache an instance, so */ /* nsSystemInfo uses uname (and we cache an instance, so */
/* the info remains present even if we block the syscall) */ /* the info remains present even if we block the syscall) */
ALLOW_SYSCALL(uname), Allow(SYSCALL(uname));
ALLOW_SYSCALL(exit_group), Allow(SYSCALL(exit_group));
ALLOW_SYSCALL(exit), Allow(SYSCALL(exit));
#ifdef MOZ_CONTENT_SANDBOX_REPORTER
TRAP_PROCESS,
#else
KILL_PROCESS,
#endif
};
static struct sock_fprog seccomp_prog = {
(unsigned short)MOZ_ARRAY_LENGTH(seccomp_filter),
seccomp_filter,
};
const sock_fprog*
GetSandboxFilter()
{
return &seccomp_prog;
} }
} }

View File

@ -8,11 +8,20 @@
#define mozilla_SandboxFilter_h #define mozilla_SandboxFilter_h
struct sock_fprog; struct sock_fprog;
struct sock_filter;
namespace mozilla { namespace mozilla {
class SandboxFilter {
const sock_fprog* GetSandboxFilter(); 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, bool aVerbose = false);
~SandboxFilter();
};
} }
#endif #endif

View File

@ -11,10 +11,15 @@ EXPORTS.mozilla += [
] ]
SOURCES += [ SOURCES += [
'../chromium/sandbox/linux/seccomp-bpf/basicblock.cc',
'../chromium/sandbox/linux/seccomp-bpf/codegen.cc',
'Sandbox.cpp', 'Sandbox.cpp',
'SandboxAssembler.cpp',
'SandboxFilter.cpp', 'SandboxFilter.cpp',
] ]
LOCAL_INCLUDES += ['/security/sandbox/chromium']
include('/ipc/chromium/chromium-config.mozbuild') include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul' FINAL_LIBRARY = 'xul'