summaryrefslogtreecommitdiffstats
path: root/security/sandbox/linux
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-05-03 05:55:15 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-05-03 05:55:15 +0200
commit43f7a588f96aaf88e7b69441c3b50bc9c7b20df7 (patch)
tree07d9b26b2f357ee9de04fea0e5e4b8b9a1ff93a4 /security/sandbox/linux
parent4613b91ecac2745252c40be64e73de5ff920b02b (diff)
downloadUXP-43f7a588f96aaf88e7b69441c3b50bc9c7b20df7.tar
UXP-43f7a588f96aaf88e7b69441c3b50bc9c7b20df7.tar.gz
UXP-43f7a588f96aaf88e7b69441c3b50bc9c7b20df7.tar.lz
UXP-43f7a588f96aaf88e7b69441c3b50bc9c7b20df7.tar.xz
UXP-43f7a588f96aaf88e7b69441c3b50bc9c7b20df7.zip
Nuke the sandbox
Diffstat (limited to 'security/sandbox/linux')
-rw-r--r--security/sandbox/linux/LinuxCapabilities.cpp28
-rw-r--r--security/sandbox/linux/LinuxCapabilities.h128
-rw-r--r--security/sandbox/linux/LinuxSched.h35
-rw-r--r--security/sandbox/linux/Sandbox.cpp609
-rw-r--r--security/sandbox/linux/Sandbox.h24
-rw-r--r--security/sandbox/linux/SandboxBrokerClient.cpp247
-rw-r--r--security/sandbox/linux/SandboxBrokerClient.h58
-rw-r--r--security/sandbox/linux/SandboxChroot.cpp212
-rw-r--r--security/sandbox/linux/SandboxChroot.h66
-rw-r--r--security/sandbox/linux/SandboxFilter.cpp343
-rw-r--r--security/sandbox/linux/SandboxFilter.h23
-rw-r--r--security/sandbox/linux/SandboxFilterUtil.cpp121
-rw-r--r--security/sandbox/linux/SandboxFilterUtil.h148
-rw-r--r--security/sandbox/linux/SandboxHooks.cpp72
-rw-r--r--security/sandbox/linux/SandboxInfo.cpp259
-rw-r--r--security/sandbox/linux/SandboxInfo.h81
-rw-r--r--security/sandbox/linux/SandboxInternal.h28
-rw-r--r--security/sandbox/linux/SandboxLogging.cpp60
-rw-r--r--security/sandbox/linux/SandboxLogging.h52
-rw-r--r--security/sandbox/linux/SandboxUtil.cpp106
-rw-r--r--security/sandbox/linux/SandboxUtil.h21
-rw-r--r--security/sandbox/linux/broker/SandboxBroker.cpp731
-rw-r--r--security/sandbox/linux/broker/SandboxBroker.h132
-rw-r--r--security/sandbox/linux/broker/SandboxBrokerCommon.cpp120
-rw-r--r--security/sandbox/linux/broker/SandboxBrokerCommon.h72
-rw-r--r--security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp50
-rw-r--r--security/sandbox/linux/broker/SandboxBrokerPolicyFactory.h28
-rw-r--r--security/sandbox/linux/broker/SandboxBrokerUtils.h30
-rw-r--r--security/sandbox/linux/broker/moz.build37
-rw-r--r--security/sandbox/linux/glue/SandboxCrash.cpp131
-rw-r--r--security/sandbox/linux/glue/moz.build29
-rw-r--r--security/sandbox/linux/gtest/TestBroker.cpp626
-rw-r--r--security/sandbox/linux/gtest/TestBrokerPolicy.cpp98
-rw-r--r--security/sandbox/linux/gtest/TestSandboxUtil.cpp44
-rw-r--r--security/sandbox/linux/gtest/moz.build27
-rw-r--r--security/sandbox/linux/moz.build116
36 files changed, 0 insertions, 4992 deletions
diff --git a/security/sandbox/linux/LinuxCapabilities.cpp b/security/sandbox/linux/LinuxCapabilities.cpp
deleted file mode 100644
index 87e24a009..000000000
--- a/security/sandbox/linux/LinuxCapabilities.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- 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 "LinuxCapabilities.h"
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-namespace mozilla {
-
-bool
-LinuxCapabilities::GetCurrent() {
- __user_cap_header_struct header = { _LINUX_CAPABILITY_VERSION_3, 0 };
- return syscall(__NR_capget, &header, &mBits) == 0
- && header.version == _LINUX_CAPABILITY_VERSION_3;
-}
-
-bool
-LinuxCapabilities::SetCurrentRaw() const {
- __user_cap_header_struct header = { _LINUX_CAPABILITY_VERSION_3, 0 };
- return syscall(__NR_capset, &header, &mBits) == 0
- && header.version == _LINUX_CAPABILITY_VERSION_3;
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/LinuxCapabilities.h b/security/sandbox/linux/LinuxCapabilities.h
deleted file mode 100644
index 9d3220841..000000000
--- a/security/sandbox/linux/LinuxCapabilities.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- 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_LinuxCapabilities_h
-#define mozilla_LinuxCapabilities_h
-
-#include <linux/capability.h>
-#include <stdint.h>
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/PodOperations.h"
-
-// This class is a relatively simple interface to manipulating the
-// capabilities of a Linux process/thread; see the capabilities(7) man
-// page for background information.
-
-// Unfortunately, Android's kernel headers omit some definitions
-// needed for the low-level capability interface. They're part of the
-// stable syscall ABI, so it's safe to include them here.
-#ifndef _LINUX_CAPABILITY_VERSION_3
-#define _LINUX_CAPABILITY_VERSION_3 0x20080522
-#define _LINUX_CAPABILITY_U32S_3 2
-#endif
-#ifndef CAP_TO_INDEX
-#define CAP_TO_INDEX(x) ((x) >> 5)
-#define CAP_TO_MASK(x) (1 << ((x) & 31))
-#endif
-
-namespace mozilla {
-
-class LinuxCapabilities final
-{
-public:
- // A class to represent a bit within the capability sets as an lvalue.
- class BitRef {
- __u32& mWord;
- __u32 mMask;
- friend class LinuxCapabilities;
- BitRef(__u32& aWord, uint32_t aMask) : mWord(aWord), mMask(aMask) { }
- BitRef(const BitRef& aBit) : mWord(aBit.mWord), mMask(aBit.mMask) { }
- public:
- MOZ_IMPLICIT operator bool() const {
- return mWord & mMask;
- }
- BitRef& operator=(bool aSetTo) {
- if (aSetTo) {
- mWord |= mMask;
- } else {
- mWord &= mMask;
- }
- return *this;
- }
- };
-
- // The default value is the empty set.
- LinuxCapabilities() { PodArrayZero(mBits); }
-
- // Get the current thread's capability sets and assign them to this
- // object. Returns whether it succeeded and sets errno on failure.
- // Shouldn't fail unless the kernel is very old.
- bool GetCurrent();
-
- // Try to set the current thread's capability sets to those
- // specified in this object. Returns whether it succeeded and sets
- // errno on failure.
- bool SetCurrentRaw() const;
-
- // The capability model requires that the permitted set always be a
- // superset of the effective and inheritable sets. This method
- // expands the permitted set as needed and then sets the current
- // thread's capabilities, as described above.
- bool SetCurrent() {
- Normalize();
- return SetCurrentRaw();
- }
-
- void Normalize() {
- for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; ++i) {
- mBits[i].permitted |= mBits[i].effective | mBits[i].inheritable;
- }
- }
-
- bool AnyEffective() const {
- for (size_t i = 0; i < _LINUX_CAPABILITY_U32S_3; ++i) {
- if (mBits[i].effective != 0) {
- return true;
- }
- }
- return false;
- }
-
- // These three methods expose individual bits in the three
- // capability sets as objects that can be used as bool lvalues.
- // The argument is the capability number, as defined in
- // the <linux/capability.h> header.
- BitRef Effective(unsigned aCap)
- {
- return GenericBitRef(&__user_cap_data_struct::effective, aCap);
- }
-
- BitRef Permitted(unsigned aCap)
- {
- return GenericBitRef(&__user_cap_data_struct::permitted, aCap);
- }
-
- BitRef Inheritable(unsigned aCap)
- {
- return GenericBitRef(&__user_cap_data_struct::inheritable, aCap);
- }
-
-private:
- __user_cap_data_struct mBits[_LINUX_CAPABILITY_U32S_3];
-
- BitRef GenericBitRef(__u32 __user_cap_data_struct::* aField, unsigned aCap)
- {
- // Please don't pass untrusted data as the capability number.
- MOZ_ASSERT(CAP_TO_INDEX(aCap) < _LINUX_CAPABILITY_U32S_3);
- return BitRef(mBits[CAP_TO_INDEX(aCap)].*aField, CAP_TO_MASK(aCap));
- }
-};
-
-} // namespace mozilla
-
-#endif // mozilla_LinuxCapabilities_h
diff --git a/security/sandbox/linux/LinuxSched.h b/security/sandbox/linux/LinuxSched.h
deleted file mode 100644
index 148067d34..000000000
--- a/security/sandbox/linux/LinuxSched.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- 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_LinuxSched_h
-#define mozilla_LinuxSched_h
-
-#include <linux/sched.h>
-
-// Some build environments, in particular the Android NDK, don't
-// define some of the newer clone/unshare flags ("newer" relatively
-// speaking; CLONE_NEWUTS is present since kernel 2.6.19 in 2006).
-
-#ifndef CLONE_NEWUTS
-#define CLONE_NEWUTS 0x04000000
-#endif
-#ifndef CLONE_NEWIPC
-#define CLONE_NEWIPC 0x08000000
-#endif
-#ifndef CLONE_NEWUSER
-#define CLONE_NEWUSER 0x10000000
-#endif
-#ifndef CLONE_NEWPID
-#define CLONE_NEWPID 0x20000000
-#endif
-#ifndef CLONE_NEWNET
-#define CLONE_NEWNET 0x40000000
-#endif
-#ifndef CLONE_IO
-#define CLONE_IO 0x80000000
-#endif
-
-#endif
diff --git a/security/sandbox/linux/Sandbox.cpp b/security/sandbox/linux/Sandbox.cpp
deleted file mode 100644
index 80a18f855..000000000
--- a/security/sandbox/linux/Sandbox.cpp
+++ /dev/null
@@ -1,609 +0,0 @@
-/* -*- 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 "Sandbox.h"
-
-#include "LinuxCapabilities.h"
-#include "LinuxSched.h"
-#include "SandboxBrokerClient.h"
-#include "SandboxChroot.h"
-#include "SandboxFilter.h"
-#include "SandboxInternal.h"
-#include "SandboxLogging.h"
-#include "SandboxUtil.h"
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/futex.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/ptrace.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#include "mozilla/Atomics.h"
-#include "mozilla/Maybe.h"
-#include "mozilla/SandboxInfo.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/Unused.h"
-#include "sandbox/linux/bpf_dsl/codegen.h"
-#include "sandbox/linux/bpf_dsl/dump_bpf.h"
-#include "sandbox/linux/bpf_dsl/policy.h"
-#include "sandbox/linux/bpf_dsl/policy_compiler.h"
-#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
-#include "sandbox/linux/seccomp-bpf/trap.h"
-#include "sandbox/linux/system_headers/linux_filter.h"
-#include "sandbox/linux/system_headers/linux_seccomp.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-#if defined(ANDROID)
-#include "sandbox/linux/system_headers/linux_ucontext.h"
-#endif
-
-#ifdef MOZ_ASAN
-// Copy libsanitizer declarations to avoid depending on ASAN headers.
-// See also bug 1081242 comment #4.
-extern "C" {
-namespace __sanitizer {
-// Win64 uses long long, but this is Linux.
-typedef signed long sptr;
-} // namespace __sanitizer
-
-typedef struct {
- int coverage_sandboxed;
- __sanitizer::sptr coverage_fd;
- unsigned int coverage_max_block_size;
-} __sanitizer_sandbox_arguments;
-
-MOZ_IMPORT_API void
-__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
-} // extern "C"
-#endif // MOZ_ASAN
-
-// Signal number used to enable seccomp on each thread.
-int gSeccompTsyncBroadcastSignum = 0;
-
-namespace mozilla {
-
-// This is initialized by SandboxSetCrashFunc().
-SandboxCrashFunc gSandboxCrashFunc;
-
-static UniquePtr<SandboxChroot> gChrootHelper;
-static void (*gChromiumSigSysHandler)(int, siginfo_t*, void*);
-
-// Test whether a ucontext, interpreted as the state after a syscall,
-// indicates the given error. See also sandbox::Syscall::PutValueInUcontext.
-static bool
-ContextIsError(const ucontext_t *aContext, int aError)
-{
- // Avoid integer promotion warnings. (The unary addition makes
- // the decltype not evaluate to a reference type.)
- typedef decltype(+SECCOMP_RESULT(aContext)) reg_t;
-
-#ifdef __mips__
- return SECCOMP_PARM4(aContext) != 0
- && SECCOMP_RESULT(aContext) == static_cast<reg_t>(aError);
-#else
- return SECCOMP_RESULT(aContext) == static_cast<reg_t>(-aError);
-#endif
-}
-
-/**
- * This is the SIGSYS handler function. It delegates to the Chromium
- * TrapRegistry handler (see InstallSigSysHandler, below) and, if the
- * trap handler installed by the policy would fail with ENOSYS,
- * crashes the process. This allows unintentional policy failures to
- * be reported as crash dumps and fixed. It also logs information
- * about the failed system call.
- *
- * Note that this could be invoked in parallel on multiple threads and
- * that it could be in async signal context (e.g., intercepting an
- * open() called from an async signal handler).
- */
-static void
-SigSysHandler(int nr, siginfo_t *info, void *void_context)
-{
- ucontext_t *ctx = static_cast<ucontext_t*>(void_context);
- // This shouldn't ever be null, but the Chromium handler checks for
- // that and refrains from crashing, so let's not crash release builds:
- MOZ_DIAGNOSTIC_ASSERT(ctx);
- if (!ctx) {
- return;
- }
-
- // Save a copy of the context before invoking the trap handler,
- // which will overwrite one or more registers with the return value.
- ucontext_t savedCtx = *ctx;
-
- gChromiumSigSysHandler(nr, info, ctx);
- if (!ContextIsError(ctx, ENOSYS)) {
- return;
- }
-
- pid_t pid = getpid();
- unsigned long syscall_nr = SECCOMP_SYSCALL(&savedCtx);
- unsigned long args[6];
- args[0] = SECCOMP_PARM1(&savedCtx);
- args[1] = SECCOMP_PARM2(&savedCtx);
- args[2] = SECCOMP_PARM3(&savedCtx);
- args[3] = SECCOMP_PARM4(&savedCtx);
- args[4] = SECCOMP_PARM5(&savedCtx);
- args[5] = SECCOMP_PARM6(&savedCtx);
-
- // TODO, someday when this is enabled on MIPS: include the two extra
- // args in the error message.
- SANDBOX_LOG_ERROR("seccomp sandbox violation: pid %d, syscall %d,"
- " args %d %d %d %d %d %d. Killing process.",
- pid, syscall_nr,
- args[0], args[1], args[2], args[3], args[4], args[5]);
-
- // Bug 1017393: record syscall number somewhere useful.
- info->si_addr = reinterpret_cast<void*>(syscall_nr);
-
- gSandboxCrashFunc(nr, info, &savedCtx);
- _exit(127);
-}
-
-/**
- * This function installs the SIGSYS handler. This is slightly
- * complicated because we want to use Chromium's handler to dispatch
- * to specific trap handlers defined in the policy, but we also need
- * the full original signal context to give to Breakpad for crash
- * dumps. So we install Chromium's handler first, then retrieve its
- * address so our replacement can delegate to it.
- */
-static void
-InstallSigSysHandler(void)
-{
- struct sigaction act;
-
- // Ensure that the Chromium handler is installed.
- Unused << sandbox::Trap::Registry();
-
- // If the signal handling state isn't as expected, crash now instead
- // of crashing later (and more confusingly) when SIGSYS happens.
-
- if (sigaction(SIGSYS, nullptr, &act) != 0) {
- MOZ_CRASH("Couldn't read old SIGSYS disposition");
- }
- if ((act.sa_flags & SA_SIGINFO) != SA_SIGINFO) {
- MOZ_CRASH("SIGSYS not already set to a siginfo handler?");
- }
- MOZ_RELEASE_ASSERT(act.sa_sigaction);
- gChromiumSigSysHandler = act.sa_sigaction;
- act.sa_sigaction = SigSysHandler;
- // Currently, SA_NODEFER should already be set by the Chromium code,
- // but it's harmless to ensure that it's set:
- MOZ_ASSERT(act.sa_flags & SA_NODEFER);
- act.sa_flags |= SA_NODEFER;
- if (sigaction(SIGSYS, &act, nullptr) < 0) {
- MOZ_CRASH("Couldn't change SIGSYS disposition");
- }
-}
-
-/**
- * This function installs the syscall filter, a.k.a. seccomp. The
- * aUseTSync flag indicates whether this should apply to all threads
- * in the process -- which will fail if the kernel doesn't support
- * that -- or only the current thread.
- *
- * SECCOMP_MODE_FILTER is the "bpf" mode of seccomp which allows
- * to pass a bpf program (in our case, it contains a syscall
- * whitelist).
- *
- * PR_SET_NO_NEW_PRIVS ensures that it is impossible to grant more
- * syscalls to the process beyond this point (even after fork()), and
- * prevents gaining capabilities (e.g., by exec'ing a setuid root
- * program). The kernel won't allow seccomp-bpf without doing this,
- * because otherwise it could be used for privilege escalation attacks.
- *
- * Returns false if the filter was already installed (see the
- * PR_SET_NO_NEW_PRIVS rule in SandboxFilter.cpp). Crashes on any
- * other error condition.
- *
- * @see SandboxInfo
- * @see BroadcastSetThreadSandbox
- */
-static bool MOZ_MUST_USE
-InstallSyscallFilter(const sock_fprog *aProg, bool aUseTSync)
-{
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
- if (!aUseTSync && errno == ETXTBSY) {
- return false;
- }
- SANDBOX_LOG_ERROR("prctl(PR_SET_NO_NEW_PRIVS) failed: %s", strerror(errno));
- MOZ_CRASH("prctl(PR_SET_NO_NEW_PRIVS)");
- }
-
- if (aUseTSync) {
- if (syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
- SECCOMP_FILTER_FLAG_TSYNC, aProg) != 0) {
- SANDBOX_LOG_ERROR("thread-synchronized seccomp failed: %s",
- strerror(errno));
- MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
- }
- } else {
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, (unsigned long)aProg, 0, 0)) {
- SANDBOX_LOG_ERROR("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) failed: %s",
- strerror(errno));
- MOZ_CRASH("seccomp+tsync failed, but kernel supports tsync");
- }
- }
- return true;
-}
-
-// Use signals for permissions that need to be set per-thread.
-// The communication channel from the signal handler back to the main thread.
-static mozilla::Atomic<int> gSetSandboxDone;
-// Pass the filter itself through a global.
-const sock_fprog* gSetSandboxFilter;
-
-// We have to dynamically allocate the signal number; see bug 1038900.
-// This function returns the first realtime signal currently set to
-// default handling (i.e., not in use), or 0 if none could be found.
-//
-// WARNING: if this function or anything similar to it (including in
-// external libraries) is used on multiple threads concurrently, there
-// will be a race condition.
-static int
-FindFreeSignalNumber()
-{
- for (int signum = SIGRTMAX; signum >= SIGRTMIN; --signum) {
- struct sigaction sa;
-
- if (sigaction(signum, nullptr, &sa) == 0 &&
- (sa.sa_flags & SA_SIGINFO) == 0 &&
- sa.sa_handler == SIG_DFL) {
- return signum;
- }
- }
- 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()
-{
- return InstallSyscallFilter(gSetSandboxFilter, false);
-}
-
-static void
-SetThreadSandboxHandler(int signum)
-{
- // The non-zero number sent back to the main thread indicates
- // whether action was taken.
- if (SetThreadSandbox()) {
- gSetSandboxDone = 2;
- } else {
- gSetSandboxDone = 1;
- }
- // Wake up the main thread. See the FUTEX_WAIT call, below, for an
- // explanation.
- syscall(__NR_futex, reinterpret_cast<int*>(&gSetSandboxDone),
- FUTEX_WAKE, 1);
-}
-
-static void
-EnterChroot()
-{
- if (gChrootHelper) {
- gChrootHelper->Invoke();
- gChrootHelper = nullptr;
- }
-}
-
-static void
-BroadcastSetThreadSandbox(const sock_fprog* aFilter)
-{
- pid_t pid, tid, myTid;
- DIR *taskdp;
- struct dirent *de;
-
- // This function does not own *aFilter, so this global needs to
- // always be zeroed before returning.
- gSetSandboxFilter = aFilter;
-
- static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
- "mozilla::Atomic<int> isn't represented by an int");
- pid = getpid();
- myTid = syscall(__NR_gettid);
- taskdp = opendir("/proc/self/task");
- if (taskdp == nullptr) {
- SANDBOX_LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
- MOZ_CRASH();
- }
-
- EnterChroot();
-
- // In case this races with a not-yet-deprivileged thread cloning
- // itself, repeat iterating over all threads until we find none
- // that are still privileged.
- bool sandboxProgress;
- do {
- sandboxProgress = false;
- // For each thread...
- while ((de = readdir(taskdp))) {
- char *endptr;
- tid = strtol(de->d_name, &endptr, 10);
- if (*endptr != '\0' || tid <= 0) {
- // Not a task ID.
- continue;
- }
- if (tid == myTid) {
- // Drop this thread's privileges last, below, so we can
- // continue to signal other threads.
- continue;
- }
-
- MOZ_RELEASE_ASSERT(gSeccompTsyncBroadcastSignum != 0);
-
- // Reset the futex cell and signal.
- gSetSandboxDone = 0;
- if (syscall(__NR_tgkill, pid, tid, gSeccompTsyncBroadcastSignum) != 0) {
- if (errno == ESRCH) {
- SANDBOX_LOG_ERROR("Thread %d unexpectedly exited.", tid);
- // Rescan threads, in case it forked before exiting.
- sandboxProgress = true;
- continue;
- }
- SANDBOX_LOG_ERROR("tgkill(%d,%d): %s\n", pid, tid, strerror(errno));
- MOZ_CRASH();
- }
- // It's unlikely, but if the thread somehow manages to exit
- // after receiving the signal but before entering the signal
- // handler, we need to avoid blocking forever.
- //
- // Using futex directly lets the signal handler send the wakeup
- // from an async signal handler (pthread mutex/condvar calls
- // aren't allowed), and to use a relative timeout that isn't
- // affected by changes to the system clock (not possible with
- // POSIX semaphores).
- //
- // If a thread doesn't respond within a reasonable amount of
- // time, but still exists, we crash -- the alternative is either
- // blocking forever or silently losing security, and it
- // shouldn't actually happen.
- static const int crashDelay = 10; // seconds
- struct timespec timeLimit;
- clock_gettime(CLOCK_MONOTONIC, &timeLimit);
- timeLimit.tv_sec += crashDelay;
- while (true) {
- static const struct timespec futexTimeout = { 0, 10*1000*1000 }; // 10ms
- // Atomically: if gSetSandboxDone == 0, then sleep.
- if (syscall(__NR_futex, reinterpret_cast<int*>(&gSetSandboxDone),
- FUTEX_WAIT, 0, &futexTimeout) != 0) {
- if (errno != EWOULDBLOCK && errno != ETIMEDOUT && errno != EINTR) {
- SANDBOX_LOG_ERROR("FUTEX_WAIT: %s\n", strerror(errno));
- MOZ_CRASH();
- }
- }
- // Did the handler finish?
- if (gSetSandboxDone > 0) {
- if (gSetSandboxDone == 2) {
- sandboxProgress = true;
- }
- break;
- }
- // Has the thread ceased to exist?
- if (syscall(__NR_tgkill, pid, tid, 0) != 0) {
- if (errno == ESRCH) {
- SANDBOX_LOG_ERROR("Thread %d unexpectedly exited.", tid);
- }
- // Rescan threads, in case it forked before exiting.
- // Also, if it somehow failed in a way that wasn't ESRCH,
- // and still exists, that will be handled on the next pass.
- sandboxProgress = true;
- break;
- }
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (now.tv_sec > timeLimit.tv_sec ||
- (now.tv_sec == timeLimit.tv_sec &&
- now.tv_nsec > timeLimit.tv_nsec)) {
- SANDBOX_LOG_ERROR("Thread %d unresponsive for %d seconds."
- " Killing process.",
- tid, crashDelay);
- MOZ_CRASH();
- }
- }
- }
- rewinddir(taskdp);
- } while (sandboxProgress);
-
- void (*oldHandler)(int);
- oldHandler = signal(gSeccompTsyncBroadcastSignum, SIG_DFL);
- gSeccompTsyncBroadcastSignum = 0;
- if (oldHandler != SetThreadSandboxHandler) {
- // See the comment on FindFreeSignalNumber about race conditions.
- SANDBOX_LOG_ERROR("handler for signal %d was changed to %p!",
- gSeccompTsyncBroadcastSignum, oldHandler);
- MOZ_CRASH();
- }
- Unused << closedir(taskdp);
- // And now, deprivilege the main thread:
- SetThreadSandbox();
- gSetSandboxFilter = nullptr;
-}
-
-static void
-ApplySandboxWithTSync(sock_fprog* aFilter)
-{
- EnterChroot();
- // At this point we're committed to using tsync, because the signal
- // broadcast workaround needs to access procfs. (Unless chroot
- // isn't used... but this failure shouldn't happen in the first
- // place, so let's not make extra special cases for it.)
- if (!InstallSyscallFilter(aFilter, true)) {
- MOZ_CRASH();
- }
-}
-
-// Common code for sandbox startup.
-static void
-SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy)
-{
- MOZ_ASSERT(gSandboxCrashFunc);
-
- // Note: PolicyCompiler borrows the policy and registry for its
- // lifetime, but does not take ownership of them.
- sandbox::bpf_dsl::PolicyCompiler compiler(aPolicy.get(),
- sandbox::Trap::Registry());
- sandbox::CodeGen::Program program = compiler.Compile();
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- sandbox::bpf_dsl::DumpBPF::PrintProgram(program);
- }
-
- InstallSigSysHandler();
-
-#ifdef MOZ_ASAN
- __sanitizer_sandbox_arguments asanArgs;
- asanArgs.coverage_sandboxed = 1;
- asanArgs.coverage_fd = -1;
- asanArgs.coverage_max_block_size = 0;
- __sanitizer_sandbox_on_notify(&asanArgs);
-#endif
-
- // The syscall takes a C-style array, so copy the vector into one.
- size_t programLen = program.size();
- UniquePtr<sock_filter[]> flatProgram(new sock_filter[programLen]);
- for (auto i = program.begin(); i != program.end(); ++i) {
- flatProgram[i - program.begin()] = *i;
- }
-
- sock_fprog fprog;
- fprog.filter = flatProgram.get();
- fprog.len = static_cast<unsigned short>(programLen);
- MOZ_RELEASE_ASSERT(static_cast<size_t>(fprog.len) == programLen);
-
- const SandboxInfo info = SandboxInfo::Get();
- if (info.Test(SandboxInfo::kHasSeccompTSync)) {
- if (info.Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("using seccomp tsync");
- }
- ApplySandboxWithTSync(&fprog);
- } else {
- if (info.Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("no tsync support; using signal broadcast");
- }
- BroadcastSetThreadSandbox(&fprog);
- }
- MOZ_RELEASE_ASSERT(!gChrootHelper, "forgot to chroot");
-}
-
-void
-SandboxEarlyInit(GeckoProcessType aType)
-{
- const SandboxInfo info = SandboxInfo::Get();
- if (info.Test(SandboxInfo::kUnexpectedThreads)) {
- return;
- }
- MOZ_RELEASE_ASSERT(IsSingleThreaded());
-
- // Which kinds of resource isolation (of those that need to be set
- // up at this point) can be used by this process?
- bool canChroot = false;
- bool canUnshareNet = false;
- bool canUnshareIPC = false;
-
- switch (aType) {
- case GeckoProcessType_Default:
- MOZ_ASSERT(false, "SandboxEarlyInit in parent process");
- return;
- default:
- // Other cases intentionally left blank.
- break;
- }
-
- // If TSYNC is not supported, set up signal handler
- // used to enable seccomp on each thread.
- if (!info.Test(SandboxInfo::kHasSeccompTSync)) {
- gSeccompTsyncBroadcastSignum = FindFreeSignalNumber();
- if (gSeccompTsyncBroadcastSignum == 0) {
- SANDBOX_LOG_ERROR("No available signal numbers!");
- MOZ_CRASH();
- }
-
- void (*oldHandler)(int);
- oldHandler = signal(gSeccompTsyncBroadcastSignum, SetThreadSandboxHandler);
- if (oldHandler != SIG_DFL) {
- // See the comment on FindFreeSignalNumber about race conditions.
- SANDBOX_LOG_ERROR("signal %d in use by handler %p!\n",
- gSeccompTsyncBroadcastSignum, oldHandler);
- MOZ_CRASH();
- }
- }
-
- // If there's nothing to do, then we're done.
- if (!canChroot && !canUnshareNet && !canUnshareIPC) {
- return;
- }
-
- {
- LinuxCapabilities existingCaps;
- if (existingCaps.GetCurrent() && existingCaps.AnyEffective()) {
- SANDBOX_LOG_ERROR("PLEASE DO NOT RUN THIS AS ROOT. Strange things may"
- " happen when capabilities are dropped.");
- }
- }
-
- // If capabilities can't be gained, then nothing can be done.
- if (!info.Test(SandboxInfo::kHasUserNamespaces)) {
- // Drop any existing capabilities; unsharing the user namespace
- // would implicitly drop them, so if we're running in a broken
- // configuration where that would matter (e.g., running as root
- // from a non-root-owned mode-0700 directory) this means it will
- // break the same way on all kernels and be easier to troubleshoot.
- LinuxCapabilities().SetCurrent();
- return;
- }
-
- // The failure cases for the various unshares, and setting up the
- // chroot helper, don't strictly need to be fatal -- but they also
- // shouldn't fail on any reasonable system, so let's take the small
- // risk of breakage over the small risk of quietly providing less
- // security than we expect. (Unlike in SandboxInfo, this is in the
- // child process, so crashing here isn't as severe a response to the
- // unexpected.)
- if (!UnshareUserNamespace()) {
- SANDBOX_LOG_ERROR("unshare(CLONE_NEWUSER): %s", strerror(errno));
- // If CanCreateUserNamespace (SandboxInfo.cpp) returns true, then
- // the unshare shouldn't have failed.
- MOZ_CRASH("unshare(CLONE_NEWUSER)");
- }
- // No early returns after this point! We need to drop the
- // capabilities that were gained by unsharing the user namesapce.
-
- if (canUnshareIPC && syscall(__NR_unshare, CLONE_NEWIPC) != 0) {
- SANDBOX_LOG_ERROR("unshare(CLONE_NEWIPC): %s", strerror(errno));
- MOZ_CRASH("unshare(CLONE_NEWIPC)");
- }
-
- if (canUnshareNet && syscall(__NR_unshare, CLONE_NEWNET) != 0) {
- SANDBOX_LOG_ERROR("unshare(CLONE_NEWNET): %s", strerror(errno));
- MOZ_CRASH("unshare(CLONE_NEWNET)");
- }
-
- if (canChroot) {
- gChrootHelper = MakeUnique<SandboxChroot>();
- if (!gChrootHelper->Prepare()) {
- SANDBOX_LOG_ERROR("failed to set up chroot helper");
- MOZ_CRASH("SandboxChroot::Prepare");
- }
- }
-
- if (!LinuxCapabilities().SetCurrent()) {
- SANDBOX_LOG_ERROR("dropping capabilities: %s", strerror(errno));
- MOZ_CRASH("can't drop capabilities");
- }
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/Sandbox.h b/security/sandbox/linux/Sandbox.h
deleted file mode 100644
index 9d1c3d4b3..000000000
--- a/security/sandbox/linux/Sandbox.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- 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_Sandbox_h
-#define mozilla_Sandbox_h
-
-#include "mozilla/Types.h"
-#include "nsXULAppAPI.h"
-
-// This defines the entry points for a content process to start
-// sandboxing itself. See also SandboxInfo.h for what parts of
-// sandboxing are enabled/supported.
-
-namespace mozilla {
-
-// This must be called early, while the process is still single-threaded.
-MOZ_EXPORT void SandboxEarlyInit(GeckoProcessType aType);
-
-} // namespace mozilla
-
-#endif // mozilla_Sandbox_h
diff --git a/security/sandbox/linux/SandboxBrokerClient.cpp b/security/sandbox/linux/SandboxBrokerClient.cpp
deleted file mode 100644
index 68744ad02..000000000
--- a/security/sandbox/linux/SandboxBrokerClient.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/* -*- 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 "SandboxBrokerClient.h"
-#include "SandboxInfo.h"
-#include "SandboxLogging.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "mozilla/Assertions.h"
-#include "mozilla/NullPtr.h"
-#include "base/strings/safe_sprintf.h"
-
-namespace mozilla {
-
-SandboxBrokerClient::SandboxBrokerClient(int aFd)
-: mFileDesc(aFd)
-{
-}
-
-SandboxBrokerClient::~SandboxBrokerClient()
-{
- close(mFileDesc);
-}
-
-int
-SandboxBrokerClient::DoCall(const Request* aReq, const char* aPath,
- const char* aPath2, void* aResponseBuff,
- bool expectFd)
-{
- // Remap /proc/self to the actual pid, so that the broker can open
- // it. This happens here instead of in the broker to follow the
- // principle of least privilege and keep the broker as simple as
- // possible. (Note: when pid namespaces happen, this will also need
- // to remap the inner pid to the outer pid.)
- // We only remap the first path.
- static const char kProcSelf[] = "/proc/self/";
- static const size_t kProcSelfLen = sizeof(kProcSelf) - 1;
- const char* path = aPath;
- // This buffer just needs to be large enough for any such path that
- // the policy would actually allow. sizeof("/proc/2147483647/") == 18.
- char rewrittenPath[64];
- if (strncmp(aPath, kProcSelf, kProcSelfLen) == 0) {
- ssize_t len =
- base::strings::SafeSPrintf(rewrittenPath, "/proc/%d/%s",
- getpid(), aPath + kProcSelfLen);
- if (static_cast<size_t>(len) < sizeof(rewrittenPath)) {
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("rewriting %s -> %s", aPath, rewrittenPath);
- }
- path = rewrittenPath;
- } else {
- SANDBOX_LOG_ERROR("not rewriting unexpectedly long path %s", aPath);
- }
- }
-
- struct iovec ios[3];
- int respFds[2];
-
- // Set up iovecs for request + path.
- ios[0].iov_base = const_cast<Request*>(aReq);
- ios[0].iov_len = sizeof(*aReq);
- ios[1].iov_base = const_cast<char*>(path);
- ios[1].iov_len = strlen(path) + 1;
- if (aPath2 != nullptr) {
- ios[2].iov_base = const_cast<char*>(aPath2);
- ios[2].iov_len = strlen(aPath2) + 1;
- } else {
- ios[2].iov_base = 0;
- ios[2].iov_len = 0;
- }
- if (ios[1].iov_len > kMaxPathLen) {
- return -ENAMETOOLONG;
- }
- if (ios[2].iov_len > kMaxPathLen) {
- return -ENAMETOOLONG;
- }
-
- // Create response socket and send request.
- if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, respFds) < 0) {
- return -errno;
- }
- const ssize_t sent = SendWithFd(mFileDesc, ios, 3, respFds[1]);
- const int sendErrno = errno;
- MOZ_ASSERT(sent < 0 ||
- static_cast<size_t>(sent) == ios[0].iov_len
- + ios[1].iov_len
- + ios[2].iov_len);
- close(respFds[1]);
- if (sent < 0) {
- close(respFds[0]);
- return -sendErrno;
- }
-
- // Set up iovecs for response.
- Response resp;
- ios[0].iov_base = &resp;
- ios[0].iov_len = sizeof(resp);
- if (aResponseBuff) {
- ios[1].iov_base = aResponseBuff;
- ios[1].iov_len = aReq->mBufSize;
- } else {
- ios[1].iov_base = nullptr;
- ios[1].iov_len = 0;
- }
-
- // Wait for response and return appropriately.
- int openedFd = -1;
- const ssize_t recvd = RecvWithFd(respFds[0], ios, aResponseBuff ? 2 : 1,
- expectFd ? &openedFd : nullptr);
- const int recvErrno = errno;
- close(respFds[0]);
- if (recvd < 0) {
- return -recvErrno;
- }
- if (recvd == 0) {
- SANDBOX_LOG_ERROR("Unexpected EOF, op %d flags 0%o path %s",
- aReq->mOp, aReq->mFlags, path);
- return -EIO;
- }
- MOZ_ASSERT(static_cast<size_t>(recvd) <= ios[0].iov_len + ios[1].iov_len);
- // Some calls such as readlink return a size if successful
- if (resp.mError >= 0) {
- // Success!
- if (expectFd) {
- MOZ_ASSERT(openedFd >= 0);
- return openedFd;
- }
- return resp.mError;
- }
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- // Keep in mind that "rejected" files can include ones that don't
- // actually exist, if it's something that's optional or part of a
- // search path (e.g., shared libraries). In those cases, this
- // error message is expected.
- SANDBOX_LOG_ERROR("Rejected errno %d op %d flags 0%o path %s",
- resp.mError, aReq->mOp, aReq->mFlags, path);
- }
- if (openedFd >= 0) {
- close(openedFd);
- }
- return resp.mError;
-}
-
-int
-SandboxBrokerClient::Open(const char* aPath, int aFlags)
-{
- Request req = { SANDBOX_FILE_OPEN, aFlags, 0 };
- int maybeFd = DoCall(&req, aPath, nullptr, nullptr, true);
- if (maybeFd >= 0) {
- // NSPR has opinions about file flags. Fix O_CLOEXEC.
- if ((aFlags & O_CLOEXEC) == 0) {
- fcntl(maybeFd, F_SETFD, 0);
- }
- }
- return maybeFd;
-}
-
-int
-SandboxBrokerClient::Access(const char* aPath, int aMode)
-{
- Request req = { SANDBOX_FILE_ACCESS, aMode, 0 };
- return DoCall(&req, aPath, nullptr, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Stat(const char* aPath, statstruct* aStat)
-{
- Request req = { SANDBOX_FILE_STAT, 0, sizeof(statstruct) };
- return DoCall(&req, aPath, nullptr, (void*)aStat, false);
-}
-
-int
-SandboxBrokerClient::LStat(const char* aPath, statstruct* aStat)
-{
- Request req = { SANDBOX_FILE_STAT, O_NOFOLLOW, sizeof(statstruct) };
- return DoCall(&req, aPath, nullptr, (void*)aStat, false);
-}
-
-int
-SandboxBrokerClient::Chmod(const char* aPath, int aMode)
-{
- Request req = {SANDBOX_FILE_CHMOD, aMode, 0};
- return DoCall(&req, aPath, nullptr, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Link(const char* aOldPath, const char* aNewPath)
-{
- Request req = {SANDBOX_FILE_LINK, 0, 0};
- return DoCall(&req, aOldPath, aNewPath, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Symlink(const char* aOldPath, const char* aNewPath)
-{
- Request req = {SANDBOX_FILE_SYMLINK, 0, 0};
- return DoCall(&req, aOldPath, aNewPath, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Rename(const char* aOldPath, const char* aNewPath)
-{
- Request req = {SANDBOX_FILE_RENAME, 0, 0};
- return DoCall(&req, aOldPath, aNewPath, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Mkdir(const char* aPath, int aMode)
-{
- Request req = {SANDBOX_FILE_MKDIR, aMode, 0};
- return DoCall(&req, aPath, nullptr, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Unlink(const char* aPath)
-{
- Request req = {SANDBOX_FILE_UNLINK, 0, 0};
- return DoCall(&req, aPath, nullptr, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Rmdir(const char* aPath)
-{
- Request req = {SANDBOX_FILE_RMDIR, 0, 0};
- return DoCall(&req, aPath, nullptr, nullptr, false);
-}
-
-int
-SandboxBrokerClient::Readlink(const char* aPath, void* aBuff, size_t aSize)
-{
- Request req = {SANDBOX_FILE_READLINK, 0, aSize};
- return DoCall(&req, aPath, nullptr, aBuff, false);
-}
-
-} // namespace mozilla
-
diff --git a/security/sandbox/linux/SandboxBrokerClient.h b/security/sandbox/linux/SandboxBrokerClient.h
deleted file mode 100644
index 06db2f183..000000000
--- a/security/sandbox/linux/SandboxBrokerClient.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- 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_SandboxBrokerClient_h
-#define mozilla_SandboxBrokerClient_h
-
-#include "broker/SandboxBrokerCommon.h"
-#include "broker/SandboxBrokerUtils.h"
-
-#include "mozilla/Attributes.h"
-
-// This is the client for the sandbox broker described in
-// broker/SandboxBroker.h; its constructor takes the file descriptor
-// returned by SandboxBroker::Create, passed to the child over IPC.
-//
-// The operations exposed here can be called from any thread and in
-// async signal handlers, like the corresponding system calls. The
-// intended use is from a seccomp-bpf SIGSYS handler, to transparently
-// replace those syscalls, but they could also be used directly.
-
-struct stat;
-
-namespace mozilla {
-
-class SandboxBrokerClient final : private SandboxBrokerCommon {
- public:
- explicit SandboxBrokerClient(int aFd);
- ~SandboxBrokerClient();
-
- int Open(const char* aPath, int aFlags);
- int Access(const char* aPath, int aMode);
- int Stat(const char* aPath, statstruct* aStat);
- int LStat(const char* aPath, statstruct* aStat);
- int Chmod(const char* aPath, int aMode);
- int Link(const char* aPath, const char* aPath2);
- int Mkdir(const char* aPath, int aMode);
- int Symlink(const char* aOldPath, const char* aNewPath);
- int Rename(const char* aOldPath, const char* aNewPath);
- int Unlink(const char* aPath);
- int Rmdir(const char* aPath);
- int Readlink(const char* aPath, void* aBuf, size_t aBufSize);
-
- private:
- int mFileDesc;
-
- int DoCall(const Request* aReq,
- const char* aPath,
- const char* aPath2,
- void *aReponseBuff,
- bool expectFd);
-};
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxBrokerClient_h
diff --git a/security/sandbox/linux/SandboxChroot.cpp b/security/sandbox/linux/SandboxChroot.cpp
deleted file mode 100644
index 2091bfe05..000000000
--- a/security/sandbox/linux/SandboxChroot.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/* -*- 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 "SandboxChroot.h"
-
-#include "SandboxLogging.h"
-#include "LinuxCapabilities.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "base/posix/eintr_wrapper.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/DebugOnly.h"
-#include "mozilla/NullPtr.h"
-
-#define MOZ_ALWAYS_ZERO(e) MOZ_ALWAYS_TRUE((e) == 0)
-
-namespace mozilla {
-
-SandboxChroot::SandboxChroot()
-{
- pthread_mutexattr_t attr;
- MOZ_ALWAYS_ZERO(pthread_mutexattr_init(&attr));
- MOZ_ALWAYS_ZERO(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
- MOZ_ALWAYS_ZERO(pthread_mutex_init(&mMutex, &attr));
- MOZ_ALWAYS_ZERO(pthread_cond_init(&mWakeup, nullptr));
- mCommand = NO_THREAD;
-}
-
-SandboxChroot::~SandboxChroot()
-{
- SendCommand(JUST_EXIT);
- MOZ_ALWAYS_ZERO(pthread_mutex_destroy(&mMutex));
- MOZ_ALWAYS_ZERO(pthread_cond_destroy(&mWakeup));
-}
-
-bool
-SandboxChroot::SendCommand(Command aComm)
-{
- MOZ_ALWAYS_ZERO(pthread_mutex_lock(&mMutex));
- if (mCommand == NO_THREAD) {
- MOZ_RELEASE_ASSERT(aComm == JUST_EXIT);
- MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
- return false;
- } else {
- MOZ_ASSERT(mCommand == NO_COMMAND);
- mCommand = aComm;
- MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
- MOZ_ALWAYS_ZERO(pthread_cond_signal(&mWakeup));
- void *retval;
- if (pthread_join(mThread, &retval) != 0 || retval != nullptr) {
- MOZ_CRASH("Failed to stop privileged chroot thread");
- }
- MOZ_ASSERT(mCommand == NO_THREAD);
- }
- return true;
-}
-
-static void
-AlwaysClose(int fd)
-{
- if (IGNORE_EINTR(close(fd)) != 0) {
- SANDBOX_LOG_ERROR("close: %s", strerror(errno));
- MOZ_CRASH("failed to close()");
- }
-}
-
-static int
-OpenDeletedDirectory()
-{
- // We don't need this directory to persist between invocations of
- // the program (nor need it to be cleaned up if something goes wrong
- // here, because mkdtemp will choose a fresh name), so /tmp as
- // specified by FHS is adequate.
- //
- // However, this needs a filesystem where a deleted directory can
- // still be used, and /tmp is sometimes not that; e.g., aufs(5),
- // often used for containers, will cause the chroot() to fail with
- // ESTALE (bug 1162965). So this uses /dev/shm if possible instead.
- char tmpPath[] = "/tmp/mozsandbox.XXXXXX";
- char shmPath[] = "/dev/shm/mozsandbox.XXXXXX";
- char* path;
- if (mkdtemp(shmPath)) {
- path = shmPath;
- } else if (mkdtemp(tmpPath)) {
- path = tmpPath;
- } else {
- SANDBOX_LOG_ERROR("mkdtemp: %s", strerror(errno));
- return -1;
- }
- int fd = HANDLE_EINTR(open(path, O_RDONLY | O_DIRECTORY));
- if (fd < 0) {
- SANDBOX_LOG_ERROR("open %s: %s", path, strerror(errno));
- // Try to clean up. Shouldn't fail, but livable if it does.
- DebugOnly<bool> ok = HANDLE_EINTR(rmdir(path)) == 0;
- MOZ_ASSERT(ok);
- return -1;
- }
- if (HANDLE_EINTR(rmdir(path)) != 0) {
- SANDBOX_LOG_ERROR("rmdir %s: %s", path, strerror(errno));
- AlwaysClose(fd);
- return -1;
- }
- return fd;
-}
-
-bool
-SandboxChroot::Prepare()
-{
- LinuxCapabilities caps;
- if (!caps.GetCurrent() || !caps.Effective(CAP_SYS_CHROOT)) {
- SANDBOX_LOG_ERROR("don't have permission to chroot");
- return false;
- }
- mFd = OpenDeletedDirectory();
- if (mFd < 0) {
- SANDBOX_LOG_ERROR("failed to create empty directory for chroot");
- return false;
- }
- MOZ_ALWAYS_ZERO(pthread_mutex_lock(&mMutex));
- MOZ_ASSERT(mCommand == NO_THREAD);
- if (pthread_create(&mThread, nullptr, StaticThreadMain, this) != 0) {
- MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
- SANDBOX_LOG_ERROR("pthread_create: %s", strerror(errno));
- return false;
- }
- while (mCommand != NO_COMMAND) {
- MOZ_ASSERT(mCommand == NO_THREAD);
- MOZ_ALWAYS_ZERO(pthread_cond_wait(&mWakeup, &mMutex));
- }
- MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
- return true;
-}
-
-void
-SandboxChroot::Invoke()
-{
- MOZ_ALWAYS_TRUE(SendCommand(DO_CHROOT));
-}
-
-static bool
-ChrootToFileDesc(int fd)
-{
- if (fchdir(fd) != 0) {
- SANDBOX_LOG_ERROR("fchdir: %s", strerror(errno));
- return false;
- }
- if (chroot(".") != 0) {
- SANDBOX_LOG_ERROR("chroot: %s", strerror(errno));
- return false;
- }
- return true;
-}
-
-/* static */ void*
-SandboxChroot::StaticThreadMain(void* aVoidPtr)
-{
- static_cast<SandboxChroot*>(aVoidPtr)->ThreadMain();
- return nullptr;
-}
-
-void
-SandboxChroot::ThreadMain()
-{
- // First, drop everything that isn't CAP_SYS_CHROOT. (This code
- // assumes that this thread already has effective CAP_SYS_CHROOT,
- // because Prepare() checked for it before creating this thread.)
- LinuxCapabilities caps;
- caps.Effective(CAP_SYS_CHROOT) = true;
- if (!caps.SetCurrent()) {
- SANDBOX_LOG_ERROR("capset: %s", strerror(errno));
- MOZ_CRASH("Can't limit chroot thread's capabilities");
- }
-
- MOZ_ALWAYS_ZERO(pthread_mutex_lock(&mMutex));
- MOZ_ASSERT(mCommand == NO_THREAD);
- mCommand = NO_COMMAND;
- MOZ_ALWAYS_ZERO(pthread_cond_signal(&mWakeup));
- while (mCommand == NO_COMMAND) {
- MOZ_ALWAYS_ZERO(pthread_cond_wait(&mWakeup, &mMutex));
- }
- if (mCommand == DO_CHROOT) {
- MOZ_ASSERT(mFd >= 0);
- if (!ChrootToFileDesc(mFd)) {
- MOZ_CRASH("Failed to chroot");
- }
- } else {
- MOZ_ASSERT(mCommand == JUST_EXIT);
- }
- if (mFd >= 0) {
- AlwaysClose(mFd);
- mFd = -1;
- }
- mCommand = NO_THREAD;
- MOZ_ALWAYS_ZERO(pthread_mutex_unlock(&mMutex));
- // Drop the remaining capabilities; see note in SandboxChroot.h
- // about the potential unreliability of pthread_join.
- if (!LinuxCapabilities().SetCurrent()) {
- MOZ_CRASH("can't drop capabilities");
- }
-}
-
-} // namespace mozilla
-
-#undef MOZ_ALWAYS_ZERO
diff --git a/security/sandbox/linux/SandboxChroot.h b/security/sandbox/linux/SandboxChroot.h
deleted file mode 100644
index 3ad89b732..000000000
--- a/security/sandbox/linux/SandboxChroot.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- 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_SandboxChroot_h
-#define mozilla_SandboxChroot_h
-
-#include <pthread.h>
-
-#include "mozilla/Attributes.h"
-
-// This class uses the chroot(2) system call and Linux namespaces to
-// revoke the process's access to the filesystem. It requires that
-// the process be able to create user namespaces; this is the
-// kHasUserNamespaces in SandboxInfo.h.
-//
-// Usage: call Prepare() from a thread with CAP_SYS_CHROOT in its
-// effective capability set, then later call Invoke() when ready to
-// drop filesystem access. Prepare() creates a thread to do the
-// chrooting, so the caller can (and should!) drop its own
-// capabilities afterwards. When Invoke() returns, the thread will
-// have exited.
-//
-// (Exception: on Android/B2G <= KitKat, because of how pthread_join
-// is implemented, the thread may still exist, but it will not have
-// capabilities. Accordingly, on such systems, be careful about
-// namespaces or other resources the thread might have inherited.)
-//
-// Prepare() can fail (return false); for example, if it doesn't have
-// CAP_SYS_CHROOT or if it can't create a directory to chroot into.
-//
-// The root directory will be empty and deleted, so the process will
-// not be able to create new entries in it regardless of permissions.
-
-namespace mozilla {
-
-class SandboxChroot final {
-public:
- SandboxChroot();
- ~SandboxChroot();
- bool Prepare();
- void Invoke();
-private:
- enum Command {
- NO_THREAD,
- NO_COMMAND,
- DO_CHROOT,
- JUST_EXIT,
- };
-
- pthread_t mThread;
- pthread_mutex_t mMutex;
- pthread_cond_t mWakeup;
- Command mCommand;
- int mFd;
-
- void ThreadMain();
- static void* StaticThreadMain(void* aVoidPtr);
- bool SendCommand(Command aComm);
-};
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxChroot_h
diff --git a/security/sandbox/linux/SandboxFilter.cpp b/security/sandbox/linux/SandboxFilter.cpp
deleted file mode 100644
index afaf53cec..000000000
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/* -*- 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 "SandboxFilter.h"
-#include "SandboxFilterUtil.h"
-
-#include "SandboxBrokerClient.h"
-#include "SandboxInfo.h"
-#include "SandboxInternal.h"
-#include "SandboxLogging.h"
-
-#include "mozilla/UniquePtr.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/ipc.h>
-#include <linux/net.h>
-#include <linux/prctl.h>
-#include <linux/sched.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
-#include "sandbox/linux/system_headers/linux_seccomp.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-using namespace sandbox::bpf_dsl;
-#define CASES SANDBOX_BPF_DSL_CASES
-
-// Fill in defines in case of old headers.
-// (Warning: these are wrong on PA-RISC.)
-#ifndef MADV_NOHUGEPAGE
-#define MADV_NOHUGEPAGE 15
-#endif
-#ifndef MADV_DONTDUMP
-#define MADV_DONTDUMP 16
-#endif
-
-// Added in Linux 4.5; see bug 1303813.
-#ifndef MADV_FREE
-#define MADV_FREE 8
-#endif
-
-#ifndef PR_SET_PTRACER
-#define PR_SET_PTRACER 0x59616d61
-#endif
-
-// To avoid visual confusion between "ifdef ANDROID" and "ifndef ANDROID":
-#ifndef ANDROID
-#define DESKTOP
-#endif
-
-// This file defines the seccomp-bpf system call filter policies.
-// See also SandboxFilterUtil.h, for the CASES_FOR_* macros and
-// SandboxFilterBase::Evaluate{Socket,Ipc}Call.
-//
-// One important difference from how Chromium bpf_dsl filters are
-// normally interpreted: returning -ENOSYS from a Trap() handler
-// indicates an unexpected system call; SigSysHandler() in Sandbox.cpp
-// will detect this, request a crash dump, and terminate the process.
-// This does not apply to using Error(ENOSYS) in the policy, so that
-// can be used if returning an actual ENOSYS is needed.
-
-namespace mozilla {
-
-// This class whitelists everything used by the sandbox itself, by the
-// core IPC code, by the crash reporter, or other core code.
-class SandboxPolicyCommon : public SandboxPolicyBase
-{
-protected:
- typedef const sandbox::arch_seccomp_data& ArgsRef;
-
- static intptr_t BlockedSyscallTrap(ArgsRef aArgs, void *aux) {
- MOZ_ASSERT(!aux);
- return -ENOSYS;
- }
-
-private:
-#if defined(ANDROID) && ANDROID_VERSION < 16
- // Bug 1093893: Translate tkill to tgkill for pthread_kill; fixed in
- // bionic commit 10c8ce59a (in JB and up; API level 16 = Android 4.1).
- static intptr_t TKillCompatTrap(const sandbox::arch_seccomp_data& aArgs,
- void *aux)
- {
- return syscall(__NR_tgkill, getpid(), aArgs.args[0], aArgs.args[1]);
- }
-#endif
-
- static intptr_t SetNoNewPrivsTrap(ArgsRef& aArgs, void* aux) {
- if (gSetSandboxFilter == nullptr) {
- // Called after BroadcastSetThreadSandbox finished, therefore
- // not our doing and not expected.
- return BlockedSyscallTrap(aArgs, nullptr);
- }
- // Signal that the filter is already in place.
- return -ETXTBSY;
- }
-
-public:
- virtual ResultExpr InvalidSyscall() const override {
- return Trap(BlockedSyscallTrap, nullptr);
- }
-
- virtual ResultExpr ClonePolicy(ResultExpr failPolicy) const {
- // Allow use for simple thread creation (pthread_create) only.
-
- // WARNING: s390 and cris pass the flags in the second arg -- see
- // CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
- // don't support seccomp-bpf on those archs yet.
- Arg<int> flags(0);
-
- // The glibc source hasn't changed the thread creation clone flags
- // since 2004, so this *should* be safe to hard-code. Bionic's
- // value has changed a few times, and has converged on the same one
- // as glibc; allow any of them.
- static const int flags_common = CLONE_VM | CLONE_FS | CLONE_FILES |
- CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
- static const int flags_modern = flags_common | CLONE_SETTLS |
- CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
-
- // Can't use CASES here because its decltype magic infers const
- // int instead of regular int and bizarre voluminous errors issue
- // forth from the depths of the standard library implementation.
- return Switch(flags)
-#ifdef ANDROID
- .Case(flags_common | CLONE_DETACHED, Allow()) // <= JB 4.2
- .Case(flags_common, Allow()) // JB 4.3 or KK 4.4
-#endif
- .Case(flags_modern, Allow()) // Android L or glibc
- .Default(failPolicy);
- }
-
- virtual ResultExpr PrctlPolicy() const {
- // Note: this will probably need PR_SET_VMA if/when it's used on
- // Android without being overridden by an allow-all policy, and
- // the constant will need to be defined locally.
- Arg<int> op(0);
- return Switch(op)
- .CASES((PR_GET_SECCOMP, // BroadcastSetThreadSandbox, etc.
- PR_SET_NAME, // Thread creation
- PR_SET_DUMPABLE, // Crash reporting
- PR_SET_PTRACER), // Debug-mode crash handling
- Allow())
- .Default(InvalidSyscall());
- }
-
- virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
- switch (aCall) {
- case SYS_RECVMSG:
- case SYS_SENDMSG:
- return Some(Allow());
- default:
- return Nothing();
- }
- }
-
- virtual ResultExpr EvaluateSyscall(int sysno) const override {
- switch (sysno) {
- // Timekeeping
- case __NR_clock_gettime: {
- Arg<clockid_t> clk_id(0);
- return If(clk_id == CLOCK_MONOTONIC, Allow())
-#ifdef CLOCK_MONOTONIC_COARSE
- .ElseIf(clk_id == CLOCK_MONOTONIC_COARSE, Allow())
-#endif
- .ElseIf(clk_id == CLOCK_PROCESS_CPUTIME_ID, Allow())
- .ElseIf(clk_id == CLOCK_REALTIME, Allow())
-#ifdef CLOCK_REALTIME_COARSE
- .ElseIf(clk_id == CLOCK_REALTIME_COARSE, Allow())
-#endif
- .ElseIf(clk_id == CLOCK_THREAD_CPUTIME_ID, Allow())
- .Else(InvalidSyscall());
- }
- case __NR_gettimeofday:
-#ifdef __NR_time
- case __NR_time:
-#endif
- case __NR_nanosleep:
- return Allow();
-
- // Thread synchronization
- case __NR_futex:
- // FIXME: This could be more restrictive....
- return Allow();
-
- // Asynchronous I/O
- case __NR_epoll_wait:
- case __NR_epoll_pwait:
- case __NR_epoll_ctl:
- case __NR_ppoll:
- case __NR_poll:
- return Allow();
-
- // Used when requesting a crash dump.
- case __NR_pipe:
- return Allow();
-
- // Metadata of opened files
- CASES_FOR_fstat:
- return Allow();
-
- // Simple I/O
- case __NR_write:
- case __NR_read:
- case __NR_readv:
- case __NR_writev: // see SandboxLogging.cpp
- CASES_FOR_lseek:
- return Allow();
-
- // Memory mapping
- CASES_FOR_mmap:
- case __NR_munmap:
- return Allow();
-
- // Signal handling
-#if defined(ANDROID) || defined(MOZ_ASAN)
- case __NR_sigaltstack:
-#endif
- CASES_FOR_sigreturn:
- CASES_FOR_sigprocmask:
- CASES_FOR_sigaction:
- return Allow();
-
- // Send signals within the process (raise(), profiling, etc.)
- case __NR_tgkill: {
- Arg<pid_t> tgid(0);
- return If(tgid == getpid(), Allow())
- .Else(InvalidSyscall());
- }
-
-#if defined(ANDROID) && ANDROID_VERSION < 16
- // Polyfill with tgkill; see above.
- case __NR_tkill:
- return Trap(TKillCompatTrap, nullptr);
-#endif
-
- // Yield
- case __NR_sched_yield:
- return Allow();
-
- // Thread creation.
- case __NR_clone:
- return ClonePolicy(InvalidSyscall());
-
- // More thread creation.
-#ifdef __NR_set_robust_list
- case __NR_set_robust_list:
- return Allow();
-#endif
-#ifdef ANDROID
- case __NR_set_tid_address:
- return Allow();
-#endif
-
- // prctl
- case __NR_prctl: {
- if (SandboxInfo::Get().Test(SandboxInfo::kHasSeccompTSync)) {
- return PrctlPolicy();
- }
-
- Arg<int> option(0);
- return If(option == PR_SET_NO_NEW_PRIVS,
- Trap(SetNoNewPrivsTrap, nullptr))
- .Else(PrctlPolicy());
- }
-
- // NSPR can call this when creating a thread, but it will accept a
- // polite "no".
- case __NR_getpriority:
- // But if thread creation races with sandbox startup, that call
- // could succeed, and then we get one of these:
- case __NR_setpriority:
- return Error(EACCES);
-
- // Stack bounds are obtained via pthread_getattr_np, which calls
- // this but doesn't actually need it:
- case __NR_sched_getaffinity:
- return Error(ENOSYS);
-
- // Read own pid/tid.
- case __NR_getpid:
- case __NR_gettid:
- return Allow();
-
- // Discard capabilities
- case __NR_close:
- return Allow();
-
- // Machine-dependent stuff
-#ifdef __arm__
- case __ARM_NR_breakpoint:
- case __ARM_NR_cacheflush:
- case __ARM_NR_usr26: // FIXME: do we actually need this?
- case __ARM_NR_usr32:
- case __ARM_NR_set_tls:
- return Allow();
-#endif
-
- // Needed when being debugged:
- case __NR_restart_syscall:
- return Allow();
-
- // Terminate threads or the process
- case __NR_exit:
- case __NR_exit_group:
- return Allow();
-
-#ifdef MOZ_ASAN
- // ASAN's error reporter wants to know if stderr is a tty.
- case __NR_ioctl: {
- Arg<int> fd(0);
- return If(fd == STDERR_FILENO, Allow())
- .Else(InvalidSyscall());
- }
-
- // ...and before compiler-rt r209773, it will call readlink on
- // /proc/self/exe and use the cached value only if that fails:
- case __NR_readlink:
- case __NR_readlinkat:
- return Error(ENOENT);
-
- // ...and if it found an external symbolizer, it will try to run it:
- // (See also bug 1081242 comment #7.)
- CASES_FOR_stat:
- return Error(ENOENT);
-#endif
-
- default:
- return SandboxPolicyBase::EvaluateSyscall(sysno);
- }
- }
-};
-
-// The process-type-specific syscall rules start here:
-
-}
diff --git a/security/sandbox/linux/SandboxFilter.h b/security/sandbox/linux/SandboxFilter.h
deleted file mode 100644
index b6031d30e..000000000
--- a/security/sandbox/linux/SandboxFilter.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- 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_SandboxFilter_h
-#define mozilla_SandboxFilter_h
-
-#include "mozilla/Atomics.h"
-#include "mozilla/UniquePtr.h"
-
-namespace sandbox {
-namespace bpf_dsl {
-class Policy;
-}
-}
-
-namespace mozilla {
-
-} // namespace mozilla
-
-#endif
diff --git a/security/sandbox/linux/SandboxFilterUtil.cpp b/security/sandbox/linux/SandboxFilterUtil.cpp
deleted file mode 100644
index 04fd6709c..000000000
--- a/security/sandbox/linux/SandboxFilterUtil.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -*- 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 "SandboxFilterUtil.h"
-
-#ifndef ANDROID
-#include <linux/ipc.h>
-#endif
-#include <linux/net.h>
-
-#include "mozilla/UniquePtr.h"
-#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
-
-// Older kernel headers (mostly Android, but also some older desktop
-// distributions) are missing some or all of these:
-#ifndef SYS_ACCEPT4
-#define SYS_ACCEPT4 18
-#endif
-#ifndef SYS_RECVMMSG
-#define SYS_RECVMMSG 19
-#endif
-#ifndef SYS_SENDMMSG
-#define SYS_SENDMMSG 20
-#endif
-
-using namespace sandbox::bpf_dsl;
-#define CASES SANDBOX_BPF_DSL_CASES
-
-namespace mozilla {
-
-sandbox::bpf_dsl::ResultExpr
-SandboxPolicyBase::EvaluateSyscall(int aSysno) const {
- switch (aSysno) {
-#ifdef __NR_socketcall
- case __NR_socketcall: {
- Arg<int> call(0);
- UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
- for (int i = SYS_SOCKET; i <= SYS_SENDMMSG; ++i) {
- auto thisCase = EvaluateSocketCall(i);
- // Optimize out cases that are equal to the default.
- if (thisCase) {
- acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
- }
- }
- return acc->Default(InvalidSyscall());
- }
-#ifndef ANDROID
- case __NR_ipc: {
- Arg<int> callAndVersion(0);
- auto call = callAndVersion & 0xFFFF;
- UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
- for (int i = SEMOP; i <= DIPC; ++i) {
- auto thisCase = EvaluateIpcCall(i);
- // Optimize out cases that are equal to the default.
- if (thisCase) {
- acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
- }
- }
- return acc->Default(InvalidSyscall());
- }
-#endif // ANDROID
-#endif // __NR_socketcall
-#define DISPATCH_SOCKETCALL(sysnum, socketnum) \
- case sysnum: \
- return EvaluateSocketCall(socketnum).valueOr(InvalidSyscall())
-#ifdef __NR_socket
- DISPATCH_SOCKETCALL(__NR_socket, SYS_SOCKET);
- DISPATCH_SOCKETCALL(__NR_bind, SYS_BIND);
- DISPATCH_SOCKETCALL(__NR_connect, SYS_CONNECT);
- DISPATCH_SOCKETCALL(__NR_listen, SYS_LISTEN);
-#ifdef __NR_accept
- DISPATCH_SOCKETCALL(__NR_accept, SYS_ACCEPT);
-#endif
- DISPATCH_SOCKETCALL(__NR_getsockname, SYS_GETSOCKNAME);
- DISPATCH_SOCKETCALL(__NR_getpeername, SYS_GETPEERNAME);
- DISPATCH_SOCKETCALL(__NR_socketpair, SYS_SOCKETPAIR);
-#ifdef __NR_send
- DISPATCH_SOCKETCALL(__NR_send, SYS_SEND);
- DISPATCH_SOCKETCALL(__NR_recv, SYS_RECV);
-#endif // __NR_send
- DISPATCH_SOCKETCALL(__NR_sendto, SYS_SENDTO);
- DISPATCH_SOCKETCALL(__NR_recvfrom, SYS_RECVFROM);
- DISPATCH_SOCKETCALL(__NR_shutdown, SYS_SHUTDOWN);
- DISPATCH_SOCKETCALL(__NR_setsockopt, SYS_SETSOCKOPT);
- DISPATCH_SOCKETCALL(__NR_getsockopt, SYS_GETSOCKOPT);
- DISPATCH_SOCKETCALL(__NR_sendmsg, SYS_SENDMSG);
- DISPATCH_SOCKETCALL(__NR_recvmsg, SYS_RECVMSG);
- DISPATCH_SOCKETCALL(__NR_accept4, SYS_ACCEPT4);
- DISPATCH_SOCKETCALL(__NR_recvmmsg, SYS_RECVMMSG);
- DISPATCH_SOCKETCALL(__NR_sendmmsg, SYS_SENDMMSG);
-#endif // __NR_socket
-#undef DISPATCH_SOCKETCALL
-#ifndef __NR_socketcall
-#ifndef ANDROID
-#define DISPATCH_SYSVCALL(sysnum, ipcnum) \
- case sysnum: \
- return EvaluateIpcCall(ipcnum).valueOr(InvalidSyscall())
- DISPATCH_SYSVCALL(__NR_semop, SEMOP);
- DISPATCH_SYSVCALL(__NR_semget, SEMGET);
- DISPATCH_SYSVCALL(__NR_semctl, SEMCTL);
- DISPATCH_SYSVCALL(__NR_semtimedop, SEMTIMEDOP);
- DISPATCH_SYSVCALL(__NR_msgsnd, MSGSND);
- DISPATCH_SYSVCALL(__NR_msgrcv, MSGRCV);
- DISPATCH_SYSVCALL(__NR_msgget, MSGGET);
- DISPATCH_SYSVCALL(__NR_msgctl, MSGCTL);
- DISPATCH_SYSVCALL(__NR_shmat, SHMAT);
- DISPATCH_SYSVCALL(__NR_shmdt, SHMDT);
- DISPATCH_SYSVCALL(__NR_shmget, SHMGET);
- DISPATCH_SYSVCALL(__NR_shmctl, SHMCTL);
-#undef DISPATCH_SYSVCALL
-#endif // ANDROID
-#endif // __NR_socketcall
- default:
- return InvalidSyscall();
- }
-}
-
-}
diff --git a/security/sandbox/linux/SandboxFilterUtil.h b/security/sandbox/linux/SandboxFilterUtil.h
deleted file mode 100644
index fb9afa79f..000000000
--- a/security/sandbox/linux/SandboxFilterUtil.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- 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_SandboxFilterUtil_h
-#define mozilla_SandboxFilterUtil_h
-
-// This header file exists to hold helper code for SandboxFilter.cpp,
-// to make that file easier to read for anyone trying to understand
-// the filter policy. It's mostly about smoothing out differences
-// between different Linux architectures.
-
-#include "mozilla/Maybe.h"
-#include "sandbox/linux/bpf_dsl/policy.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-namespace mozilla {
-
-// This class handles syscalls for BSD socket and SysV IPC operations.
-// On 32-bit x86 they're multiplexed via socketcall(2) and ipc(2),
-// respectively; on most other architectures they're individual system
-// calls. It translates the syscalls into socketcall/ipc selector
-// values, because those are defined (even if not used) for all
-// architectures.
-//
-// This EvaluateSyscall() routine always returns InvalidSyscall() for
-// everything else. It's assumed that subclasses will be implementing
-// a whitelist policy, so they can handle what they're whitelisting
-// and then defer to this class in the default case.
-class SandboxPolicyBase : public sandbox::bpf_dsl::Policy
-{
-public:
- using ResultExpr = sandbox::bpf_dsl::ResultExpr;
-
- virtual ResultExpr EvaluateSyscall(int aSysno) const override;
- virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const {
- return Nothing();
- }
-#ifndef ANDROID
- // Android doesn't use SysV IPC (and doesn't define the selector
- // constants in its headers), so this isn't implemented there.
- virtual Maybe<ResultExpr> EvaluateIpcCall(int aCall) const {
- return Nothing();
- }
-#endif
-
-#ifdef __NR_socketcall
- // socketcall(2) takes the actual call's arguments via a pointer, so
- // seccomp-bpf can't inspect them; ipc(2) takes them at different indices.
- static const bool kSocketCallHasArgs = false;
- static const bool kIpcCallNormalArgs = false;
-#else
- // Otherwise, the bpf_dsl Arg<> class can be used normally.
- static const bool kSocketCallHasArgs = true;
- static const bool kIpcCallNormalArgs = true;
-#endif
-};
-
-} // namespace mozilla
-
-// "Machine independent" pseudo-syscall numbers, to deal with arch
-// dependencies. (Most 32-bit archs started with 32-bit off_t; older
-// archs started with 16-bit uid_t/gid_t; 32-bit registers can't hold
-// a 64-bit offset for mmap; and so on.)
-//
-// For some of these, the "old" syscalls are also in use in some
-// cases; see, e.g., the handling of RT vs. non-RT signal syscalls.
-
-#ifdef __NR_mmap2
-#define CASES_FOR_mmap case __NR_mmap2
-#else
-#define CASES_FOR_mmap case __NR_mmap
-#endif
-
-#ifdef __NR_fchown32
-#define CASES_FOR_fchown case __NR_fchown32: case __NR_fchown
-#else
-#define CASES_FOR_fchown case __NR_fchown
-#endif
-
-#ifdef __NR_getuid32
-#define CASES_FOR_getuid case __NR_getuid32
-#define CASES_FOR_getgid case __NR_getgid32
-#define CASES_FOR_geteuid case __NR_geteuid32
-#define CASES_FOR_getegid case __NR_getegid32
-#define CASES_FOR_getresuid case __NR_getresuid32: case __NR_getresuid
-#define CASES_FOR_getresgid case __NR_getresgid32: case __NR_getresgid
-// The set*id syscalls are omitted; we'll probably never need to allow them.
-#else
-#define CASES_FOR_getuid case __NR_getuid
-#define CASES_FOR_getgid case __NR_getgid
-#define CASES_FOR_geteuid case __NR_geteuid
-#define CASES_FOR_getegid case __NR_getegid
-#define CASES_FOR_getresuid case __NR_getresuid
-#define CASES_FOR_getresgid case __NR_getresgid
-#endif
-
-#ifdef __NR_stat64
-#define CASES_FOR_stat case __NR_stat64
-#define CASES_FOR_lstat case __NR_lstat64
-#define CASES_FOR_fstat case __NR_fstat64
-#define CASES_FOR_fstatat case __NR_fstatat64
-#define CASES_FOR_statfs case __NR_statfs64: case __NR_statfs
-#define CASES_FOR_fstatfs case __NR_fstatfs64: case __NR_fstatfs
-#define CASES_FOR_fcntl case __NR_fcntl64
-// We're using the 32-bit version on 32-bit desktop for some reason.
-#define CASES_FOR_getdents case __NR_getdents64: case __NR_getdents
-// FIXME: we might not need the compat cases for these on non-Android:
-#define CASES_FOR_lseek case __NR_lseek: case __NR__llseek
-#define CASES_FOR_ftruncate case __NR_ftruncate: case __NR_ftruncate64
-#else
-#define CASES_FOR_stat case __NR_stat
-#define CASES_FOR_lstat case __NR_lstat
-#define CASES_FOR_fstatat case __NR_newfstatat
-#define CASES_FOR_fstat case __NR_fstat
-#define CASES_FOR_fstatfs case __NR_fstatfs
-#define CASES_FOR_statfs case __NR_statfs
-#define CASES_FOR_fcntl case __NR_fcntl
-#define CASES_FOR_getdents case __NR_getdents
-#define CASES_FOR_lseek case __NR_lseek
-#define CASES_FOR_ftruncate case __NR_ftruncate
-#endif
-
-#ifdef __NR_sigprocmask
-#define CASES_FOR_sigprocmask case __NR_sigprocmask: case __NR_rt_sigprocmask
-#define CASES_FOR_sigaction case __NR_sigaction: case __NR_rt_sigaction
-#define CASES_FOR_sigreturn case __NR_sigreturn: case __NR_rt_sigreturn
-#else
-#define CASES_FOR_sigprocmask case __NR_rt_sigprocmask
-#define CASES_FOR_sigaction case __NR_rt_sigaction
-#define CASES_FOR_sigreturn case __NR_rt_sigreturn
-#endif
-
-#ifdef __NR__newselect
-#define CASES_FOR_select case __NR__newselect
-#else
-#define CASES_FOR_select case __NR_select
-#endif
-
-#ifdef __NR_ugetrlimit
-#define CASES_FOR_getrlimit case __NR_ugetrlimit
-#else
-#define CASES_FOR_getrlimit case __NR_getrlimit
-#endif
-
-#endif // mozilla_SandboxFilterUtil_h
diff --git a/security/sandbox/linux/SandboxHooks.cpp b/security/sandbox/linux/SandboxHooks.cpp
deleted file mode 100644
index eaaf56982..000000000
--- a/security/sandbox/linux/SandboxHooks.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- 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 <dlfcn.h>
-#include <signal.h>
-#include <errno.h>
-
-#include "mozilla/Types.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-// Signal number used to enable seccomp on each thread.
-extern int gSeccompTsyncBroadcastSignum;
-
-// This file defines a hook for sigprocmask() and pthread_sigmask().
-// Bug 1176099: some threads block SIGSYS signal which breaks our seccomp-bpf
-// sandbox. To avoid this, we intercept the call and remove SIGSYS.
-//
-// ENOSYS indicates an error within the hook function itself.
-static int HandleSigset(int (*aRealFunc)(int, const sigset_t*, sigset_t*),
- int aHow, const sigset_t* aSet,
- sigset_t* aOldSet, bool aUseErrno)
-{
- if (!aRealFunc) {
- if (aUseErrno) {
- errno = ENOSYS;
- return -1;
- }
-
- return ENOSYS;
- }
-
- // Avoid unnecessary work
- if (aSet == NULL || aHow == SIG_UNBLOCK) {
- return aRealFunc(aHow, aSet, aOldSet);
- }
-
- sigset_t newSet = *aSet;
- if (sigdelset(&newSet, SIGSYS) != 0 ||
- (gSeccompTsyncBroadcastSignum &&
- sigdelset(&newSet, gSeccompTsyncBroadcastSignum) != 0)) {
- if (aUseErrno) {
- errno = ENOSYS;
- return -1;
- }
-
- return ENOSYS;
- }
-
- return aRealFunc(aHow, &newSet, aOldSet);
-}
-
-extern "C" MOZ_EXPORT int
-sigprocmask(int how, const sigset_t* set, sigset_t* oldset)
-{
- static auto sRealFunc = (int (*)(int, const sigset_t*, sigset_t*))
- dlsym(RTLD_NEXT, "sigprocmask");
-
- return HandleSigset(sRealFunc, how, set, oldset, true);
-}
-
-extern "C" MOZ_EXPORT int
-pthread_sigmask(int how, const sigset_t* set, sigset_t* oldset)
-{
- static auto sRealFunc = (int (*)(int, const sigset_t*, sigset_t*))
- dlsym(RTLD_NEXT, "pthread_sigmask");
-
- return HandleSigset(sRealFunc, how, set, oldset, false);
-}
diff --git a/security/sandbox/linux/SandboxInfo.cpp b/security/sandbox/linux/SandboxInfo.cpp
deleted file mode 100644
index 2eb65e39c..000000000
--- a/security/sandbox/linux/SandboxInfo.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/* -*- 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 "SandboxInfo.h"
-#include "SandboxLogging.h"
-#include "LinuxSched.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "base/posix/eintr_wrapper.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/ArrayUtils.h"
-#include "sandbox/linux/system_headers/linux_seccomp.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-#ifdef MOZ_VALGRIND
-#include <valgrind/valgrind.h>
-#endif
-
-
-// A note about assertions: in general, the worst thing this module
-// should be able to do is disable sandboxing features, so release
-// asserts or MOZ_CRASH should be avoided, even for seeming
-// impossibilities like an unimplemented syscall returning success
-// (which has happened: https://crbug.com/439795 ).
-//
-// MOZ_DIAGNOSTIC_ASSERT (debug builds, plus Nightly/Aurora non-debug)
-// is probably the best choice for conditions that shouldn't be able
-// to fail without the help of bugs in the kernel or system libraries.
-//
-// Regardless of assertion type, whatever condition caused it to fail
-// should generally also disable the corresponding feature on builds
-// that omit the assertion.
-
-namespace mozilla {
-
-// Bug 1229136: this is copied from ../SandboxUtil.cpp to avoid
-// complicated build issues; renamespaced to avoid the possibility of
-// symbol conflict.
-namespace {
-
-static bool
-IsSingleThreaded()
-{
- // This detects the thread count indirectly. /proc/<pid>/task has a
- // subdirectory for each thread in <pid>'s thread group, and the
- // link count on the "task" directory follows Unix expectations: the
- // link from its parent, the "." link from itself, and the ".." link
- // from each subdirectory; thus, 2+N links for N threads.
- struct stat sb;
- if (stat("/proc/self/task", &sb) < 0) {
- MOZ_DIAGNOSTIC_ASSERT(false, "Couldn't access /proc/self/task!");
- return false;
- }
- MOZ_DIAGNOSTIC_ASSERT(sb.st_nlink >= 3);
- return sb.st_nlink == 3;
-}
-
-} // anonymous namespace
-
-static bool
-HasSeccompBPF()
-{
- // Allow simulating the absence of seccomp-bpf support, for testing.
- if (getenv("MOZ_FAKE_NO_SANDBOX")) {
- return false;
- }
-
- // Valgrind and the sandbox don't interact well, probably because Valgrind
- // does various system calls which aren't allowed, even if Firefox itself
- // is playing by the rules.
-# if defined(MOZ_VALGRIND)
- if (RUNNING_ON_VALGRIND) {
- return false;
- }
-# endif
-
- // 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.
-
- int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
- MOZ_DIAGNOSTIC_ASSERT(rv == -1, "prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,"
- " nullptr) didn't fail");
- MOZ_DIAGNOSTIC_ASSERT(errno == EFAULT || errno == EINVAL);
- return rv == -1 && errno == EFAULT;
-}
-
-static bool
-HasSeccompTSync()
-{
- // Similar to above, but for thread-sync mode. See also Chromium's
- // sandbox::SandboxBPF::SupportsSeccompThreadFilterSynchronization
- if (getenv("MOZ_FAKE_NO_SECCOMP_TSYNC")) {
- return false;
- }
- int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER,
- SECCOMP_FILTER_FLAG_TSYNC, nullptr);
- MOZ_DIAGNOSTIC_ASSERT(rv == -1, "seccomp(..., SECCOMP_FILTER_FLAG_TSYNC,"
- " nullptr) didn't fail");
- MOZ_DIAGNOSTIC_ASSERT(errno == EFAULT || errno == EINVAL || errno == ENOSYS);
- return rv == -1 && errno == EFAULT;
-}
-
-static bool
-HasUserNamespaceSupport()
-{
- // Note: the /proc/<pid>/ns/* files track setns(2) support, which in
- // some cases (e.g., pid) significantly postdates kernel support for
- // the namespace type, so in general this type of check could be a
- // false negative. However, for user namespaces, any kernel new
- // enough for the feature to be usable for us has setns support
- // (v3.8), so this is okay.
- //
- // The non-user namespaces all default to "y" in init/Kconfig, but
- // check them explicitly in case someone has a weird custom config.
- static const char* const paths[] = {
- "/proc/self/ns/user",
- "/proc/self/ns/pid",
- "/proc/self/ns/net",
- "/proc/self/ns/ipc",
- };
- for (size_t i = 0; i < ArrayLength(paths); ++i) {
- if (access(paths[i], F_OK) == -1) {
- MOZ_ASSERT(errno == ENOENT);
- return false;
- }
- }
- return true;
-}
-
-static bool
-CanCreateUserNamespace()
-{
- // Unfortunately, the only way to verify that this process can
- // create a new user namespace is to actually create one; because
- // this process's namespaces shouldn't be side-effected (yet), it's
- // necessary to clone (and collect) a child process. See also
- // Chromium's sandbox::Credentials::SupportsNewUserNS.
- //
- // This is somewhat more expensive than the other tests, so it's
- // cached in the environment to prevent child processes from having
- // to re-run the test.
- //
- // This is run at static initializer time, while single-threaded, so
- // locking isn't needed to access the environment.
- static const char kCacheEnvName[] = "MOZ_ASSUME_USER_NS";
- const char* cached = getenv(kCacheEnvName);
- if (cached) {
- return cached[0] > '0';
- }
-
- // Valgrind might allow the clone, but doesn't know what to do with
- // unshare. Check for that by unsharing nothing. (Valgrind will
- // probably need sandboxing disabled entirely, but no need to break
- // things worse than strictly necessary.)
- if (syscall(__NR_unshare, 0) != 0) {
-#ifdef MOZ_VALGRIND
- MOZ_ASSERT(errno == ENOSYS);
-#else
- // If something else can cause that call to fail, we's like to know
- // about it; the right way to handle it might not be the same.
- MOZ_ASSERT(false);
-#endif
- return false;
- }
-
- pid_t pid = syscall(__NR_clone, SIGCHLD | CLONE_NEWUSER,
- nullptr, nullptr, nullptr, nullptr);
- if (pid == 0) {
- // In the child. Do as little as possible.
- _exit(0);
- }
- if (pid == -1) {
- // Failure.
- MOZ_ASSERT(errno == EINVAL || // unsupported
- errno == EPERM || // root-only, or we're already chrooted
- errno == EUSERS); // already at user namespace nesting limit
- setenv(kCacheEnvName, "0", 1);
- return false;
- }
- // Otherwise, in the parent and successful.
- bool waitpid_ok = HANDLE_EINTR(waitpid(pid, nullptr, 0)) == pid;
- MOZ_ASSERT(waitpid_ok);
- if (!waitpid_ok) {
- return false;
- }
- setenv(kCacheEnvName, "1", 1);
- return true;
-}
-
-/* static */
-SandboxInfo SandboxInfo::sSingleton = SandboxInfo();
-
-SandboxInfo::SandboxInfo() {
- int flags = 0;
- static_assert(sizeof(flags) >= sizeof(Flags), "enum Flags fits in an int");
-
- if (HasSeccompBPF()) {
- flags |= kHasSeccompBPF;
- if (HasSeccompTSync()) {
- flags |= kHasSeccompTSync;
- }
- }
-
- // Detect the threading-problem signal from the parent process.
- if (getenv("MOZ_SANDBOX_UNEXPECTED_THREADS")) {
- flags |= kUnexpectedThreads;
- } else {
- if (HasUserNamespaceSupport()) {
- flags |= kHasPrivilegedUserNamespaces;
- if (CanCreateUserNamespace()) {
- flags |= kHasUserNamespaces;
- }
- }
- }
-
- if (getenv("MOZ_SANDBOX_VERBOSE")) {
- flags |= kVerbose;
- }
-
- mFlags = static_cast<Flags>(flags);
-}
-
-/* static */ void
-SandboxInfo::ThreadingCheck()
-{
- // Allow MOZ_SANDBOX_UNEXPECTED_THREADS to be set manually for testing.
- if (IsSingleThreaded() &&
- !getenv("MOZ_SANDBOX_UNEXPECTED_THREADS")) {
- return;
- }
- SANDBOX_LOG_ERROR("unexpected multithreading found; this prevents using"
- " namespace sandboxing.%s",
- // getenv isn't thread-safe, but see below.
- getenv("LD_PRELOAD") ? " (If you're LD_PRELOAD'ing"
- " nVidia GL: that's not necessary for Gecko.)" : "");
-
- // Propagate this information for use by child processes. (setenv
- // isn't thread-safe, but other threads are from non-Gecko code so
- // they wouldn't be using NSPR; we have to hope for the best.)
- setenv("MOZ_SANDBOX_UNEXPECTED_THREADS", "1", 0);
- int flags = sSingleton.mFlags;
- flags |= kUnexpectedThreads;
- flags &= ~(kHasUserNamespaces | kHasPrivilegedUserNamespaces);
- sSingleton.mFlags = static_cast<Flags>(flags);
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/SandboxInfo.h b/security/sandbox/linux/SandboxInfo.h
deleted file mode 100644
index 1999ac392..000000000
--- a/security/sandbox/linux/SandboxInfo.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- 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_SandboxInfo_h
-#define mozilla_SandboxInfo_h
-
-#include "mozilla/Types.h"
-
-// Information on what parts of sandboxing are enabled in this build
-// and/or supported by the system.
-
-namespace mozilla {
-
-class SandboxInfo {
-public:
- // No need to prevent copying; this is essentially just a const int.
- SandboxInfo(const SandboxInfo& aOther) : mFlags(aOther.mFlags) { }
-
- // Flags are checked at initializer time; this returns them.
- static const SandboxInfo& Get() { return sSingleton; }
-
- enum Flags {
- // System call filtering; kernel config option CONFIG_SECCOMP_FILTER.
- kHasSeccompBPF = 1 << 0,
- // Config flag MOZ_CONTENT_SANDBOX; env var MOZ_DISABLE_CONTENT_SANDBOX.
- kEnabledForContent = 1 << 1,
- // Config flag MOZ_GMP_SANDBOX; env var MOZ_DISABLE_GMP_SANDBOX.
- kEnabledForMedia = 1 << 2,
- // Env var MOZ_SANDBOX_VERBOSE.
- kVerbose = 1 << 3,
- // Kernel can atomically set system call filtering on entire thread group.
- kHasSeccompTSync = 1 << 4,
- // Can this process create user namespaces? (Man page user_namespaces(7).)
- kHasUserNamespaces = 1 << 5,
- // Could a more privileged process have user namespaces, even if we can't?
- kHasPrivilegedUserNamespaces = 1 << 6,
- // Env var MOZ_PERMISSIVE_CONTENT_SANDBOX
- kPermissive = 1 << 7,
- // Something is creating threads when we need to still be single-threaded.
- kUnexpectedThreads = 1 << 8,
- };
-
- bool Test(Flags aFlag) const { return (mFlags & aFlag) == aFlag; }
-
- // Returns true if SetContentProcessSandbox may be called.
- bool CanSandboxContent() const
- {
- return !Test(kEnabledForContent) || Test(kHasSeccompBPF);
- }
-
- // Returns true if SetMediaPluginSandbox may be called.
- bool CanSandboxMedia() const
- {
- return !Test(kEnabledForMedia) || Test(kHasSeccompBPF);
- }
-
- // For telemetry / crash annotation uses.
- uint32_t AsInteger() const {
- return mFlags;
- }
-
- // For bug 1222500 or anything else like it: On desktop, this is
- // called in the parent process at a point when it should still be
- // single-threaded, to check that the SandboxEarlyInit() call in a
- // child process is early enough to be single-threaded. If not,
- // kUnexpectedThreads is set and affected flags (user namespaces;
- // possibly others in the future) are cleared.
- static MOZ_EXPORT void ThreadingCheck();
-private:
- enum Flags mFlags;
- // This should be const, but has to allow for ThreadingCheck.
- static MOZ_EXPORT SandboxInfo sSingleton;
- SandboxInfo();
-};
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxInfo_h
diff --git a/security/sandbox/linux/SandboxInternal.h b/security/sandbox/linux/SandboxInternal.h
deleted file mode 100644
index 90a688421..000000000
--- a/security/sandbox/linux/SandboxInternal.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- 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_SandboxInternal_h
-#define mozilla_SandboxInternal_h
-
-#include <signal.h>
-
-#include "mozilla/Types.h"
-
-struct sock_fprog;
-
-namespace mozilla {
-
-// SandboxCrash() has to be in libxul to use internal interfaces, but
-// its caller in libmozsandbox.
-// See also bug 1101170.
-
-typedef void (*SandboxCrashFunc)(int, siginfo_t*, void*);
-extern MOZ_EXPORT SandboxCrashFunc gSandboxCrashFunc;
-extern const sock_fprog* gSetSandboxFilter;
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxInternal_h
diff --git a/security/sandbox/linux/SandboxLogging.cpp b/security/sandbox/linux/SandboxLogging.cpp
deleted file mode 100644
index 19196a75a..000000000
--- a/security/sandbox/linux/SandboxLogging.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- 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 "SandboxLogging.h"
-
-#ifdef ANDROID
-#include <android/log.h>
-#endif
-#include <algorithm>
-#include <stdio.h>
-#include <string.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include "base/posix/eintr_wrapper.h"
-
-namespace mozilla {
-
-// Alters an iovec array to remove the first `toDrop` bytes. This
-// complexity is necessary because writev can return a short write
-// (e.g., if stderr is a pipe and the buffer is almost full).
-static void
-IOVecDrop(struct iovec* iov, int iovcnt, size_t toDrop)
-{
- while (toDrop > 0 && iovcnt > 0) {
- size_t toDropHere = std::min(toDrop, iov->iov_len);
- iov->iov_base = static_cast<char*>(iov->iov_base) + toDropHere;
- iov->iov_len -= toDropHere;
- toDrop -= toDropHere;
- ++iov;
- --iovcnt;
- }
-}
-
-void
-SandboxLogError(const char* message)
-{
-#ifdef ANDROID
- // This uses writev internally and appears to be async signal safe.
- __android_log_write(ANDROID_LOG_ERROR, "Sandbox", message);
-#endif
- static const char logPrefix[] = "Sandbox: ", logSuffix[] = "\n";
- struct iovec iovs[3] = {
- { const_cast<char*>(logPrefix), sizeof(logPrefix) - 1 },
- { const_cast<char*>(message), strlen(message) },
- { const_cast<char*>(logSuffix), sizeof(logSuffix) - 1 },
- };
- while (iovs[2].iov_len > 0) {
- ssize_t written = HANDLE_EINTR(writev(STDERR_FILENO, iovs, 3));
- if (written <= 0) {
- break;
- }
- IOVecDrop(iovs, 3, static_cast<size_t>(written));
- }
-}
-
-}
diff --git a/security/sandbox/linux/SandboxLogging.h b/security/sandbox/linux/SandboxLogging.h
deleted file mode 100644
index 88891adfb..000000000
--- a/security/sandbox/linux/SandboxLogging.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- 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_SandboxLogging_h
-#define mozilla_SandboxLogging_h
-
-// This header defines the SANDBOX_LOG_ERROR macro used in the Linux
-// sandboxing code. It uses Android logging on Android and writes to
-// stderr otherwise. Android logging has severity levels; currently
-// only "error" severity is exposed here, and this isn't marked when
-// writing to stderr.
-//
-// The format strings are processed by Chromium SafeSPrintf, which
-// doesn't accept size modifiers or %u because it uses C++11 variadic
-// templates to obtain the actual argument types; all decimal integer
-// formatting uses %d. See safe_sprintf.h for more details.
-
-// Build SafeSPrintf without assertions to avoid a dependency on
-// Chromium logging. This doesn't affect safety; it just means that
-// type mismatches (pointer vs. integer) always result in unexpanded
-// %-directives instead of crashing. See also the moz.build files,
-// which apply NDEBUG to the .cc file.
-#ifndef NDEBUG
-#define NDEBUG 1
-#include "base/strings/safe_sprintf.h"
-#undef NDEBUG
-#else
-#include "base/strings/safe_sprintf.h"
-#endif
-
-namespace mozilla {
-// Logs the formatted string (marked with "error" severity, if supported).
-void SandboxLogError(const char* aMessage);
-}
-
-#define SANDBOX_LOG_LEN 256
-
-// Formats a log message and logs it (with "error" severity, if supported).
-//
-// Note that SafeSPrintf doesn't accept size modifiers or %u; all
-// decimal integers are %d, because it uses C++11 variadic templates
-// to use the actual argument type.
-#define SANDBOX_LOG_ERROR(fmt, args...) do { \
- char _sandboxLogBuf[SANDBOX_LOG_LEN]; \
- ::base::strings::SafeSPrintf(_sandboxLogBuf, fmt, ## args); \
- ::mozilla::SandboxLogError(_sandboxLogBuf); \
-} while(0)
-
-#endif // mozilla_SandboxLogging_h
diff --git a/security/sandbox/linux/SandboxUtil.cpp b/security/sandbox/linux/SandboxUtil.cpp
deleted file mode 100644
index 999329882..000000000
--- a/security/sandbox/linux/SandboxUtil.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/* -*- 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 "SandboxUtil.h"
-
-#include "LinuxCapabilities.h"
-#include "LinuxSched.h"
-#include "SandboxLogging.h"
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "mozilla/Assertions.h"
-#include "mozilla/Sprintf.h"
-#include "mozilla/Unused.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-namespace mozilla {
-
-bool
-IsSingleThreaded()
-{
- // This detects the thread count indirectly. /proc/<pid>/task has a
- // subdirectory for each thread in <pid>'s thread group, and the
- // link count on the "task" directory follows Unix expectations: the
- // link from its parent, the "." link from itself, and the ".." link
- // from each subdirectory; thus, 2+N links for N threads.
- struct stat sb;
- if (stat("/proc/self/task", &sb) < 0) {
- MOZ_DIAGNOSTIC_ASSERT(false, "Couldn't access /proc/self/task!");
- return false;
- }
- MOZ_DIAGNOSTIC_ASSERT(sb.st_nlink >= 3);
- return sb.st_nlink == 3;
-}
-
-static bool
-WriteStringToFile(const char* aPath, const char* aStr, const size_t aLen)
-{
- int fd = open(aPath, O_WRONLY);
- if (fd < 0) {
- return false;
- }
- ssize_t written = write(fd, aStr, aLen);
- if (close(fd) != 0 || written != ssize_t(aLen)) {
- return false;
- }
- return true;
-}
-
-bool
-UnshareUserNamespace()
-{
- // The uid and gid need to be retrieved before the unshare; see
- // below.
- uid_t uid = getuid();
- gid_t gid = getgid();
- char buf[80];
-
- if (syscall(__NR_unshare, CLONE_NEWUSER) != 0) {
- return false;
- }
-
- // As mentioned in the header, this function sets up uid/gid
- // mappings that preserve the process's previous ids. Mapping the
- // uid/gid to something is necessary in order to nest user
- // namespaces (not used yet, but we'll need this in the future for
- // pid namespace support), and leaving the ids unchanged is the
- // least confusing option.
- //
- // In recent kernels (3.19, 3.18.2, 3.17.8), for security reasons,
- // establishing gid mappings will fail unless the process first
- // revokes its ability to call setgroups() by using a /proc node
- // added in the same set of patches.
- //
- // Note that /proc/self points to the thread group leader, not the
- // current thread. However, CLONE_NEWUSER can be unshared only in a
- // single-threaded process, so those are equivalent if we reach this
- // point.
- int len = SprintfLiteral(buf, "%u %u 1\n", uid, uid);
- if (len >= int(sizeof(buf)) || len < 0) {
- return false;
- }
- if (!WriteStringToFile("/proc/self/uid_map", buf, size_t(len))) {
- MOZ_CRASH("Failed to write /proc/self/uid_map");
- }
-
- Unused << WriteStringToFile("/proc/self/setgroups", "deny", 4);
-
- len = SprintfLiteral(buf, "%u %u 1\n", gid, gid);
- if (len >= int(sizeof(buf)) || len < 0) {
- return false;
- }
- if (!WriteStringToFile("/proc/self/gid_map", buf, size_t(len))) {
- MOZ_CRASH("Failed to write /proc/self/gid_map");
- }
- return true;
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/SandboxUtil.h b/security/sandbox/linux/SandboxUtil.h
deleted file mode 100644
index 7bd84f798..000000000
--- a/security/sandbox/linux/SandboxUtil.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- 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_SandboxUtil_h
-#define mozilla_SandboxUtil_h
-
-namespace mozilla {
-
-bool IsSingleThreaded();
-
-// Unshare the user namespace, and set up id mappings so that the
-// process's subjective uid and gid are unchanged. This will always
-// fail if the process is multithreaded.
-bool UnshareUserNamespace();
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxUtil_h
diff --git a/security/sandbox/linux/broker/SandboxBroker.cpp b/security/sandbox/linux/broker/SandboxBroker.cpp
deleted file mode 100644
index a31d1fc66..000000000
--- a/security/sandbox/linux/broker/SandboxBroker.cpp
+++ /dev/null
@@ -1,731 +0,0 @@
-/* -*- 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 "SandboxBroker.h"
-#include "SandboxInfo.h"
-#include "SandboxLogging.h"
-#include "SandboxBrokerUtils.h"
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#ifdef XP_LINUX
-#include <sys/prctl.h>
-#endif
-
-#ifdef MOZ_WIDGET_GONK
-#include <private/android_filesystem_config.h>
-#include <sys/syscall.h>
-#endif
-
-#include "mozilla/Assertions.h"
-#include "mozilla/DebugOnly.h"
-#include "mozilla/Move.h"
-#include "mozilla/NullPtr.h"
-#include "mozilla/Sprintf.h"
-#include "mozilla/ipc/FileDescriptor.h"
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-namespace mozilla {
-
-// This constructor signals failure by setting mFileDesc and aClientFd to -1.
-SandboxBroker::SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
- int& aClientFd)
- : mChildPid(aChildPid), mPolicy(Move(aPolicy))
-{
- int fds[2];
- if (0 != socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)) {
- SANDBOX_LOG_ERROR("SandboxBroker: socketpair failed: %s", strerror(errno));
- mFileDesc = -1;
- aClientFd = -1;
- return;
- }
- mFileDesc = fds[0];
- aClientFd = fds[1];
-
- if (!PlatformThread::Create(0, this, &mThread)) {
- SANDBOX_LOG_ERROR("SandboxBroker: thread creation failed: %s",
- strerror(errno));
- close(mFileDesc);
- close(aClientFd);
- mFileDesc = -1;
- aClientFd = -1;
- }
-}
-
-UniquePtr<SandboxBroker>
-SandboxBroker::Create(UniquePtr<const Policy> aPolicy, int aChildPid,
- ipc::FileDescriptor& aClientFdOut)
-{
- int clientFd;
- // Can't use MakeUnique here because the constructor is private.
- UniquePtr<SandboxBroker> rv(new SandboxBroker(Move(aPolicy), aChildPid,
- clientFd));
- if (clientFd < 0) {
- rv = nullptr;
- } else {
- aClientFdOut = ipc::FileDescriptor(clientFd);
- }
- return Move(rv);
-}
-
-SandboxBroker::~SandboxBroker() {
- // If the constructor failed, there's nothing to be done here.
- if (mFileDesc < 0) {
- return;
- }
-
- shutdown(mFileDesc, SHUT_RD);
- // The thread will now get EOF even if the client hasn't exited.
- PlatformThread::Join(mThread);
- // Now that the thread has exited, the fd will no longer be accessed.
- close(mFileDesc);
- // Having ensured that this object outlives the thread, this
- // destructor can now return.
-}
-
-SandboxBroker::Policy::Policy() { }
-SandboxBroker::Policy::~Policy() { }
-
-SandboxBroker::Policy::Policy(const Policy& aOther) {
- for (auto iter = aOther.mMap.ConstIter(); !iter.Done(); iter.Next()) {
- mMap.Put(iter.Key(), iter.Data());
- }
-}
-
-// Chromium
-// sandbox/linux/syscall_broker/broker_file_permission.cc
-// Async signal safe
-bool
-SandboxBroker::Policy::ValidatePath(const char* path) const {
- if (!path)
- return false;
-
- const size_t len = strlen(path);
- // No empty paths
- if (len == 0)
- return false;
- // Paths must be absolute and not relative
- if (path[0] != '/')
- return false;
- // No trailing / (but "/" is valid)
- if (len > 1 && path[len - 1] == '/')
- return false;
- // No trailing /.
- if (len >= 2 && path[len - 2] == '/' && path[len - 1] == '.')
- return false;
- // No trailing /..
- if (len >= 3 && path[len - 3] == '/' && path[len - 2] == '.' &&
- path[len - 1] == '.')
- return false;
- // No /../ anywhere
- for (size_t i = 0; i < len; i++) {
- if (path[i] == '/' && (len - i) > 3) {
- if (path[i + 1] == '.' && path[i + 2] == '.' && path[i + 3] == '/') {
- return false;
- }
- }
- }
- return true;
-}
-
-void
-SandboxBroker::Policy::AddPath(int aPerms, const char* aPath,
- AddCondition aCond)
-{
- nsDependentCString path(aPath);
- MOZ_ASSERT(path.Length() <= kMaxPathLen);
- int perms;
- if (aCond == AddIfExistsNow) {
- struct stat statBuf;
- if (lstat(aPath, &statBuf) != 0) {
- return;
- }
- }
- if (!mMap.Get(path, &perms)) {
- perms = MAY_ACCESS;
- } else {
- MOZ_ASSERT(perms & MAY_ACCESS);
- }
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("policy for %s: %d -> %d", aPath, perms, perms | aPerms);
- }
- perms |= aPerms;
- mMap.Put(path, perms);
-}
-
-void
-SandboxBroker::Policy::AddTree(int aPerms, const char* aPath)
-{
- struct stat statBuf;
-
- if (stat(aPath, &statBuf) != 0) {
- return;
- }
- if (!S_ISDIR(statBuf.st_mode)) {
- AddPath(aPerms, aPath, AddAlways);
- } else {
- DIR* dirp = opendir(aPath);
- if (!dirp) {
- return;
- }
- while (struct dirent* de = readdir(dirp)) {
- if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) {
- continue;
- }
- // Note: could optimize the string handling.
- nsAutoCString subPath;
- subPath.Assign(aPath);
- subPath.Append('/');
- subPath.Append(de->d_name);
- AddTree(aPerms, subPath.get());
- }
- closedir(dirp);
- }
-}
-
-void
-SandboxBroker::Policy::AddDir(int aPerms, const char* aPath)
-{
- struct stat statBuf;
-
- if (stat(aPath, &statBuf) != 0) {
- return;
- }
-
- if (!S_ISDIR(statBuf.st_mode)) {
- return;
- }
-
- nsDependentCString path(aPath);
- MOZ_ASSERT(path.Length() <= kMaxPathLen - 1);
- // Enforce trailing / on aPath
- if (path[path.Length() - 1] != '/') {
- path.Append('/');
- }
- int origPerms;
- if (!mMap.Get(path, &origPerms)) {
- origPerms = MAY_ACCESS;
- } else {
- MOZ_ASSERT(origPerms & MAY_ACCESS);
- }
- int newPerms = origPerms | aPerms | RECURSIVE;
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("policy for %s: %d -> %d", aPath, origPerms, newPerms);
- }
- mMap.Put(path, newPerms);
-}
-
-void
-SandboxBroker::Policy::AddPrefix(int aPerms, const char* aDir,
- const char* aPrefix)
-{
- size_t prefixLen = strlen(aPrefix);
- DIR* dirp = opendir(aDir);
- struct dirent* de;
- if (!dirp) {
- return;
- }
- while ((de = readdir(dirp))) {
- if (strncmp(de->d_name, aPrefix, prefixLen) == 0) {
- nsAutoCString subPath;
- subPath.Assign(aDir);
- subPath.Append('/');
- subPath.Append(de->d_name);
- AddPath(aPerms, subPath.get(), AddAlways);
- }
- }
- closedir(dirp);
-}
-
-int
-SandboxBroker::Policy::Lookup(const nsACString& aPath) const
-{
- // Early exit for paths explicitly found in the
- // whitelist.
- // This means they will not gain extra permissions
- // from recursive paths.
- int perms = mMap.Get(aPath);
- if (perms) {
- return perms;
- }
-
- // Not a legally constructed path
- if (!ValidatePath(PromiseFlatCString(aPath).get()))
- return 0;
-
- // Now it's either an illegal access, or a recursive
- // directory permission. We'll have to check the entire
- // whitelist for the best match (slower).
- int allPerms = 0;
- for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
- const nsACString& whiteListPath = iter.Key();
- const int& perms = iter.Data();
-
- if (!(perms & RECURSIVE))
- continue;
-
- // passed part starts with something on the whitelist
- if (StringBeginsWith(aPath, whiteListPath)) {
- allPerms |= perms;
- }
- }
-
- // Strip away the RECURSIVE flag as it doesn't
- // necessarily apply to aPath.
- return allPerms & ~RECURSIVE;
-}
-
-static bool
-AllowOperation(int aReqFlags, int aPerms)
-{
- int needed = 0;
- if (aReqFlags & R_OK) {
- needed |= SandboxBroker::MAY_READ;
- }
- if (aReqFlags & W_OK) {
- needed |= SandboxBroker::MAY_WRITE;
- }
- // We don't really allow executing anything,
- // so in true unix tradition we hijack this
- // for directories.
- if (aReqFlags & X_OK) {
- needed |= SandboxBroker::MAY_CREATE;
- }
- return (aPerms & needed) == needed;
-}
-
-static bool
-AllowAccess(int aReqFlags, int aPerms)
-{
- if (aReqFlags & ~(R_OK|W_OK|F_OK)) {
- return false;
- }
- int needed = 0;
- if (aReqFlags & R_OK) {
- needed |= SandboxBroker::MAY_READ;
- }
- if (aReqFlags & W_OK) {
- needed |= SandboxBroker::MAY_WRITE;
- }
- return (aPerms & needed) == needed;
-}
-
-// These flags are added to all opens to prevent possible side-effects
-// on this process. These shouldn't be relevant to the child process
-// in any case due to the sandboxing restrictions on it. (See also
-// the use of MSG_CMSG_CLOEXEC in SandboxBrokerCommon.cpp).
-static const int kRequiredOpenFlags = O_CLOEXEC | O_NOCTTY;
-
-// Linux originally assigned a flag bit to O_SYNC but implemented the
-// semantics standardized as O_DSYNC; later, that bit was renamed and
-// a new bit was assigned to the full O_SYNC, and O_SYNC was redefined
-// to be both bits. As a result, this #define is needed to compensate
-// for outdated kernel headers like Android's.
-#define O_SYNC_NEW 04010000
-static const int kAllowedOpenFlags =
- O_APPEND | O_ASYNC | O_DIRECT | O_DIRECTORY | O_EXCL | O_LARGEFILE
- | O_NOATIME | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_NDELAY | O_SYNC_NEW
- | O_TRUNC | O_CLOEXEC | O_CREAT;
-#undef O_SYNC_NEW
-
-static bool
-AllowOpen(int aReqFlags, int aPerms)
-{
- if (aReqFlags & ~O_ACCMODE & ~kAllowedOpenFlags) {
- return false;
- }
- int needed;
- switch(aReqFlags & O_ACCMODE) {
- case O_RDONLY:
- needed = SandboxBroker::MAY_READ;
- break;
- case O_WRONLY:
- needed = SandboxBroker::MAY_WRITE;
- break;
- case O_RDWR:
- needed = SandboxBroker::MAY_READ | SandboxBroker::MAY_WRITE;
- break;
- default:
- return false;
- }
- if (aReqFlags & O_CREAT) {
- needed |= SandboxBroker::MAY_CREATE;
- }
- return (aPerms & needed) == needed;
-}
-
-static int
-DoStat(const char* aPath, void* aBuff, int aFlags)
-{
- if (aFlags & O_NOFOLLOW) {
- return lstatsyscall(aPath, (statstruct*)aBuff);
- }
- return statsyscall(aPath, (statstruct*)aBuff);
-}
-
-static int
-DoLink(const char* aPath, const char* aPath2,
- SandboxBrokerCommon::Operation aOper)
-{
- if (aOper == SandboxBrokerCommon::Operation::SANDBOX_FILE_LINK) {
- return link(aPath, aPath2);
- } else if (aOper == SandboxBrokerCommon::Operation::SANDBOX_FILE_SYMLINK) {
- return symlink(aPath, aPath2);
- }
- MOZ_CRASH("SandboxBroker: Unknown link operation");
-}
-
-size_t
-SandboxBroker::ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen)
-{
- if (strstr(aPath, "..") != NULL) {
- char* result = realpath(aPath, NULL);
- if (result != NULL) {
- strncpy(aPath, result, aBufSize);
- aPath[aBufSize - 1] = '\0';
- free(result);
- // Size changed, but guaranteed to be 0 terminated
- aPathLen = strlen(aPath);
- }
- // ValidatePath will handle failure to translate
- }
- return aPathLen;
-}
-
-void
-SandboxBroker::ThreadMain(void)
-{
- char threadName[16];
- SprintfLiteral(threadName, "FS Broker %d", mChildPid);
- PlatformThread::SetName(threadName);
-
- // Permissive mode can only be enabled through an environment variable,
- // therefore it is sufficient to fetch the value once
- // before the main thread loop starts
- bool permissive = SandboxInfo::Get().Test(SandboxInfo::kPermissive);
-
-#ifdef MOZ_WIDGET_GONK
-#ifdef __NR_setreuid32
- static const long nr_setreuid = __NR_setreuid32;
- static const long nr_setregid = __NR_setregid32;
-#else
- static const long nr_setreuid = __NR_setreuid;
- static const long nr_setregid = __NR_setregid;
-#endif
- if (syscall(nr_setregid, getgid(), AID_APP + mChildPid) != 0 ||
- syscall(nr_setreuid, getuid(), AID_APP + mChildPid) != 0) {
- MOZ_CRASH("SandboxBroker: failed to drop privileges");
- }
-#endif
-
- while (true) {
- struct iovec ios[2];
- // We will receive the path strings in 1 buffer and split them back up.
- char recvBuf[2 * (kMaxPathLen + 1)];
- char pathBuf[kMaxPathLen + 1];
- char pathBuf2[kMaxPathLen + 1];
- size_t pathLen;
- size_t pathLen2;
- char respBuf[kMaxPathLen + 1]; // Also serves as struct stat
- Request req;
- Response resp;
- int respfd;
-
- // Make sure stat responses fit in the response buffer
- MOZ_ASSERT((kMaxPathLen + 1) > sizeof(struct stat));
-
- // This makes our string handling below a bit less error prone.
- memset(recvBuf, 0, sizeof(recvBuf));
-
- ios[0].iov_base = &req;
- ios[0].iov_len = sizeof(req);
- ios[1].iov_base = recvBuf;
- ios[1].iov_len = sizeof(recvBuf);
-
- const ssize_t recvd = RecvWithFd(mFileDesc, ios, 2, &respfd);
- if (recvd == 0) {
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("EOF from pid %d", mChildPid);
- }
- break;
- }
- // It could be possible to continue after errors and short reads,
- // at least in some cases, but protocol violation indicates a
- // hostile client, so terminate the broker instead.
- if (recvd < 0) {
- SANDBOX_LOG_ERROR("bad read from pid %d: %s",
- mChildPid, strerror(errno));
- shutdown(mFileDesc, SHUT_RD);
- break;
- }
- if (recvd < static_cast<ssize_t>(sizeof(req))) {
- SANDBOX_LOG_ERROR("bad read from pid %d (%d < %d)",
- mChildPid, recvd, sizeof(req));
- shutdown(mFileDesc, SHUT_RD);
- break;
- }
- if (respfd == -1) {
- SANDBOX_LOG_ERROR("no response fd from pid %d", mChildPid);
- shutdown(mFileDesc, SHUT_RD);
- break;
- }
-
- // Initialize the response with the default failure.
- memset(&resp, 0, sizeof(resp));
- memset(&respBuf, 0, sizeof(respBuf));
- resp.mError = -EACCES;
- ios[0].iov_base = &resp;
- ios[0].iov_len = sizeof(resp);
- ios[1].iov_base = nullptr;
- ios[1].iov_len = 0;
- int openedFd = -1;
-
- // Clear permissions
- int perms;
-
- // Find end of first string, make sure the buffer is still
- // 0 terminated.
- size_t recvBufLen = static_cast<size_t>(recvd) - sizeof(req);
- if (recvBufLen > 0 && recvBuf[recvBufLen - 1] != 0) {
- SANDBOX_LOG_ERROR("corrupted path buffer from pid %d", mChildPid);
- shutdown(mFileDesc, SHUT_RD);
- break;
- }
-
- // First path should fit in maximum path length buffer.
- size_t first_len = strlen(recvBuf);
- if (first_len <= kMaxPathLen) {
- strcpy(pathBuf, recvBuf);
- // Skip right over the terminating 0, and try to copy in the
- // second path, if any. If there's no path, this will hit a
- // 0 immediately (we nulled the buffer before receiving).
- // We do not assume the second path is 0-terminated, this is
- // enforced below.
- strncpy(pathBuf2, recvBuf + first_len + 1, kMaxPathLen + 1);
-
- // First string is guaranteed to be 0-terminated.
- pathLen = first_len;
-
- // Look up the first pathname but first translate relative paths.
- pathLen = ConvertToRealPath(pathBuf, sizeof(pathBuf), pathLen);
- perms = mPolicy->Lookup(nsDependentCString(pathBuf, pathLen));
-
- // Same for the second path.
- pathLen2 = strnlen(pathBuf2, kMaxPathLen);
- if (pathLen2 > 0) {
- // Force 0 termination.
- pathBuf2[pathLen2] = '\0';
- pathLen2 = ConvertToRealPath(pathBuf2, sizeof(pathBuf2), pathLen2);
- int perms2 = mPolicy->Lookup(nsDependentCString(pathBuf2, pathLen2));
-
- // Take the intersection of the permissions for both paths.
- perms &= perms2;
- }
- } else {
- // Failed to receive intelligible paths.
- perms = 0;
- }
-
- // And now perform the operation if allowed.
- if (perms & CRASH_INSTEAD) {
- // This is somewhat nonmodular, but it works.
- resp.mError = -ENOSYS;
- } else if (permissive || perms & MAY_ACCESS) {
- // If the operation was only allowed because of permissive mode, log it.
- if (permissive && !(perms & MAY_ACCESS)) {
- AuditPermissive(req.mOp, req.mFlags, perms, pathBuf);
- }
-
- switch(req.mOp) {
- case SANDBOX_FILE_OPEN:
- if (permissive || AllowOpen(req.mFlags, perms)) {
- // Permissions for O_CREAT hardwired to 0600; if that's
- // ever a problem we can change the protocol (but really we
- // should be trying to remove uses of MAY_CREATE, not add
- // new ones).
- openedFd = open(pathBuf, req.mFlags | kRequiredOpenFlags, 0600);
- if (openedFd >= 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_ACCESS:
- if (permissive || AllowAccess(req.mFlags, perms)) {
- // This can't use access() itself because that uses the ruid
- // and not the euid. In theory faccessat() with AT_EACCESS
- // would work, but Linux doesn't actually implement the
- // flags != 0 case; glibc has a hack which doesn't even work
- // in this case so it'll ignore the flag, and Bionic just
- // passes through the syscall and always ignores the flags.
- //
- // Instead, because we've already checked the requested
- // r/w/x bits against the policy, just return success if the
- // file exists and hope that's close enough.
- if (stat(pathBuf, (struct stat*)&respBuf) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_STAT:
- if (DoStat(pathBuf, (struct stat*)&respBuf, req.mFlags) == 0) {
- resp.mError = 0;
- ios[1].iov_base = &respBuf;
- ios[1].iov_len = req.mBufSize;
- } else {
- resp.mError = -errno;
- }
- break;
-
- case SANDBOX_FILE_CHMOD:
- if (permissive || AllowOperation(W_OK, perms)) {
- if (chmod(pathBuf, req.mFlags) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_LINK:
- case SANDBOX_FILE_SYMLINK:
- if (permissive || AllowOperation(W_OK, perms)) {
- if (DoLink(pathBuf, pathBuf2, req.mOp) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_RENAME:
- if (permissive || AllowOperation(W_OK, perms)) {
- if (rename(pathBuf, pathBuf2) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_MKDIR:
- if (permissive || AllowOperation(W_OK | X_OK, perms)) {
- if (mkdir(pathBuf, req.mFlags) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_UNLINK:
- if (permissive || AllowOperation(W_OK, perms)) {
- if (unlink(pathBuf) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_RMDIR:
- if (permissive || AllowOperation(W_OK | X_OK, perms)) {
- if (rmdir(pathBuf) == 0) {
- resp.mError = 0;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
-
- case SANDBOX_FILE_READLINK:
- if (permissive || AllowOperation(R_OK, perms)) {
- ssize_t respSize = readlink(pathBuf, (char*)&respBuf, sizeof(respBuf));
- if (respSize >= 0) {
- resp.mError = respSize;
- ios[1].iov_base = &respBuf;
- ios[1].iov_len = respSize;
- } else {
- resp.mError = -errno;
- }
- } else {
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
- break;
- }
- } else {
- MOZ_ASSERT(perms == 0);
- AuditDenial(req.mOp, req.mFlags, perms, pathBuf);
- }
-
- const size_t numIO = ios[1].iov_len > 0 ? 2 : 1;
- DebugOnly<const ssize_t> sent = SendWithFd(respfd, ios, numIO, openedFd);
- close(respfd);
- MOZ_ASSERT(sent < 0 ||
- static_cast<size_t>(sent) == ios[0].iov_len + ios[1].iov_len);
-
- if (openedFd >= 0) {
- close(openedFd);
- }
- }
-}
-
-void
-SandboxBroker::AuditPermissive(int aOp, int aFlags, int aPerms, const char* aPath)
-{
- MOZ_RELEASE_ASSERT(SandboxInfo::Get().Test(SandboxInfo::kPermissive));
-
- struct stat statBuf;
-
- if (lstat(aPath, &statBuf) == 0) {
- // Path exists, set errno to 0 to indicate "success".
- errno = 0;
- }
-
- SANDBOX_LOG_ERROR("SandboxBroker: would have denied op=%d rflags=%o perms=%d path=%s for pid=%d" \
- " permissive=1 error=\"%s\"", aOp, aFlags, aPerms,
- aPath, mChildPid, strerror(errno));
-}
-
-void
-SandboxBroker::AuditDenial(int aOp, int aFlags, int aPerms, const char* aPath)
-{
- if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
- SANDBOX_LOG_ERROR("SandboxBroker: denied op=%d rflags=%o perms=%d path=%s for pid=%d" \
- " error=\"%s\"", aOp, aFlags, aPerms, aPath, mChildPid,
- strerror(errno));
- }
-}
-
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/broker/SandboxBroker.h b/security/sandbox/linux/broker/SandboxBroker.h
deleted file mode 100644
index bb4570a64..000000000
--- a/security/sandbox/linux/broker/SandboxBroker.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* -*- 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_SandboxBroker_h
-#define mozilla_SandboxBroker_h
-
-#include "mozilla/SandboxBrokerCommon.h"
-
-#include "base/platform_thread.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/UniquePtr.h"
-#include "nsDataHashtable.h"
-#include "nsHashKeys.h"
-#include "nsString.h"
-
-namespace mozilla {
-
-namespace ipc {
-class FileDescriptor;
-}
-
-// This class implements a broker for filesystem operations requested
-// by a sandboxed child process -- opening files and accessing their
-// metadata. (This is necessary in order to restrict access by path;
-// seccomp-bpf can filter only on argument register values, not
-// parameters passed in memory like pathnames.)
-//
-// The broker currently runs on a thread in the parent process (with
-// effective uid changed on B2G), which is for memory efficiency
-// (compared to forking a process) and simplicity (compared to having
-// a separate executable and serializing/deserializing the policy).
-//
-// See also ../SandboxBrokerClient.h for the corresponding client.
-
-class SandboxBroker final
- : private SandboxBrokerCommon
- , public PlatformThread::Delegate
-{
- public:
- enum Perms {
- MAY_ACCESS = 1 << 0,
- MAY_READ = 1 << 1,
- MAY_WRITE = 1 << 2,
- MAY_CREATE = 1 << 3,
- // This flag is for testing policy changes -- when the client is
- // used with the seccomp-bpf integration, an access to this file
- // will invoke a crash dump with the context of the syscall.
- // (This overrides all other flags.)
- CRASH_INSTEAD = 1 << 4,
- // Applies to everything below this path, including subdirs created
- // at runtime
- RECURSIVE = 1 << 5,
- };
- // Bitwise operations on enum values return ints, so just use int in
- // the hash table type (and below) to avoid cluttering code with casts.
- typedef nsDataHashtable<nsCStringHashKey, int> PathMap;
-
- class Policy {
- PathMap mMap;
- public:
- Policy();
- Policy(const Policy& aOther);
- ~Policy();
-
- enum AddCondition {
- AddIfExistsNow,
- AddAlways,
- };
- // Typically, files that don't exist at policy creation time don't
- // need to be whitelisted, but this allows adding entries for
- // them if they'll exist later. See also the overload below.
- void AddPath(int aPerms, const char* aPath, AddCondition aCond);
- // This adds all regular files (not directories) in the tree
- // rooted at the given path.
- void AddTree(int aPerms, const char* aPath);
- // A directory, and all files and directories under it, even those
- // added after creation (the dir itself must exist).
- void AddDir(int aPerms, const char* aPath);
- // All files in a directory with a given prefix; useful for devices.
- void AddPrefix(int aPerms, const char* aDir, const char* aPrefix);
- // Default: add file if it exists when creating policy or if we're
- // conferring permission to create it (log files, etc.).
- void AddPath(int aPerms, const char* aPath) {
- AddPath(aPerms, aPath,
- (aPerms & MAY_CREATE) ? AddAlways : AddIfExistsNow);
- }
- int Lookup(const nsACString& aPath) const;
- int Lookup(const char* aPath) const {
- return Lookup(nsDependentCString(aPath));
- }
- private:
- // ValidatePath checks |path| and returns true if these conditions are met
- // * Greater than 0 length
- // * Is an absolute path
- // * No trailing slash
- // * No /../ path traversal
- bool ValidatePath(const char* path) const;
- };
-
- // Constructing a broker involves creating a socketpair and a
- // background thread to handle requests, so it can fail. If this
- // returns nullptr, do not use the value of aClientFdOut.
- static UniquePtr<SandboxBroker>
- Create(UniquePtr<const Policy> aPolicy, int aChildPid,
- ipc::FileDescriptor& aClientFdOut);
- virtual ~SandboxBroker();
-
- private:
- PlatformThreadHandle mThread;
- int mFileDesc;
- const int mChildPid;
- const UniquePtr<const Policy> mPolicy;
-
- SandboxBroker(UniquePtr<const Policy> aPolicy, int aChildPid,
- int& aClientFd);
- void ThreadMain(void) override;
- void AuditPermissive(int aOp, int aFlags, int aPerms, const char* aPath);
- void AuditDenial(int aOp, int aFlags, int aPerms, const char* aPath);
- // Remap relative paths to absolute paths.
- size_t ConvertToRealPath(char* aPath, size_t aBufSize, size_t aPathLen);
-
- // Holding a UniquePtr should disallow copying, but to make that explicit:
- SandboxBroker(const SandboxBroker&) = delete;
- void operator=(const SandboxBroker&) = delete;
-};
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxBroker_h
diff --git a/security/sandbox/linux/broker/SandboxBrokerCommon.cpp b/security/sandbox/linux/broker/SandboxBrokerCommon.cpp
deleted file mode 100644
index fe7bc8c45..000000000
--- a/security/sandbox/linux/broker/SandboxBrokerCommon.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/* -*- 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 "SandboxBrokerCommon.h"
-
-#include "mozilla/Assertions.h"
-
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#ifndef MSG_CMSG_CLOEXEC
-#ifdef XP_LINUX
-// As always, Android's kernel headers are somewhat old.
-#define MSG_CMSG_CLOEXEC 0x40000000
-#else
-// Most of this code can support other POSIX OSes, but being able to
-// receive fds and atomically make them close-on-exec is important,
-// because this is running in a multithreaded process that can fork.
-// In the future, if the broker becomes a dedicated executable, this
-// can change.
-#error "No MSG_CMSG_CLOEXEC?"
-#endif // XP_LINUX
-#endif // MSG_CMSG_CLOEXEC
-
-namespace mozilla {
-
-/* static */ ssize_t
-SandboxBrokerCommon::RecvWithFd(int aFd, const iovec* aIO, size_t aNumIO,
- int* aPassedFdPtr)
-{
- struct msghdr msg = {};
- msg.msg_iov = const_cast<iovec*>(aIO);
- msg.msg_iovlen = aNumIO;
-
- char cmsg_buf[CMSG_SPACE(sizeof(int))];
- if (aPassedFdPtr) {
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = sizeof(cmsg_buf);
- *aPassedFdPtr = -1;
- }
-
- ssize_t rv;
- do {
- // MSG_CMSG_CLOEXEC is needed to prevent the parent process from
- // accidentally leaking a copy of the child's response socket to a
- // new child process. (The child won't be able to exec, so this
- // doesn't matter as much for that direction.)
- rv = recvmsg(aFd, &msg, MSG_CMSG_CLOEXEC);
- } while (rv < 0 && errno == EINTR);
-
- if (rv <= 0) {
- return rv;
- }
- if (msg.msg_controllen > 0) {
- MOZ_ASSERT(aPassedFdPtr);
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS) {
- int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
- // A client could, for example, send an extra 32-bit int if
- // CMSG_SPACE pads to 64-bit size_t alignment. If so, treat
- // it as an error, but also don't leak the fds.
- for (size_t i = 0; CMSG_LEN(sizeof(int) * i) < cmsg->cmsg_len; ++i) {
- close(fds[i]);
- }
- errno = EMSGSIZE;
- return -1;
- }
- *aPassedFdPtr = fds[0];
- } else {
- errno = EPROTO;
- return -1;
- }
- }
- if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
- if (aPassedFdPtr && *aPassedFdPtr >= 0) {
- close(*aPassedFdPtr);
- *aPassedFdPtr = -1;
- }
- errno = EMSGSIZE;
- return -1;
- }
-
- return rv;
-}
-
-/* static */ ssize_t
-SandboxBrokerCommon::SendWithFd(int aFd, const iovec* aIO, size_t aNumIO,
- int aPassedFd)
-{
- struct msghdr msg = {};
- msg.msg_iov = const_cast<iovec*>(aIO);
- msg.msg_iovlen = aNumIO;
-
- char cmsg_buf[CMSG_SPACE(sizeof(int))];
- if (aPassedFd != -1) {
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = sizeof(cmsg_buf);
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- *reinterpret_cast<int*>(CMSG_DATA(cmsg)) = aPassedFd;
- }
-
- ssize_t rv;
- do {
- rv = sendmsg(aFd, &msg, MSG_NOSIGNAL);
- } while (rv < 0 && errno == EINTR);
-
- return rv;
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/broker/SandboxBrokerCommon.h b/security/sandbox/linux/broker/SandboxBrokerCommon.h
deleted file mode 100644
index dbd17e0b9..000000000
--- a/security/sandbox/linux/broker/SandboxBrokerCommon.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- 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_SandboxBrokerCommon_h
-#define mozilla_SandboxBrokerCommon_h
-
-#include <sys/types.h>
-
-struct iovec;
-
-// This file defines the protocol between the filesystem broker,
-// described in SandboxBroker.h, and its client, described in
-// ../SandboxBrokerClient.h; and it defines some utility functions
-// used by both.
-//
-// In order to keep the client simple while allowing it to be thread
-// safe and async signal safe, the main broker socket is used only for
-// requests; responses arrive on a per-request socketpair sent with
-// the request. (This technique is also used by Chromium and Breakpad.)
-
-namespace mozilla {
-
-class SandboxBrokerCommon {
-public:
- enum Operation {
- SANDBOX_FILE_OPEN,
- SANDBOX_FILE_ACCESS,
- SANDBOX_FILE_STAT,
- SANDBOX_FILE_CHMOD,
- SANDBOX_FILE_LINK,
- SANDBOX_FILE_SYMLINK,
- SANDBOX_FILE_MKDIR,
- SANDBOX_FILE_RENAME,
- SANDBOX_FILE_RMDIR,
- SANDBOX_FILE_UNLINK,
- SANDBOX_FILE_READLINK,
- };
-
- struct Request {
- Operation mOp;
- // For open, flags; for access, "mode"; for stat, O_NOFOLLOW for lstat.
- int mFlags;
- // Size of return value buffer, if any
- size_t mBufSize;
- // The rest of the packet is the pathname.
- // SCM_RIGHTS for response socket attached.
- };
-
- struct Response {
- // Syscall result, -errno if failure, or 0 for no error
- int mError;
- // Followed by struct stat for stat/lstat.
- // SCM_RIGHTS attached for successful open.
- };
-
- // This doesn't need to be the system's maximum path length, just
- // the largest path that would be allowed by any policy. (It's used
- // to size a stack-allocated buffer.)
- static const size_t kMaxPathLen = 4096;
-
- static ssize_t RecvWithFd(int aFd, const iovec* aIO, size_t aNumIO,
- int* aPassedFdPtr);
- static ssize_t SendWithFd(int aFd, const iovec* aIO, size_t aNumIO,
- int aPassedFd);
-};
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxBrokerCommon_h
diff --git a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
deleted file mode 100644
index c3a15ea3d..000000000
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- 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 "SandboxBrokerPolicyFactory.h"
-#include "SandboxInfo.h"
-
-#include "mozilla/ClearOnShutdown.h"
-#include "mozilla/Preferences.h"
-#include "nsPrintfCString.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-#include "nsXULAppAPI.h"
-#include "SpecialSystemDirectory.h"
-
-#ifdef ANDROID
-#include "cutils/properties.h"
-#endif
-
-namespace mozilla {
-
-/* static */ bool
-SandboxBrokerPolicyFactory::IsSystemSupported() {
-#ifdef ANDROID
- char hardware[PROPERTY_VALUE_MAX];
- int length = property_get("ro.hardware", hardware, nullptr);
- // "goldfish" -> emulator. Other devices can be added when we're
- // reasonably sure they work. Eventually this won't be needed....
- if (length > 0 && strcmp(hardware, "goldfish") == 0) {
- return true;
- }
-
- // When broker is running in permissive mode, we enable it
- // automatically regardless of the device.
- if (SandboxInfo::Get().Test(SandboxInfo::kPermissive)) {
- return true;
- }
-#endif
- return false;
-}
-
-SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
-{
- // Policy entries that are the same in every process go here, and
- // are cached over the lifetime of the factory.
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.h b/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.h
deleted file mode 100644
index bf9be9856..000000000
--- a/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- 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_SandboxBrokerPolicyFactory_h
-#define mozilla_SandboxBrokerPolicyFactory_h
-
-#include "mozilla/SandboxBroker.h"
-
-namespace mozilla {
-
-class SandboxBrokerPolicyFactory {
-public:
- SandboxBrokerPolicyFactory();
-
-private:
- UniquePtr<const SandboxBroker::Policy> mCommonContentPolicy;
- // B2G devices tend to have hardware-specific paths used by device
- // drivers, so rollout of filesystem isolation will need per-device
- // testing. This predicate allows that to happen gradually.
- static bool IsSystemSupported();
-};
-
-} // namespace mozilla
-
-#endif // mozilla_SandboxBrokerPolicyFactory_h
diff --git a/security/sandbox/linux/broker/SandboxBrokerUtils.h b/security/sandbox/linux/broker/SandboxBrokerUtils.h
deleted file mode 100644
index 1db4f4411..000000000
--- a/security/sandbox/linux/broker/SandboxBrokerUtils.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- 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_SandboxBrokerUtils_h
-#define mozilla_SandboxBrokerUtils_h
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "sandbox/linux/system_headers/linux_syscalls.h"
-
-// On 32-bit Linux, stat calls are translated by libc into stat64
-// calls. We'll intercept those and handle them in the stat functions
-// but must be sure to use the right structure layout.
-
-#if defined(__NR_stat64)
-typedef struct stat64 statstruct;
-#define statsyscall stat64
-#define lstatsyscall lstat64
-#elif defined(__NR_stat)
-typedef struct stat statstruct;
-#define statsyscall stat
-#define lstatsyscall lstat
-#else
-#error Missing stat syscall include.
-#endif
-
-#endif // mozilla_SandboxBrokerUtils_h
diff --git a/security/sandbox/linux/broker/moz.build b/security/sandbox/linux/broker/moz.build
deleted file mode 100644
index 343a5cfad..000000000
--- a/security/sandbox/linux/broker/moz.build
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- Mode: python; python-indent: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS.mozilla += [
- 'SandboxBroker.h',
- 'SandboxBrokerCommon.h',
- 'SandboxBrokerPolicyFactory.h',
-]
-
-SOURCES += [
- 'SandboxBroker.cpp',
- 'SandboxBrokerCommon.cpp',
- 'SandboxBrokerPolicyFactory.cpp',
-]
-
-if CONFIG['OS_TARGET'] == 'Android':
- if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
- DEFINES['HAVE_ANDROID_OS'] = True
-
-LOCAL_INCLUDES += [
- '/security/sandbox/linux', # SandboxLogging.h, SandboxInfo.h
-]
-
-# Need this for mozilla::ipc::FileDescriptor etc.
-include('/ipc/chromium/chromium-config.mozbuild')
-
-# Need this for safe_sprintf.h used by SandboxLogging.h,
-# but it has to be after ipc/chromium/src.
-LOCAL_INCLUDES += [
- '/security/sandbox/chromium',
-]
-
-
-FINAL_LIBRARY = 'xul'
diff --git a/security/sandbox/linux/glue/SandboxCrash.cpp b/security/sandbox/linux/glue/SandboxCrash.cpp
deleted file mode 100644
index 8ead16bdf..000000000
--- a/security/sandbox/linux/glue/SandboxCrash.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- 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/. */
-
-// This file needs to be linked into libxul, so it can access the JS
-// stack and the crash reporter. Everything else in this directory
-// should be able to be linked into its own shared library, in order
-// to be able to isolate sandbox/chromium from ipc/chromium.
-
-#include "SandboxInternal.h"
-#include "SandboxLogging.h"
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-#include "mozilla/Unused.h"
-#include "mozilla/dom/Exceptions.h"
-#include "nsContentUtils.h"
-#include "mozilla/StackWalk.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-
-namespace mozilla {
-
-// 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
-// are logs and a minidump with the C++ stacks (e.g., on TBPL).
-static void
-SandboxLogJSStack(void)
-{
- if (!NS_IsMainThread()) {
- // This might be a worker thread... or it might be a non-JS
- // thread, or a non-NSPR thread. There's isn't a good API for
- // dealing with this, yet.
- return;
- }
- if (!nsContentUtils::XPConnect()) {
- // There is no content (e.g., the process is a media plugin), in
- // which case this will probably crash and definitely not work.
- return;
- }
- nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
- // If we got a stack, we must have a current JSContext. This is icky. :(
- // Would be better if GetCurrentJSStack() handed out the JSContext it ended up
- // using or something.
- JSContext* cx = frame ? nsContentUtils::GetCurrentJSContext() : nullptr;
- for (int i = 0; frame != nullptr; ++i) {
- nsAutoString fileName, funName;
- int32_t lineNumber;
-
- // Don't stop unwinding if an attribute can't be read.
- fileName.SetIsVoid(true);
- Unused << frame->GetFilename(cx, fileName);
- lineNumber = 0;
- Unused << frame->GetLineNumber(cx, &lineNumber);
- funName.SetIsVoid(true);
- Unused << frame->GetName(cx, funName);
-
- if (!funName.IsVoid() || !fileName.IsVoid()) {
- SANDBOX_LOG_ERROR("JS frame %d: %s %s line %d", i,
- funName.IsVoid() ?
- "(anonymous)" : NS_ConvertUTF16toUTF8(funName).get(),
- fileName.IsVoid() ?
- "(no file)" : NS_ConvertUTF16toUTF8(fileName).get(),
- lineNumber);
- }
-
- nsCOMPtr<nsIStackFrame> nextFrame;
- nsresult rv = frame->GetCaller(cx, getter_AddRefs(nextFrame));
- NS_ENSURE_SUCCESS_VOID(rv);
- frame = nextFrame;
- }
-}
-
-static void SandboxPrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
- void *aClosure)
-{
- char buf[1024];
- MozCodeAddressDetails details;
-
- MozDescribeCodeAddress(aPC, &details);
- MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
- SANDBOX_LOG_ERROR("frame %s", buf);
-}
-
-static void
-SandboxLogCStack()
-{
- // Skip 3 frames: one for this module, one for the signal handler in
- // libmozsandbox, and one for the signal trampoline.
- //
- // Warning: this might not print any stack frames. MozStackWalk
- // can't walk past the signal trampoline on ARM (bug 968531), and
- // x86 frame pointer walking may or may not work (bug 1082276).
-
- MozStackWalk(SandboxPrintStackFrame, /* skip */ 3, /* max */ 0,
- nullptr, 0, nullptr);
- SANDBOX_LOG_ERROR("end of stack.");
-}
-
-static void
-SandboxCrash(int nr, siginfo_t *info, void *void_context)
-{
- pid_t pid = getpid(), tid = syscall(__NR_gettid);
- bool dumped = false;
-
- if (!dumped) {
- SANDBOX_LOG_ERROR("crash reporter is disabled (or failed);"
- " trying stack trace:");
- SandboxLogCStack();
- }
-
- // Do this last, in case it crashes or deadlocks.
- SandboxLogJSStack();
-
- // Try to reraise, so the parent sees that this process crashed.
- // (If tgkill is forbidden, then seccomp will raise SIGSYS, which
- // also accomplishes that goal.)
- signal(SIGSYS, SIG_DFL);
- syscall(__NR_tgkill, pid, tid, nr);
-}
-
-static void __attribute__((constructor))
-SandboxSetCrashFunc()
-{
- gSandboxCrashFunc = SandboxCrash;
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/glue/moz.build b/security/sandbox/linux/glue/moz.build
deleted file mode 100644
index 0d40dcd63..000000000
--- a/security/sandbox/linux/glue/moz.build
+++ /dev/null
@@ -1,29 +0,0 @@
-# -*- Mode: python; python-indent: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-SOURCES += [
- '../../chromium/base/strings/safe_sprintf.cc',
- '../SandboxLogging.cpp',
- 'SandboxCrash.cpp',
-]
-
-# Avoid Chromium logging dependency, because this is going into
-# libxul. See also the comment in SandboxLogging.h.
-SOURCES['../../chromium/base/strings/safe_sprintf.cc'].flags += ['-DNDEBUG']
-
-LOCAL_INCLUDES += [
- '/security/sandbox/chromium',
- '/security/sandbox/linux',
-]
-
-USE_LIBS += [
- 'mozsandbox',
-]
-
-FINAL_LIBRARY = 'xul'
-
-if CONFIG['GNU_CXX']:
- CXXFLAGS += ['-Wno-error=shadow']
diff --git a/security/sandbox/linux/gtest/TestBroker.cpp b/security/sandbox/linux/gtest/TestBroker.cpp
deleted file mode 100644
index a311e181a..000000000
--- a/security/sandbox/linux/gtest/TestBroker.cpp
+++ /dev/null
@@ -1,626 +0,0 @@
-/* -*- 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 "gtest/gtest.h"
-
-#include "broker/SandboxBroker.h"
-#include "broker/SandboxBrokerUtils.h"
-#include "SandboxBrokerClient.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <sched.h>
-#include <semaphore.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "mozilla/Atomics.h"
-#include "mozilla/NullPtr.h"
-#include "mozilla/PodOperations.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/ipc/FileDescriptor.h"
-
-namespace mozilla {
-
-static const int MAY_ACCESS = SandboxBroker::MAY_ACCESS;
-static const int MAY_READ = SandboxBroker::MAY_READ;
-static const int MAY_WRITE = SandboxBroker::MAY_WRITE;
-static const int MAY_CREATE = SandboxBroker::MAY_CREATE;
-static const auto AddAlways = SandboxBroker::Policy::AddAlways;
-
-class SandboxBrokerTest : public ::testing::Test
-{
- UniquePtr<SandboxBroker> mServer;
- UniquePtr<SandboxBrokerClient> mClient;
-
- UniquePtr<const SandboxBroker::Policy> GetPolicy() const;
-
- template<class C, void (C::* Main)()>
- static void* ThreadMain(void* arg) {
- (static_cast<C*>(arg)->*Main)();
- return nullptr;
- }
-
-protected:
- int Open(const char* aPath, int aFlags) {
- return mClient->Open(aPath, aFlags);
- }
- int Access(const char* aPath, int aMode) {
- return mClient->Access(aPath, aMode);
- }
- int Stat(const char* aPath, statstruct* aStat) {
- return mClient->Stat(aPath, aStat);
- }
- int LStat(const char* aPath, statstruct* aStat) {
- return mClient->LStat(aPath, aStat);
- }
- int Chmod(const char* aPath, int aMode) {
- return mClient->Chmod(aPath, aMode);
- }
- int Link(const char* aPath, const char* bPath) {
- return mClient->Link(aPath, bPath);
- }
- int Mkdir(const char* aPath, int aMode) {
- return mClient->Mkdir(aPath, aMode);
- }
- int Symlink(const char* aPath, const char* bPath) {
- return mClient->Symlink(aPath, bPath);
- }
- int Rename(const char* aPath, const char* bPath) {
- return mClient->Rename(aPath, bPath);
- }
- int Rmdir(const char* aPath) {
- return mClient->Rmdir(aPath);
- }
- int Unlink(const char* aPath) {
- return mClient->Unlink(aPath);
- }
- ssize_t Readlink(const char* aPath, char* aBuff, size_t aSize) {
- return mClient->Readlink(aPath, aBuff, aSize);
- }
-
- virtual void SetUp() {
- ipc::FileDescriptor fd;
-
- mServer = SandboxBroker::Create(GetPolicy(), getpid(), fd);
- ASSERT_NE(mServer, nullptr);
- ASSERT_TRUE(fd.IsValid());
- auto rawFD = fd.ClonePlatformHandle();
- mClient.reset(new SandboxBrokerClient(rawFD.release()));
- }
-
- template<class C, void (C::* Main)()>
- void StartThread(pthread_t *aThread) {
- ASSERT_EQ(0, pthread_create(aThread, nullptr, ThreadMain<C, Main>,
- static_cast<C*>(this)));
- }
-
- template<class C, void (C::* Main)()>
- void RunOnManyThreads() {
- static const int kNumThreads = 5;
- pthread_t threads[kNumThreads];
- for (int i = 0; i < kNumThreads; ++i) {
- StartThread<C, Main>(&threads[i]);
- }
- for (int i = 0; i < kNumThreads; ++i) {
- void* retval;
- ASSERT_EQ(pthread_join(threads[i], &retval), 0);
- ASSERT_EQ(retval, static_cast<void*>(nullptr));
- }
- }
-
-public:
- void MultiThreadOpenWorker();
- void MultiThreadStatWorker();
-};
-
-UniquePtr<const SandboxBroker::Policy>
-SandboxBrokerTest::GetPolicy() const
-{
- UniquePtr<SandboxBroker::Policy> policy(new SandboxBroker::Policy());
-
- policy->AddPath(MAY_READ | MAY_WRITE, "/dev/null", AddAlways);
- policy->AddPath(MAY_READ, "/dev/zero", AddAlways);
- policy->AddPath(MAY_READ, "/var/empty/qwertyuiop", AddAlways);
- policy->AddPath(MAY_ACCESS, "/proc/self", AddAlways); // Warning: Linux-specific.
- policy->AddPath(MAY_READ | MAY_WRITE, "/tmp", AddAlways);
- policy->AddPath(MAY_READ | MAY_WRITE | MAY_CREATE, "/tmp/blublu", AddAlways);
- policy->AddPath(MAY_READ | MAY_WRITE | MAY_CREATE, "/tmp/blublublu", AddAlways);
-
- return Move(policy);
-}
-
-TEST_F(SandboxBrokerTest, OpenForRead)
-{
- int fd;
-
- fd = Open("/dev/null", O_RDONLY);
- ASSERT_GE(fd, 0) << "Opening /dev/null failed.";
- close(fd);
- fd = Open("/dev/zero", O_RDONLY);
- ASSERT_GE(fd, 0) << "Opening /dev/zero failed.";
- close(fd);
- fd = Open("/var/empty/qwertyuiop", O_RDONLY);
- EXPECT_EQ(-ENOENT, fd) << "Opening allowed but nonexistent file succeeded.";
- fd = Open("/proc/self", O_RDONLY);
- EXPECT_EQ(-EACCES, fd) << "Opening stat-only file for read succeeded.";
- fd = Open("/proc/self/stat", O_RDONLY);
- EXPECT_EQ(-EACCES, fd) << "Opening disallowed file succeeded.";
-}
-
-TEST_F(SandboxBrokerTest, OpenForWrite)
-{
- int fd;
-
- fd = Open("/dev/null", O_WRONLY);
- ASSERT_GE(fd, 0) << "Opening /dev/null write-only failed.";
- close(fd);
- fd = Open("/dev/null", O_RDWR);
- ASSERT_GE(fd, 0) << "Opening /dev/null read/write failed.";
- close(fd);
- fd = Open("/dev/zero", O_WRONLY);
- ASSERT_EQ(-EACCES, fd) << "Opening read-only-by-policy file write-only succeeded.";
- fd = Open("/dev/zero", O_RDWR);
- ASSERT_EQ(-EACCES, fd) << "Opening read-only-by-policy file read/write succeeded.";
-}
-
-TEST_F(SandboxBrokerTest, SimpleRead)
-{
- int fd;
- char c;
-
- fd = Open("/dev/null", O_RDONLY);
- ASSERT_GE(fd, 0);
- EXPECT_EQ(0, read(fd, &c, 1));
- close(fd);
- fd = Open("/dev/zero", O_RDONLY);
- ASSERT_GE(fd, 0);
- ASSERT_EQ(1, read(fd, &c, 1));
- EXPECT_EQ(c, '\0');
-}
-
-TEST_F(SandboxBrokerTest, Access)
-{
- EXPECT_EQ(0, Access("/dev/null", F_OK));
- EXPECT_EQ(0, Access("/dev/null", R_OK));
- EXPECT_EQ(0, Access("/dev/null", W_OK));
- EXPECT_EQ(0, Access("/dev/null", R_OK|W_OK));
- EXPECT_EQ(-EACCES, Access("/dev/null", X_OK));
- EXPECT_EQ(-EACCES, Access("/dev/null", R_OK|X_OK));
-
- EXPECT_EQ(0, Access("/dev/zero", R_OK));
- EXPECT_EQ(-EACCES, Access("/dev/zero", W_OK));
- EXPECT_EQ(-EACCES, Access("/dev/zero", R_OK|W_OK));
-
- EXPECT_EQ(-ENOENT, Access("/var/empty/qwertyuiop", R_OK));
- EXPECT_EQ(-EACCES, Access("/var/empty/qwertyuiop", W_OK));
-
- EXPECT_EQ(0, Access("/proc/self", F_OK));
- EXPECT_EQ(-EACCES, Access("/proc/self", R_OK));
-
- EXPECT_EQ(-EACCES, Access("/proc/self/stat", F_OK));
-}
-
-TEST_F(SandboxBrokerTest, Stat)
-{
- statstruct realStat, brokeredStat;
- ASSERT_EQ(0, statsyscall("/dev/null", &realStat)) << "Shouldn't ever fail!";
- EXPECT_EQ(0, Stat("/dev/null", &brokeredStat));
- EXPECT_EQ(realStat.st_ino, brokeredStat.st_ino);
- EXPECT_EQ(realStat.st_rdev, brokeredStat.st_rdev);
-
- EXPECT_EQ(-ENOENT, Stat("/var/empty/qwertyuiop", &brokeredStat));
- EXPECT_EQ(-EACCES, Stat("/dev", &brokeredStat));
-
- EXPECT_EQ(0, Stat("/proc/self", &brokeredStat));
- EXPECT_TRUE(S_ISDIR(brokeredStat.st_mode));
-}
-
-TEST_F(SandboxBrokerTest, LStat)
-{
- statstruct realStat, brokeredStat;
- ASSERT_EQ(0, lstatsyscall("/dev/null", &realStat));
- EXPECT_EQ(0, LStat("/dev/null", &brokeredStat));
- EXPECT_EQ(realStat.st_ino, brokeredStat.st_ino);
- EXPECT_EQ(realStat.st_rdev, brokeredStat.st_rdev);
-
- EXPECT_EQ(-ENOENT, LStat("/var/empty/qwertyuiop", &brokeredStat));
- EXPECT_EQ(-EACCES, LStat("/dev", &brokeredStat));
-
- EXPECT_EQ(0, LStat("/proc/self", &brokeredStat));
- EXPECT_TRUE(S_ISLNK(brokeredStat.st_mode));
-}
-
-static void PrePostTestCleanup(void)
-{
- unlink("/tmp/blublu");
- rmdir("/tmp/blublu");
- unlink("/tmp/nope");
- rmdir("/tmp/nope");
- unlink("/tmp/blublublu");
- rmdir("/tmp/blublublu");
-}
-
-TEST_F(SandboxBrokerTest, Chmod)
-{
- PrePostTestCleanup();
-
- int fd = Open("/tmp/blublu", O_WRONLY | O_CREAT);
- ASSERT_GE(fd, 0) << "Opening /tmp/blublu for writing failed.";
- close(fd);
- // Set read only. SandboxBroker enforces 0600 mode flags.
- ASSERT_EQ(0, Chmod("/tmp/blublu", S_IRUSR));
- // SandboxBroker doesn't use real access(), it just checks against
- // the policy. So it can't see the change in permisions here.
- // This won't work:
- // EXPECT_EQ(-EACCES, Access("/tmp/blublu", W_OK));
- statstruct realStat;
- EXPECT_EQ(0, statsyscall("/tmp/blublu", &realStat));
- EXPECT_EQ((mode_t)S_IRUSR, realStat.st_mode & 0777);
-
- ASSERT_EQ(0, Chmod("/tmp/blublu", S_IRUSR | S_IWUSR));
- EXPECT_EQ(0, statsyscall("/tmp/blublu", &realStat));
- EXPECT_EQ((mode_t)(S_IRUSR | S_IWUSR), realStat.st_mode & 0777);
- EXPECT_EQ(0, unlink("/tmp/blublu"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Link)
-{
- PrePostTestCleanup();
-
- int fd = Open("/tmp/blublu", O_WRONLY | O_CREAT);
- ASSERT_GE(fd, 0) << "Opening /tmp/blublu for writing failed.";
- close(fd);
- ASSERT_EQ(0, Link("/tmp/blublu", "/tmp/blublublu"));
- EXPECT_EQ(0, Access("/tmp/blublublu", F_OK));
- // Not whitelisted target path
- EXPECT_EQ(-EACCES, Link("/tmp/blublu", "/tmp/nope"));
- EXPECT_EQ(0, unlink("/tmp/blublublu"));
- EXPECT_EQ(0, unlink("/tmp/blublu"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Symlink)
-{
- PrePostTestCleanup();
-
- int fd = Open("/tmp/blublu", O_WRONLY | O_CREAT);
- ASSERT_GE(fd, 0) << "Opening /tmp/blublu for writing failed.";
- close(fd);
- ASSERT_EQ(0, Symlink("/tmp/blublu", "/tmp/blublublu"));
- EXPECT_EQ(0, Access("/tmp/blublublu", F_OK));
- statstruct aStat;
- ASSERT_EQ(0, lstatsyscall("/tmp/blublublu", &aStat));
- EXPECT_EQ((mode_t)S_IFLNK, aStat.st_mode & S_IFMT);
- // Not whitelisted target path
- EXPECT_EQ(-EACCES, Symlink("/tmp/blublu", "/tmp/nope"));
- EXPECT_EQ(0, unlink("/tmp/blublublu"));
- EXPECT_EQ(0, unlink("/tmp/blublu"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Mkdir)
-{
- PrePostTestCleanup();
-
- ASSERT_EQ(0, mkdir("/tmp/blublu", 0600))
- << "Creating dir /tmp/blublu failed.";
- EXPECT_EQ(0, Access("/tmp/blublu", F_OK));
- // Not whitelisted target path
- EXPECT_EQ(-EACCES, Mkdir("/tmp/nope", 0600))
- << "Creating dir without MAY_CREATE succeed.";
- EXPECT_EQ(0, rmdir("/tmp/blublu"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Rename)
-{
- PrePostTestCleanup();
-
- ASSERT_EQ(0, mkdir("/tmp/blublu", 0600))
- << "Creating dir /tmp/blublu failed.";
- EXPECT_EQ(0, Access("/tmp/blublu", F_OK));
- ASSERT_EQ(0, Rename("/tmp/blublu", "/tmp/blublublu"));
- EXPECT_EQ(0, Access("/tmp/blublublu", F_OK));
- EXPECT_EQ(-ENOENT , Access("/tmp/blublu", F_OK));
- // Not whitelisted target path
- EXPECT_EQ(-EACCES, Rename("/tmp/blublublu", "/tmp/nope"))
- << "Renaming dir without write access succeed.";
- EXPECT_EQ(0, rmdir("/tmp/blublublu"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Rmdir)
-{
- PrePostTestCleanup();
-
- ASSERT_EQ(0, mkdir("/tmp/blublu", 0600))
- << "Creating dir /tmp/blublu failed.";
- EXPECT_EQ(0, Access("/tmp/blublu", F_OK));
- ASSERT_EQ(0, Rmdir("/tmp/blublu"));
- EXPECT_EQ(-ENOENT, Access("/tmp/blublu", F_OK));
- // Bypass sandbox to create a non-deletable dir
- ASSERT_EQ(0, mkdir("/tmp/nope", 0600));
- EXPECT_EQ(-EACCES, Rmdir("/tmp/nope"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Unlink)
-{
- PrePostTestCleanup();
-
- int fd = Open("/tmp/blublu", O_WRONLY | O_CREAT);
- ASSERT_GE(fd, 0) << "Opening /tmp/blublu for writing failed.";
- close(fd);
- EXPECT_EQ(0, Access("/tmp/blublu", F_OK));
- EXPECT_EQ(0, Unlink("/tmp/blublu"));
- EXPECT_EQ(-ENOENT , Access("/tmp/blublu", F_OK));
- // Bypass sandbox to write a non-deletable file
- fd = open("/tmp/nope", O_WRONLY | O_CREAT, 0600);
- ASSERT_GE(fd, 0) << "Opening /tmp/nope for writing failed.";
- close(fd);
- EXPECT_EQ(-EACCES, Unlink("/tmp/nope"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, Readlink)
-{
- PrePostTestCleanup();
-
- int fd = Open("/tmp/blublu", O_WRONLY | O_CREAT);
- ASSERT_GE(fd, 0) << "Opening /tmp/blublu for writing failed.";
- close(fd);
- ASSERT_EQ(0, Symlink("/tmp/blublu", "/tmp/blublublu"));
- EXPECT_EQ(0, Access("/tmp/blublublu", F_OK));
- char linkBuff[256];
- EXPECT_EQ(11, Readlink("/tmp/blublublu", linkBuff, sizeof(linkBuff)));
- linkBuff[11] = '\0';
- EXPECT_EQ(0, strcmp(linkBuff, "/tmp/blublu"));
-
- PrePostTestCleanup();
-}
-
-TEST_F(SandboxBrokerTest, MultiThreadOpen) {
- RunOnManyThreads<SandboxBrokerTest,
- &SandboxBrokerTest::MultiThreadOpenWorker>();
-}
-void SandboxBrokerTest::MultiThreadOpenWorker() {
- static const int kNumLoops = 10000;
-
- for (int i = 1; i <= kNumLoops; ++i) {
- int nullfd = Open("/dev/null", O_RDONLY);
- int zerofd = Open("/dev/zero", O_RDONLY);
- ASSERT_GE(nullfd, 0) << "Loop " << i << "/" << kNumLoops;
- ASSERT_GE(zerofd, 0) << "Loop " << i << "/" << kNumLoops;
- char c;
- ASSERT_EQ(0, read(nullfd, &c, 1)) << "Loop " << i << "/" << kNumLoops;
- ASSERT_EQ(1, read(zerofd, &c, 1)) << "Loop " << i << "/" << kNumLoops;
- ASSERT_EQ('\0', c) << "Loop " << i << "/" << kNumLoops;
- close(nullfd);
- close(zerofd);
- }
-}
-
-TEST_F(SandboxBrokerTest, MultiThreadStat) {
- RunOnManyThreads<SandboxBrokerTest,
- &SandboxBrokerTest::MultiThreadStatWorker>();
-}
-void SandboxBrokerTest::MultiThreadStatWorker() {
- static const int kNumLoops = 7500;
- statstruct nullStat, zeroStat, selfStat;
- dev_t realNullDev, realZeroDev;
- ino_t realSelfInode;
-
- ASSERT_EQ(0, statsyscall("/dev/null", &nullStat)) << "Shouldn't ever fail!";
- ASSERT_EQ(0, statsyscall("/dev/zero", &zeroStat)) << "Shouldn't ever fail!";
- ASSERT_EQ(0, lstatsyscall("/proc/self", &selfStat)) << "Shouldn't ever fail!";
- ASSERT_TRUE(S_ISLNK(selfStat.st_mode)) << "Shouldn't ever fail!";
- realNullDev = nullStat.st_rdev;
- realZeroDev = zeroStat.st_rdev;
- realSelfInode = selfStat.st_ino;
- for (int i = 1; i <= kNumLoops; ++i) {
- ASSERT_EQ(0, Stat("/dev/null", &nullStat))
- << "Loop " << i << "/" << kNumLoops;
- ASSERT_EQ(0, Stat("/dev/zero", &zeroStat))
- << "Loop " << i << "/" << kNumLoops;
- ASSERT_EQ(0, LStat("/proc/self", &selfStat))
- << "Loop " << i << "/" << kNumLoops;
-
- ASSERT_EQ(realNullDev, nullStat.st_rdev)
- << "Loop " << i << "/" << kNumLoops;
- ASSERT_EQ(realZeroDev, zeroStat.st_rdev)
- << "Loop " << i << "/" << kNumLoops;
- ASSERT_TRUE(S_ISLNK(selfStat.st_mode))
- << "Loop " << i << "/" << kNumLoops;
- ASSERT_EQ(realSelfInode, selfStat.st_ino)
- << "Loop " << i << "/" << kNumLoops;
- }
-}
-
-#if 0
-class SandboxBrokerSigStress : public SandboxBrokerTest
-{
- int mSigNum;
- struct sigaction mOldAction;
- Atomic<void*> mVoidPtr;
-
- static void SigHandler(int aSigNum, siginfo_t* aSigInfo, void *aCtx) {
- ASSERT_EQ(SI_QUEUE, aSigInfo->si_code);
- SandboxBrokerSigStress* that =
- static_cast<SandboxBrokerSigStress*>(aSigInfo->si_value.sival_ptr);
- ASSERT_EQ(that->mSigNum, aSigNum);
- that->DoSomething();
- }
-
-protected:
- Atomic<int> mTestIter;
- sem_t mSemaphore;
-
- void SignalThread(pthread_t aThread) {
- union sigval sv;
- sv.sival_ptr = this;
- ASSERT_NE(0, mSigNum);
- ASSERT_EQ(0, pthread_sigqueue(aThread, mSigNum, sv));
- }
-
- virtual void SetUp() {
- ASSERT_EQ(0, sem_init(&mSemaphore, 0, 0));
- mVoidPtr = nullptr;
- mSigNum = 0;
- for (int sigNum = SIGRTMIN; sigNum < SIGRTMAX; ++sigNum) {
- ASSERT_EQ(0, sigaction(sigNum, nullptr, &mOldAction));
- if ((mOldAction.sa_flags & SA_SIGINFO) == 0 &&
- mOldAction.sa_handler == SIG_DFL) {
- struct sigaction newAction;
- PodZero(&newAction);
- newAction.sa_flags = SA_SIGINFO;
- newAction.sa_sigaction = SigHandler;
- ASSERT_EQ(0, sigaction(sigNum, &newAction, nullptr));
- mSigNum = sigNum;
- break;
- }
- }
- ASSERT_NE(mSigNum, 0);
-
- SandboxBrokerTest::SetUp();
- }
-
- virtual void TearDown() {
- ASSERT_EQ(0, sem_destroy(&mSemaphore));
- if (mSigNum != 0) {
- ASSERT_EQ(0, sigaction(mSigNum, &mOldAction, nullptr));
- }
- if (mVoidPtr) {
- free(mVoidPtr);
- }
- }
-
- void DoSomething();
-
-public:
- void MallocWorker();
- void FreeWorker();
-};
-
-TEST_F(SandboxBrokerSigStress, StressTest)
-{
- static const int kIters = 6250;
- static const int kNsecPerIterPerIter = 4;
- struct timespec delay = { 0, 0 };
- pthread_t threads[2];
-
- mTestIter = kIters;
-
- StartThread<SandboxBrokerSigStress,
- &SandboxBrokerSigStress::MallocWorker>(&threads[0]);
- StartThread<SandboxBrokerSigStress,
- &SandboxBrokerSigStress::FreeWorker>(&threads[1]);
-
- for (int i = kIters; i > 0; --i) {
- SignalThread(threads[i % 2]);
- while (sem_wait(&mSemaphore) == -1 && errno == EINTR)
- /* retry */;
- ASSERT_EQ(i - 1, mTestIter);
- delay.tv_nsec += kNsecPerIterPerIter;
- struct timespec req = delay, rem;
- while (nanosleep(&req, &rem) == -1 && errno == EINTR) {
- req = rem;
- }
- }
- void *retval;
- ASSERT_EQ(0, pthread_join(threads[0], &retval));
- ASSERT_EQ(nullptr, retval);
- ASSERT_EQ(0, pthread_join(threads[1], &retval));
- ASSERT_EQ(nullptr, retval);
-}
-
-void
-SandboxBrokerSigStress::MallocWorker()
-{
- static const size_t kSize = 64;
-
- void* mem = malloc(kSize);
- while (mTestIter > 0) {
- ASSERT_NE(mem, mVoidPtr);
- mem = mVoidPtr.exchange(mem);
- if (mem) {
- sched_yield();
- } else {
- mem = malloc(kSize);
- }
- }
- if (mem) {
- free(mem);
- }
-}
-
-void
-SandboxBrokerSigStress::FreeWorker()
-{
- void *mem = nullptr;
- while (mTestIter > 0) {
- mem = mVoidPtr.exchange(mem);
- if (mem) {
- free(mem);
- mem = nullptr;
- } else {
- sched_yield();
- }
- }
-}
-
-void
-SandboxBrokerSigStress::DoSomething()
-{
- int fd;
- char c;
- struct stat st;
-
- //fprintf(stderr, "Don't try this at home: %d\n", static_cast<int>(mTestIter));
- switch (mTestIter % 5) {
- case 0:
- fd = Open("/dev/null", O_RDWR);
- ASSERT_GE(fd, 0);
- ASSERT_EQ(0, read(fd, &c, 1));
- close(fd);
- break;
- case 1:
- fd = Open("/dev/zero", O_RDONLY);
- ASSERT_GE(fd, 0);
- ASSERT_EQ(1, read(fd, &c, 1));
- ASSERT_EQ('\0', c);
- close(fd);
- break;
- case 2:
- ASSERT_EQ(0, Access("/dev/null", W_OK));
- break;
- case 3:
- ASSERT_EQ(0, Stat("/proc/self", &st));
- ASSERT_TRUE(S_ISDIR(st.st_mode));
- break;
- case 4:
- ASSERT_EQ(0, LStat("/proc/self", &st));
- ASSERT_TRUE(S_ISLNK(st.st_mode));
- break;
- }
- mTestIter--;
- sem_post(&mSemaphore);
-}
-#endif
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/gtest/TestBrokerPolicy.cpp b/security/sandbox/linux/gtest/TestBrokerPolicy.cpp
deleted file mode 100644
index 474458446..000000000
--- a/security/sandbox/linux/gtest/TestBrokerPolicy.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- 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 "gtest/gtest.h"
-
-#include "broker/SandboxBroker.h"
-
-namespace mozilla {
-
-static const int MAY_ACCESS = SandboxBroker::MAY_ACCESS;
-static const int MAY_READ = SandboxBroker::MAY_READ;
-static const int MAY_WRITE = SandboxBroker::MAY_WRITE;
-//static const int MAY_CREATE = SandboxBroker::MAY_CREATE;
-//static const int RECURSIVE = SandboxBroker::RECURSIVE;
-static const auto AddAlways = SandboxBroker::Policy::AddAlways;
-
-TEST(SandboxBrokerPolicyLookup, Simple)
-{
- SandboxBroker::Policy p;
- p.AddPath(MAY_READ, "/dev/urandom", AddAlways);
-
- EXPECT_NE(0, p.Lookup("/dev/urandom")) << "Added path not found.";
- EXPECT_EQ(MAY_ACCESS | MAY_READ, p.Lookup("/dev/urandom"))
- << "Added path found with wrong perms.";
- EXPECT_EQ(0, p.Lookup("/etc/passwd")) << "Non-added path was found.";
-}
-
-TEST(SandboxBrokerPolicyLookup, CopyCtor)
-{
- SandboxBroker::Policy psrc;
- psrc.AddPath(MAY_READ | MAY_WRITE, "/dev/null", AddAlways);
- SandboxBroker::Policy pdst(psrc);
- psrc.AddPath(MAY_READ, "/dev/zero", AddAlways);
- pdst.AddPath(MAY_READ, "/dev/urandom", AddAlways);
-
- EXPECT_EQ(MAY_ACCESS | MAY_READ | MAY_WRITE, psrc.Lookup("/dev/null"))
- << "Common path absent in copy source.";
- EXPECT_EQ(MAY_ACCESS | MAY_READ | MAY_WRITE, pdst.Lookup("/dev/null"))
- << "Common path absent in copy destination.";
-
- EXPECT_EQ(MAY_ACCESS | MAY_READ, psrc.Lookup("/dev/zero"))
- << "Source-only path is absent.";
- EXPECT_EQ(0, pdst.Lookup("/dev/zero"))
- << "Source-only path is present in copy destination.";
-
- EXPECT_EQ(0, psrc.Lookup("/dev/urandom"))
- << "Destination-only path is present in copy source.";
- EXPECT_EQ(MAY_ACCESS | MAY_READ, pdst.Lookup("/dev/urandom"))
- << "Destination-only path is absent.";
-
- EXPECT_EQ(0, psrc.Lookup("/etc/passwd"))
- << "Non-added path is present in copy source.";
- EXPECT_EQ(0, pdst.Lookup("/etc/passwd"))
- << "Non-added path is present in copy source.";
-}
-
-TEST(SandboxBrokerPolicyLookup, Recursive)
-{
- SandboxBroker::Policy psrc;
- psrc.AddPath(MAY_READ | MAY_WRITE, "/dev/null", AddAlways);
- psrc.AddPath(MAY_READ, "/dev/zero", AddAlways);
- psrc.AddPath(MAY_READ, "/dev/urandom", AddAlways);
-
- EXPECT_EQ(MAY_ACCESS | MAY_READ | MAY_WRITE, psrc.Lookup("/dev/null"))
- << "Basic path is present.";
- EXPECT_EQ(MAY_ACCESS | MAY_READ, psrc.Lookup("/dev/zero"))
- << "Basic path has no extra flags";
-
- psrc.AddDir(MAY_READ | MAY_WRITE, "/dev/");
-
- EXPECT_EQ(MAY_ACCESS | MAY_READ | MAY_WRITE, psrc.Lookup("/dev/random"))
- << "Permission via recursive dir.";
- EXPECT_EQ(MAY_ACCESS | MAY_READ | MAY_WRITE, psrc.Lookup("/dev/sd/0"))
- << "Permission via recursive dir, nested deeper";
- EXPECT_EQ(0, psrc.Lookup("/dev/sd/0/"))
- << "Invalid path format.";
- EXPECT_EQ(0, psrc.Lookup("/usr/dev/sd"))
- << "Match must be a prefix.";
-
- psrc.AddDir(MAY_READ, "/dev/sd/");
- EXPECT_EQ(MAY_ACCESS | MAY_READ | MAY_WRITE, psrc.Lookup("/dev/sd/0"))
- << "Extra permissions from parent path granted.";
- EXPECT_EQ(0, psrc.Lookup("/dev/.."))
- << "Refuse attempted subdir escape.";
-
- psrc.AddDir(MAY_READ, "/tmp");
- EXPECT_EQ(MAY_ACCESS | MAY_READ, psrc.Lookup("/tmp/good/a"))
- << "Check whether dir add with no trailing / was sucessful.";
- EXPECT_EQ(0, psrc.Lookup("/tmp_good_but_bad"))
- << "Enforce terminator on directories.";
- EXPECT_EQ(0, psrc.Lookup("/tmp/."))
- << "Do not allow opening a directory handle.";
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/gtest/TestSandboxUtil.cpp b/security/sandbox/linux/gtest/TestSandboxUtil.cpp
deleted file mode 100644
index cd29813f9..000000000
--- a/security/sandbox/linux/gtest/TestSandboxUtil.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- 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 "gtest/gtest.h"
-
-#include "SandboxUtil.h"
-#include "SandboxInfo.h"
-
-#include <pthread.h>
-
-namespace mozilla {
-
-// In order to test IsSingleThreaded when the test-running process is
-// single-threaded, before assorted XPCOM components have created many
-// additional threads, a static initializer is used.
-
-namespace {
-
-struct EarlyTest {
- bool mWasSingleThreaded;
-
- EarlyTest()
- : mWasSingleThreaded(IsSingleThreaded())
- { }
-};
-
-static const EarlyTest gEarlyTest;
-
-} // namespace
-
-TEST(SandboxUtil, IsSingleThreaded)
-{
- // If the test system if affected by kUnexpectedThreads, (1) there's
- // no point in doing this test, and (2) if that happens on Mozilla
- // CI then burning the tree is an appropriate response.
- ASSERT_FALSE(SandboxInfo::Get().Test(SandboxInfo::kUnexpectedThreads));
- EXPECT_TRUE(gEarlyTest.mWasSingleThreaded);
- EXPECT_FALSE(IsSingleThreaded());
-}
-
-} // namespace mozilla
diff --git a/security/sandbox/linux/gtest/moz.build b/security/sandbox/linux/gtest/moz.build
deleted file mode 100644
index 7aecc7fe3..000000000
--- a/security/sandbox/linux/gtest/moz.build
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-Library('sandboxtest')
-
-SOURCES = [
- '../SandboxBrokerClient.cpp',
- '../SandboxUtil.cpp',
- 'TestBroker.cpp',
- 'TestBrokerPolicy.cpp',
- 'TestSandboxUtil.cpp',
-]
-
-LOCAL_INCLUDES += [
- '/security/sandbox/linux',
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-LOCAL_INCLUDES += [
- '/security/sandbox/chromium',
-]
-
-FINAL_LIBRARY = 'xul-gtest'
diff --git a/security/sandbox/linux/moz.build b/security/sandbox/linux/moz.build
deleted file mode 100644
index 4273da955..000000000
--- a/security/sandbox/linux/moz.build
+++ /dev/null
@@ -1,116 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-SharedLibrary('mozsandbox')
-
-# Depend on mozglue if and only if it's a shared library;
-# this needs to match mozglue/build/moz.build:
-if CONFIG['OS_TARGET'] == 'Android':
- USE_LIBS += [
- 'mozglue',
- ]
-
-EXPORTS.mozilla += [
- 'Sandbox.h',
- 'SandboxInfo.h',
-]
-
-SOURCES += [
- '../chromium-shim/base/logging.cpp',
- '../chromium/base/at_exit.cc',
- '../chromium/base/callback_internal.cc',
- '../chromium/base/lazy_instance.cc',
- '../chromium/base/memory/ref_counted.cc',
- '../chromium/base/memory/singleton.cc',
- '../chromium/base/strings/safe_sprintf.cc',
- '../chromium/base/strings/string16.cc',
- '../chromium/base/strings/string_piece.cc',
- '../chromium/base/strings/string_util.cc',
- '../chromium/base/strings/string_util_constants.cc',
- '../chromium/base/strings/stringprintf.cc',
- '../chromium/base/strings/utf_string_conversion_utils.cc',
- '../chromium/base/strings/utf_string_conversions.cc',
- '../chromium/base/synchronization/condition_variable_posix.cc',
- '../chromium/base/synchronization/lock.cc',
- '../chromium/base/synchronization/lock_impl_posix.cc',
- '../chromium/base/synchronization/waitable_event_posix.cc',
- '../chromium/base/third_party/icu/icu_utf.cc',
- '../chromium/base/threading/platform_thread_internal_posix.cc',
- '../chromium/base/threading/platform_thread_linux.cc',
- '../chromium/base/threading/platform_thread_posix.cc',
- '../chromium/base/threading/thread_collision_warner.cc',
- '../chromium/base/threading/thread_id_name_manager.cc',
- '../chromium/base/threading/thread_local_posix.cc',
- '../chromium/base/threading/thread_restrictions.cc',
- '../chromium/base/time/time.cc',
- '../chromium/base/time/time_posix.cc',
- '../chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc',
- '../chromium/sandbox/linux/bpf_dsl/codegen.cc',
- '../chromium/sandbox/linux/bpf_dsl/dump_bpf.cc',
- '../chromium/sandbox/linux/bpf_dsl/policy.cc',
- '../chromium/sandbox/linux/bpf_dsl/policy_compiler.cc',
- '../chromium/sandbox/linux/bpf_dsl/syscall_set.cc',
- '../chromium/sandbox/linux/seccomp-bpf/die.cc',
- '../chromium/sandbox/linux/seccomp-bpf/syscall.cc',
- '../chromium/sandbox/linux/seccomp-bpf/trap.cc',
- '../chromium/sandbox/linux/services/syscall_wrappers.cc',
- 'broker/SandboxBrokerCommon.cpp',
- 'LinuxCapabilities.cpp',
- 'Sandbox.cpp',
- 'SandboxBrokerClient.cpp',
- 'SandboxChroot.cpp',
- 'SandboxFilter.cpp',
- 'SandboxFilterUtil.cpp',
- 'SandboxHooks.cpp',
- 'SandboxInfo.cpp',
- 'SandboxLogging.cpp',
- 'SandboxUtil.cpp',
-]
-
-# This copy of SafeSPrintf doesn't need to avoid the Chromium logging
-# dependency like the one in libxul does, but this way the behavior is
-# consistent. See also the comment in SandboxLogging.h.
-SOURCES['../chromium/base/strings/safe_sprintf.cc'].flags += ['-DNDEBUG']
-
-# Keep clang and GCC from warning about intentional 'switch' fallthrough in icu_utf.cc:
-if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
- SOURCES['../chromium/base/third_party/icu/icu_utf.cc'].flags += ['-Wno-implicit-fallthrough']
-
-if CONFIG['GNU_CXX']:
- CXXFLAGS += ['-Wno-shadow']
- SOURCES['../chromium/sandbox/linux/services/syscall_wrappers.cc'].flags += [
- '-Wno-empty-body',
- ]
-
-# gcc lto likes to put the top level asm in syscall.cc in a different partition
-# from the function using it which breaks the build. Work around that by
-# forcing there to be only one partition.
-if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']:
- LDFLAGS += ['--param lto-partitions=1']
-
-DEFINES['NS_NO_XPCOM'] = True
-DISABLE_STL_WRAPPING = True
-
-LOCAL_INCLUDES += ['/security/sandbox/linux']
-LOCAL_INCLUDES += ['/security/sandbox/chromium-shim']
-LOCAL_INCLUDES += ['/security/sandbox/chromium']
-LOCAL_INCLUDES += ['/nsprpub']
-
-
-if CONFIG['OS_TARGET'] != 'Android':
- # Needed for clock_gettime with glibc < 2.17:
- OS_LIBS += [
- 'rt',
- ]
-
-DIRS += [
- 'broker',
- 'glue',
-]
-
-TEST_DIRS += [
- 'gtest',
-]