From ebb89f61f4445ea6a6b3b94c5f2584ba6f4ac124 Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 20 May 2014 18:37:53 -0700 Subject: [PATCH] Bug 920372 - Use Chromium seccomp-bpf compiler to dynamically build sandbox program. r=kang --- security/sandbox/linux/Sandbox.cpp | 45 ++- security/sandbox/linux/SandboxAssembler.cpp | 150 +++++++++ security/sandbox/linux/SandboxAssembler.h | 97 ++++++ security/sandbox/linux/SandboxFilter.cpp | 341 +++++++++++--------- security/sandbox/linux/SandboxFilter.h | 15 +- security/sandbox/linux/moz.build | 5 + 6 files changed, 489 insertions(+), 164 deletions(-) create mode 100644 security/sandbox/linux/SandboxAssembler.cpp create mode 100644 security/sandbox/linux/SandboxAssembler.h diff --git a/security/sandbox/linux/Sandbox.cpp b/security/sandbox/linux/Sandbox.cpp index c88027f20518..1b60e549362c 100644 --- a/security/sandbox/linux/Sandbox.cpp +++ b/security/sandbox/linux/Sandbox.cpp @@ -47,6 +47,9 @@ #include "prlog.h" #include "prenv.h" +// See definition of SandboxDie, below. +#include "sandbox/linux/seccomp-bpf/die.h" + namespace mozilla { #if defined(ANDROID) #define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args) @@ -206,7 +209,7 @@ InstallSyscallReporter(void) * @see sock_fprog (the seccomp_prog). */ static int -InstallSyscallFilter(void) +InstallSyscallFilter(const sock_fprog *prog) { #ifdef MOZ_DMD char* e = PR_GetEnv("DMD"); @@ -221,9 +224,7 @@ InstallSyscallFilter(void) return 1; } - const sock_fprog *filter = GetSandboxFilter(); - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)filter, 0, 0)) { + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)prog, 0, 0)) { return 1; } return 0; @@ -235,6 +236,8 @@ static mozilla::Atomic sSetSandboxDone; // about:memory has the first 3 RT signals. (We should allocate // signals centrally instead of hard-coding them like this.) static const int sSetSandboxSignum = SIGRTMIN + 3; +// Pass the filter itself through a global. +static const sock_fprog *sSetSandboxFilter; static bool SetThreadSandbox() @@ -243,7 +246,7 @@ SetThreadSandbox() if (PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX") == nullptr && prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) { - if (InstallSyscallFilter() == 0) { + if (InstallSyscallFilter(sSetSandboxFilter) == 0) { didAnything = true; } /* @@ -277,6 +280,8 @@ BroadcastSetThreadSandbox() pid_t pid, tid; DIR *taskdp; struct dirent *de; + SandboxFilter filter(&sSetSandboxFilter, + PR_GetEnv("MOZ_CONTENT_SANDBOX_VERBOSE")); static_assert(sizeof(mozilla::Atomic) == sizeof(int), "mozilla::Atomic isn't represented by an int"); @@ -425,3 +430,33 @@ SetCurrentProcessSandbox() } // 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 diff --git a/security/sandbox/linux/SandboxAssembler.cpp b/security/sandbox/linux/SandboxAssembler.cpp new file mode 100644 index 000000000000..a2b63d93c12f --- /dev/null +++ b/security/sandbox/linux/SandboxAssembler.cpp @@ -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 + +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 *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 diff --git a/security/sandbox/linux/SandboxAssembler.h b/security/sandbox/linux/SandboxAssembler.h new file mode 100644 index 000000000000..0cf77512e247 --- /dev/null +++ b/security/sandbox/linux/SandboxAssembler.h @@ -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 +#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 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 + 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 *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 *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 diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp index 03f6304f9c51..e195d7b6409c 100644 --- a/security/sandbox/linux/SandboxFilter.cpp +++ b/security/sandbox/linux/SandboxFilter.cpp @@ -5,30 +5,76 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SandboxFilter.h" +#include "SandboxAssembler.h" #include "linux_seccomp.h" #include "linux_syscalls.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/NullPtr.h" #include +#include 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[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL, +SandboxFilter::SandboxFilter(const sock_fprog** aStored, bool aVerbose) + : mStored(aStored) +{ + MOZ_ASSERT(*mStored == nullptr); + std::vector 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 // 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 ALLOW_SYSCALL_LARGEFILE(plain, versioned) ALLOW_SYSCALL(versioned) +#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(versioned) #else -#define ALLOW_SYSCALL_LARGEFILE(plain, versioned) ALLOW_SYSCALL(plain) +#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(plain) #endif /* 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 ' for most used web apps. */ - ALLOW_SYSCALL(futex), + Allow(SYSCALL(futex)); // FIXME, bug 920372: i386 multiplexes all the socket-related // interfaces into a single syscall. We should check the selector. #if SYSCALL_EXISTS(socketcall) - ALLOW_SYSCALL(socketcall), + Allow(SYSCALL(socketcall)); #else - ALLOW_SYSCALL(recvmsg), - ALLOW_SYSCALL(sendmsg), + Allow(SYSCALL(recvmsg)); + Allow(SYSCALL(sendmsg)); #endif // 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 // arch) -- and the workaround, mmap2, passes a page offset instead. #if SYSCALL_EXISTS(mmap2) - ALLOW_SYSCALL(mmap2), + Allow(SYSCALL(mmap2)); #else - ALLOW_SYSCALL(mmap), + Allow(SYSCALL(mmap)); #endif /* B2G specific high-frequency syscalls */ #ifdef MOZ_WIDGET_GONK - ALLOW_SYSCALL(clock_gettime), - ALLOW_SYSCALL(epoll_wait), - ALLOW_SYSCALL(gettimeofday), + Allow(SYSCALL(clock_gettime)); + Allow(SYSCALL(epoll_wait)); + Allow(SYSCALL(gettimeofday)); #endif - ALLOW_SYSCALL(read), - ALLOW_SYSCALL(write), + Allow(SYSCALL(read)); + Allow(SYSCALL(write)); // 32-bit lseek is used, at least on Android, to implement ANSI fseek. #if SYSCALL_EXISTS(_llseek) - ALLOW_SYSCALL(_llseek), + Allow(SYSCALL(_llseek)); #endif - ALLOW_SYSCALL(lseek), + Allow(SYSCALL(lseek)); // Android also uses 32-bit ftruncate. - ALLOW_SYSCALL(ftruncate), + Allow(SYSCALL(ftruncate)); #if SYSCALL_EXISTS(ftruncate64) - ALLOW_SYSCALL(ftruncate64), + Allow(SYSCALL(ftruncate64)); #endif /* ioctl() is for GL. Remove when GL proxy is implemented. * Additionally ioctl() might be a place where we want to have * argument filtering */ - ALLOW_SYSCALL(ioctl), - ALLOW_SYSCALL(close), - ALLOW_SYSCALL(munmap), - ALLOW_SYSCALL(mprotect), - ALLOW_SYSCALL(writev), - ALLOW_SYSCALL(clone), - ALLOW_SYSCALL(brk), + Allow(SYSCALL(ioctl)); + Allow(SYSCALL(close)); + Allow(SYSCALL(munmap)); + Allow(SYSCALL(mprotect)); + Allow(SYSCALL(writev)); + Allow(SYSCALL(clone)); + Allow(SYSCALL(brk)); #if SYSCALL_EXISTS(set_thread_area) - ALLOW_SYSCALL(set_thread_area), + Allow(SYSCALL(set_thread_area)); #endif - ALLOW_SYSCALL(getpid), - ALLOW_SYSCALL(gettid), - ALLOW_SYSCALL(getrusage), - ALLOW_SYSCALL(madvise), - ALLOW_SYSCALL(dup), - ALLOW_SYSCALL(nanosleep), - ALLOW_SYSCALL(poll), + Allow(SYSCALL(getpid)); + Allow(SYSCALL(gettid)); + Allow(SYSCALL(getrusage)); + Allow(SYSCALL(madvise)); + Allow(SYSCALL(dup)); + Allow(SYSCALL(nanosleep)); + Allow(SYSCALL(poll)); // select()'s arguments used to be passed by pointer as a struct. #if SYSCALL_EXISTS(_newselect) - ALLOW_SYSCALL(_newselect), + Allow(SYSCALL(_newselect)); #else - ALLOW_SYSCALL(select), + Allow(SYSCALL(select)); #endif // Some archs used to have 16-bit uid/gid instead of 32-bit. #if SYSCALL_EXISTS(getuid32) - ALLOW_SYSCALL(getuid32), - ALLOW_SYSCALL(geteuid32), + Allow(SYSCALL(getuid32)); + Allow(SYSCALL(geteuid32)); #else - ALLOW_SYSCALL(getuid), - ALLOW_SYSCALL(geteuid), + Allow(SYSCALL(getuid)); + Allow(SYSCALL(geteuid)); #endif // Some newer archs (e.g., x64 and x32) have only rt_sigreturn, but // ARM has and uses both syscalls -- rt_sigreturn for SA_SIGINFO // handlers and classic sigreturn otherwise. #if SYSCALL_EXISTS(sigreturn) - ALLOW_SYSCALL(sigreturn), + Allow(SYSCALL(sigreturn)); #endif - ALLOW_SYSCALL(rt_sigreturn), - ALLOW_SYSCALL_LARGEFILE(fcntl, fcntl64), + Allow(SYSCALL(rt_sigreturn)); + Allow(SYSCALL_LARGEFILE(fcntl, fcntl64)); /* Must remove all of the following in the future, when no longer used */ /* open() is for some legacy APIs such as font loading. */ /* See bug 906996 for removing unlink(). */ - ALLOW_SYSCALL_LARGEFILE(fstat, fstat64), - ALLOW_SYSCALL_LARGEFILE(stat, stat64), - ALLOW_SYSCALL_LARGEFILE(lstat, lstat64), + Allow(SYSCALL_LARGEFILE(fstat, fstat64)); + Allow(SYSCALL_LARGEFILE(stat, stat64)); + Allow(SYSCALL_LARGEFILE(lstat, lstat64)); // FIXME, bug 920372: see above. #if !SYSCALL_EXISTS(socketcall) - ALLOW_SYSCALL(socketpair), - DENY_SYSCALL(socket, EACCES), + Allow(SYSCALL(socketpair)); + Deny(EACCES, SYSCALL(socket)); #endif - ALLOW_SYSCALL(open), - ALLOW_SYSCALL(readlink), /* Workaround for bug 964455 */ - ALLOW_SYSCALL(prctl), - ALLOW_SYSCALL(access), - ALLOW_SYSCALL(unlink), - ALLOW_SYSCALL(fsync), - ALLOW_SYSCALL(msync), + Allow(SYSCALL(open)); + Allow(SYSCALL(readlink)); /* Workaround for bug 964455 */ + Allow(SYSCALL(prctl)); + Allow(SYSCALL(access)); + Allow(SYSCALL(unlink)); + Allow(SYSCALL(fsync)); + Allow(SYSCALL(msync)); /* Should remove all of the following in the future, if possible */ - ALLOW_SYSCALL(getpriority), - ALLOW_SYSCALL(sched_get_priority_min), - ALLOW_SYSCALL(sched_get_priority_max), - ALLOW_SYSCALL(setpriority), + Allow(SYSCALL(getpriority)); + Allow(SYSCALL(sched_get_priority_min)); + Allow(SYSCALL(sched_get_priority_max)); + Allow(SYSCALL(setpriority)); // rt_sigprocmask is passed the sigset_t size. On older archs, // sigprocmask is a compatibility shim that assumes the pre-RT size. #if SYSCALL_EXISTS(sigprocmask) - ALLOW_SYSCALL(sigprocmask), + Allow(SYSCALL(sigprocmask)); #endif - ALLOW_SYSCALL(rt_sigprocmask), + Allow(SYSCALL(rt_sigprocmask)); // Used by profiler. Also used for raise(), which causes problems // with Android KitKat abort(); see bug 1004832. - ALLOW_SYSCALL(tgkill), + Allow(SYSCALL(tgkill)); /* B2G specific low-frequency syscalls */ #ifdef MOZ_WIDGET_GONK #if !SYSCALL_EXISTS(socketcall) - ALLOW_SYSCALL(sendto), - ALLOW_SYSCALL(recvfrom), + Allow(SYSCALL(sendto)); + Allow(SYSCALL(recvfrom)); #endif - ALLOW_SYSCALL_LARGEFILE(getdents, getdents64), - ALLOW_SYSCALL(epoll_ctl), - ALLOW_SYSCALL(sched_yield), - ALLOW_SYSCALL(sched_getscheduler), - ALLOW_SYSCALL(sched_setscheduler), - ALLOW_SYSCALL(sigaltstack), + Allow(SYSCALL_LARGEFILE(getdents, getdents64)); + Allow(SYSCALL(epoll_ctl)); + Allow(SYSCALL(sched_yield)); + Allow(SYSCALL(sched_getscheduler)); + Allow(SYSCALL(sched_setscheduler)); + Allow(SYSCALL(sigaltstack)); #endif /* Always last and always OK calls */ /* Architecture-specific very infrequently used syscalls */ #if SYSCALL_EXISTS(sigaction) - ALLOW_SYSCALL(sigaction), + Allow(SYSCALL(sigaction)); #endif - ALLOW_SYSCALL(rt_sigaction), -#ifdef ALLOW_ARM_SYSCALL - ALLOW_ARM_SYSCALL(breakpoint), - ALLOW_ARM_SYSCALL(cacheflush), - ALLOW_ARM_SYSCALL(usr26), - ALLOW_ARM_SYSCALL(usr32), - ALLOW_ARM_SYSCALL(set_tls), + Allow(SYSCALL(rt_sigaction)); +#ifdef ARM_SYSCALL + Allow(ARM_SYSCALL(breakpoint)); + Allow(ARM_SYSCALL(cacheflush)); + Allow(ARM_SYSCALL(usr26)); + Allow(ARM_SYSCALL(usr32)); + Allow(ARM_SYSCALL(set_tls)); #endif /* 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 */ /* we can place desktop syscalls at the end */ #ifndef MOZ_WIDGET_GONK - ALLOW_SYSCALL(stat), - ALLOW_SYSCALL(getdents), - ALLOW_SYSCALL(lstat), - ALLOW_SYSCALL(mmap), - ALLOW_SYSCALL(openat), - ALLOW_SYSCALL(fcntl), - ALLOW_SYSCALL(fstat), - ALLOW_SYSCALL(readlink), - ALLOW_SYSCALL(getsockname), - ALLOW_SYSCALL(getuid), - ALLOW_SYSCALL(geteuid), - ALLOW_SYSCALL(mkdir), - ALLOW_SYSCALL(getcwd), - ALLOW_SYSCALL(readahead), - ALLOW_SYSCALL(pread64), - ALLOW_SYSCALL(statfs), - ALLOW_SYSCALL(pipe), - ALLOW_SYSCALL(getrlimit), - ALLOW_SYSCALL(shutdown), - ALLOW_SYSCALL(getpeername), - ALLOW_SYSCALL(eventfd2), - ALLOW_SYSCALL(clock_getres), - ALLOW_SYSCALL(sysinfo), - ALLOW_SYSCALL(getresuid), - ALLOW_SYSCALL(umask), - ALLOW_SYSCALL(getresgid), - ALLOW_SYSCALL(poll), - ALLOW_SYSCALL(getegid), - ALLOW_SYSCALL(inotify_init1), - ALLOW_SYSCALL(wait4), - ALLOW_SYSCALL(shmctl), - ALLOW_SYSCALL(set_robust_list), - ALLOW_SYSCALL(rmdir), - ALLOW_SYSCALL(recvfrom), - ALLOW_SYSCALL(shmdt), - ALLOW_SYSCALL(pipe2), - ALLOW_SYSCALL(setsockopt), - ALLOW_SYSCALL(shmat), - ALLOW_SYSCALL(set_tid_address), - ALLOW_SYSCALL(inotify_add_watch), - ALLOW_SYSCALL(rt_sigprocmask), - ALLOW_SYSCALL(shmget), - ALLOW_SYSCALL(getgid), - ALLOW_SYSCALL(utime), - ALLOW_SYSCALL(arch_prctl), - ALLOW_SYSCALL(sched_getaffinity), + Allow(SYSCALL(stat)); + Allow(SYSCALL(getdents)); + Allow(SYSCALL(lstat)); + Allow(SYSCALL(mmap)); + Allow(SYSCALL(openat)); + Allow(SYSCALL(fcntl)); + Allow(SYSCALL(fstat)); + Allow(SYSCALL(readlink)); + Allow(SYSCALL(getsockname)); + Allow(SYSCALL(getuid)); + Allow(SYSCALL(geteuid)); + Allow(SYSCALL(mkdir)); + Allow(SYSCALL(getcwd)); + Allow(SYSCALL(readahead)); + Allow(SYSCALL(pread64)); + Allow(SYSCALL(statfs)); + Allow(SYSCALL(pipe)); + Allow(SYSCALL(getrlimit)); + Allow(SYSCALL(shutdown)); + Allow(SYSCALL(getpeername)); + Allow(SYSCALL(eventfd2)); + Allow(SYSCALL(clock_getres)); + Allow(SYSCALL(sysinfo)); + Allow(SYSCALL(getresuid)); + Allow(SYSCALL(umask)); + Allow(SYSCALL(getresgid)); + Allow(SYSCALL(poll)); + Allow(SYSCALL(getegid)); + Allow(SYSCALL(inotify_init1)); + Allow(SYSCALL(wait4)); + Allow(SYSCALL(shmctl)); + Allow(SYSCALL(set_robust_list)); + Allow(SYSCALL(rmdir)); + Allow(SYSCALL(recvfrom)); + Allow(SYSCALL(shmdt)); + Allow(SYSCALL(pipe2)); + Allow(SYSCALL(setsockopt)); + Allow(SYSCALL(shmat)); + Allow(SYSCALL(set_tid_address)); + Allow(SYSCALL(inotify_add_watch)); + Allow(SYSCALL(rt_sigprocmask)); + Allow(SYSCALL(shmget)); + Allow(SYSCALL(getgid)); + Allow(SYSCALL(utime)); + Allow(SYSCALL(arch_prctl)); + Allow(SYSCALL(sched_getaffinity)); /* We should remove all of the following in the future (possibly even more) */ - ALLOW_SYSCALL(socket), - ALLOW_SYSCALL(chmod), - ALLOW_SYSCALL(execve), - ALLOW_SYSCALL(rename), - ALLOW_SYSCALL(symlink), - ALLOW_SYSCALL(connect), - ALLOW_SYSCALL(quotactl), - ALLOW_SYSCALL(kill), - ALLOW_SYSCALL(sendto), + Allow(SYSCALL(socket)); + Allow(SYSCALL(chmod)); + Allow(SYSCALL(execve)); + Allow(SYSCALL(rename)); + Allow(SYSCALL(symlink)); + Allow(SYSCALL(connect)); + Allow(SYSCALL(quotactl)); + Allow(SYSCALL(kill)); + Allow(SYSCALL(sendto)); #endif /* nsSystemInfo uses uname (and we cache an instance, so */ /* the info remains present even if we block the syscall) */ - ALLOW_SYSCALL(uname), - ALLOW_SYSCALL(exit_group), - 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; + Allow(SYSCALL(uname)); + Allow(SYSCALL(exit_group)); + Allow(SYSCALL(exit)); } } diff --git a/security/sandbox/linux/SandboxFilter.h b/security/sandbox/linux/SandboxFilter.h index 9fd7f9507039..a00dea2cf4b1 100644 --- a/security/sandbox/linux/SandboxFilter.h +++ b/security/sandbox/linux/SandboxFilter.h @@ -8,11 +8,20 @@ #define mozilla_SandboxFilter_h struct sock_fprog; +struct sock_filter; namespace mozilla { - -const sock_fprog* GetSandboxFilter(); - + 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, bool aVerbose = false); + ~SandboxFilter(); + }; } #endif diff --git a/security/sandbox/linux/moz.build b/security/sandbox/linux/moz.build index c52ad545fe6d..ae9da080d9fb 100644 --- a/security/sandbox/linux/moz.build +++ b/security/sandbox/linux/moz.build @@ -11,10 +11,15 @@ EXPORTS.mozilla += [ ] SOURCES += [ + '../chromium/sandbox/linux/seccomp-bpf/basicblock.cc', + '../chromium/sandbox/linux/seccomp-bpf/codegen.cc', 'Sandbox.cpp', + 'SandboxAssembler.cpp', 'SandboxFilter.cpp', ] +LOCAL_INCLUDES += ['/security/sandbox/chromium'] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul'