Merge from Chromium at DEPS revision 288042
This commit was generated by merge_to_master.py.
Change-Id: I583602ff16d735199f1810565c9296e970ce2854
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index 274d065..99499d9 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -12,7 +12,8 @@
'compile_suid_client': 0,
'compile_credentials': 0,
}],
- ['OS=="linux" and (target_arch=="ia32" or target_arch=="x64")', {
+ ['OS=="linux" and (target_arch=="ia32" or target_arch=="x64" or '
+ 'target_arch=="mipsel")', {
'compile_seccomp_bpf_demo': 1,
}, {
'compile_seccomp_bpf_demo': 0,
@@ -270,7 +271,9 @@
'services/android_futex.h',
'services/android_ucontext.h',
'services/android_i386_ucontext.h',
+ 'services/android_mips_ucontext.h',
'services/arm_linux_syscalls.h',
+ 'services/mips_linux_syscalls.h',
'services/linux_syscalls.h',
'services/x86_32_linux_syscalls.h',
'services/x86_64_linux_syscalls.h',
diff --git a/sandbox/linux/seccomp-bpf-helpers/DEPS b/sandbox/linux/seccomp-bpf-helpers/DEPS
index e8000d3..d4b2611 100644
--- a/sandbox/linux/seccomp-bpf-helpers/DEPS
+++ b/sandbox/linux/seccomp-bpf-helpers/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+sandbox/linux/bpf_dsl",
"+sandbox/linux/services",
"+sandbox/linux/seccomp-bpf",
]
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index a9fb104..7f4d559 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -23,6 +23,12 @@
// Changing this implementation will have an effect on *all* policies.
// Currently this means: Renderer/Worker, GPU, Flash and NaCl.
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Arg;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::If;
+using sandbox::bpf_dsl::ResultExpr;
+
namespace sandbox {
namespace {
@@ -43,6 +49,9 @@
#if defined(__arm__)
SyscallSets::IsArmPrivate(sysno) ||
#endif
+#if defined(__mips__)
+ SyscallSets::IsMipsPrivate(sysno) ||
+#endif
SyscallSets::IsAllowedOperationOnFd(sysno);
}
@@ -72,125 +81,130 @@
SyscallSets::IsNuma(sysno) ||
SyscallSets::IsPrctl(sysno) ||
SyscallSets::IsProcessGroupOrSession(sysno) ||
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
SyscallSets::IsSocketCall(sysno) ||
#endif
#if defined(__arm__)
SyscallSets::IsArmPciConfig(sysno) ||
#endif
+#if defined(__mips__)
+ SyscallSets::IsMipsMisc(sysno) ||
+#endif
SyscallSets::IsTimer(sysno);
}
// |fs_denied_errno| is the errno return for denied filesystem access.
-ErrorCode EvaluateSyscallImpl(int fs_denied_errno,
- pid_t current_pid,
- SandboxBPF* sandbox,
- int sysno) {
+ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
+ pid_t current_pid,
+ int sysno) {
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
defined(MEMORY_SANITIZER)
// TCGETS is required by the sanitizers on failure.
if (sysno == __NR_ioctl) {
- return RestrictIoctl(sandbox);
+ return RestrictIoctl();
}
if (sysno == __NR_sched_getaffinity) {
- return ErrorCode(ErrorCode::ERR_ALLOWED);
+ return Allow();
}
if (sysno == __NR_sigaltstack) {
// Required for better stack overflow detection in ASan. Disallowed in
// non-ASan builds.
- return ErrorCode(ErrorCode::ERR_ALLOWED);
+ return Allow();
}
#endif // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||
// defined(MEMORY_SANITIZER)
if (IsBaselinePolicyAllowed(sysno)) {
- return ErrorCode(ErrorCode::ERR_ALLOWED);
+ return Allow();
}
if (sysno == __NR_clone) {
- return RestrictCloneToThreadsAndEPERMFork(sandbox);
+ return RestrictCloneToThreadsAndEPERMFork();
}
if (sysno == __NR_fcntl)
- return RestrictFcntlCommands(sandbox);
+ return RestrictFcntlCommands();
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
if (sysno == __NR_fcntl64)
- return RestrictFcntlCommands(sandbox);
+ return RestrictFcntlCommands();
#endif
+ // fork() is never used as a system call (clone() is used instead), but we
+ // have seen it in fallback code on Android.
+ if (sysno == __NR_fork) {
+ return Error(EPERM);
+ }
+
if (sysno == __NR_futex)
- return RestrictFutex(sandbox);
+ return RestrictFutex();
if (sysno == __NR_madvise) {
// Only allow MADV_DONTNEED (aka MADV_FREE).
- return sandbox->Cond(2, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, MADV_DONTNEED,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- ErrorCode(EPERM));
+ const Arg<int> advice(2);
+ return If(advice == MADV_DONTNEED, Allow()).Else(Error(EPERM));
}
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
if (sysno == __NR_mmap)
- return RestrictMmapFlags(sandbox);
+ return RestrictMmapFlags();
#endif
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
if (sysno == __NR_mmap2)
- return RestrictMmapFlags(sandbox);
+ return RestrictMmapFlags();
#endif
if (sysno == __NR_mprotect)
- return RestrictMprotectFlags(sandbox);
+ return RestrictMprotectFlags();
if (sysno == __NR_prctl)
- return sandbox::RestrictPrctl(sandbox);
+ return sandbox::RestrictPrctl();
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
if (sysno == __NR_socketpair) {
// Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different);
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, AF_UNIX,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(CrashSIGSYS_Handler, NULL));
+ const Arg<int> domain(0);
+ return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS());
}
#endif
if (SyscallSets::IsKill(sysno)) {
- return RestrictKillTarget(current_pid, sandbox, sysno);
+ return RestrictKillTarget(current_pid, sysno);
}
if (SyscallSets::IsFileSystem(sysno) ||
SyscallSets::IsCurrentDirectory(sysno)) {
- return ErrorCode(fs_denied_errno);
+ return Error(fs_denied_errno);
}
if (SyscallSets::IsAnySystemV(sysno)) {
- return ErrorCode(EPERM);
+ return Error(EPERM);
}
if (SyscallSets::IsUmask(sysno) ||
SyscallSets::IsDeniedFileSystemAccessViaFd(sysno) ||
SyscallSets::IsDeniedGetOrModifySocket(sysno) ||
SyscallSets::IsProcessPrivilegeChange(sysno)) {
- return ErrorCode(EPERM);
+ return Error(EPERM);
}
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
if (SyscallSets::IsSocketCall(sysno))
- return RestrictSocketcallCommand(sandbox);
+ return RestrictSocketcallCommand();
#endif
if (IsBaselinePolicyWatched(sysno)) {
// Previously unseen syscalls. TODO(jln): some of these should
// be denied gracefully right away.
- return sandbox->Trap(CrashSIGSYS_Handler, NULL);
+ return CrashSIGSYS();
}
// In any other case crash the program with our SIGSYS handler.
- return sandbox->Trap(CrashSIGSYS_Handler, NULL);
+ return CrashSIGSYS();
}
} // namespace.
@@ -209,13 +223,18 @@
DCHECK_EQ(syscall(__NR_getpid), current_pid_);
}
-ErrorCode BaselinePolicy::EvaluateSyscall(SandboxBPF* sandbox,
- int sysno) const {
+ResultExpr BaselinePolicy::EvaluateSyscall(int sysno) const {
+ // Sanity check that we're only called with valid syscall numbers.
+ DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
// Make sure that this policy is used in the creating process.
if (1 == sysno) {
DCHECK_EQ(syscall(__NR_getpid), current_pid_);
}
- return EvaluateSyscallImpl(fs_denied_errno_, current_pid_, sandbox, sysno);
+ return EvaluateSyscallImpl(fs_denied_errno_, current_pid_, sysno);
+}
+
+ResultExpr BaselinePolicy::InvalidSyscall() const {
+ return CrashSIGSYS();
}
} // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
index edf4c77..8f842f0 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
@@ -5,27 +5,23 @@
#ifndef SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
-#include "sandbox/linux/seccomp-bpf/errorcode.h"
-#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/sandbox_export.h"
namespace sandbox {
-class SandboxBPF;
-class SandboxBPFPolicy;
-
// This is a helper to build seccomp-bpf policies, i.e. policies for a sandbox
// that reduces the Linux kernel's attack surface. Given its nature, it doesn't
// have a clear semantics and is mostly "implementation-defined".
//
-// This class implements the SandboxBPFPolicy interface with a "baseline"
-// policy for us within Chromium.
+// This class implements the SandboxBPFDSLPolicy interface with a "baseline"
+// policy for use within Chromium.
// The "baseline" policy is somewhat arbitrary. All Chromium policies are an
// alteration of it, and it represents a reasonable common ground to run most
// code in a sandboxed environment.
// A baseline policy is only valid for the process for which this object was
// instantiated (so do not fork() and use it in a child).
-class SANDBOX_EXPORT BaselinePolicy : public SandboxBPFPolicy {
+class SANDBOX_EXPORT BaselinePolicy : public bpf_dsl::SandboxBPFDSLPolicy {
public:
BaselinePolicy();
// |fs_denied_errno| is the errno returned when a filesystem access system
@@ -33,8 +29,9 @@
explicit BaselinePolicy(int fs_denied_errno);
virtual ~BaselinePolicy();
- virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
- int system_call_number) const OVERRIDE;
+ virtual bpf_dsl::ResultExpr EvaluateSyscall(
+ int system_call_number) const OVERRIDE;
+ virtual bpf_dsl::ResultExpr InvalidSyscall() const OVERRIDE;
private:
int fs_denied_errno_;
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
index 2fa0e93..d1899c3 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -26,7 +26,7 @@
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
-#include "sandbox/linux/services/android_futex.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
#include "sandbox/linux/services/linux_syscalls.h"
#include "sandbox/linux/services/thread_helpers.h"
#include "sandbox/linux/tests/unit_tests.h"
@@ -144,7 +144,7 @@
BPF_DEATH_TEST_C(BaselinePolicy,
DisallowedCloneFlagCrashes,
- DEATH_MESSAGE(GetCloneErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()),
BaselinePolicy) {
pid_t pid = syscall(__NR_clone, CLONE_THREAD | SIGCHLD);
HandlePostForkReturn(pid);
@@ -152,11 +152,11 @@
BPF_DEATH_TEST_C(BaselinePolicy,
DisallowedKillCrashes,
- DEATH_MESSAGE(GetKillErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetKillErrorMessageContentForTests()),
BaselinePolicy) {
BPF_ASSERT_NE(1, getpid());
kill(1, 0);
- _exit(1);
+ _exit(0);
}
BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) {
@@ -179,7 +179,7 @@
#if defined(__x86_64__) || defined(__arm__)
BPF_DEATH_TEST_C(BaselinePolicy,
SocketpairWrongDomain,
- DEATH_MESSAGE(GetErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
BaselinePolicy) {
int sv[2];
ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv));
@@ -209,19 +209,26 @@
BPF_ASSERT_EQ(EPERM, errno);
}
+BPF_DEATH_TEST_C(BaselinePolicy,
+ SIGSYS_InvalidSyscall,
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+ BaselinePolicy) {
+ Syscall::InvalidCall();
+}
+
// A failing test using this macro could be problematic since we perform
// system calls by passing "0" as every argument.
// The kernel could SIGSEGV the process or the system call itself could reboot
// the machine. Some thoughts have been given when hand-picking the system
// calls below to limit any potential side effects outside of the current
// process.
-#define TEST_BASELINE_SIGSYS(sysno) \
- BPF_DEATH_TEST_C(BaselinePolicy, \
- SIGSYS_##sysno, \
- DEATH_MESSAGE(GetErrorMessageContentForTests()), \
- BaselinePolicy) { \
- syscall(sysno, 0, 0, 0, 0, 0, 0); \
- _exit(1); \
+#define TEST_BASELINE_SIGSYS(sysno) \
+ BPF_DEATH_TEST_C(BaselinePolicy, \
+ SIGSYS_##sysno, \
+ DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), \
+ BaselinePolicy) { \
+ syscall(sysno, 0, 0, 0, 0, 0, 0); \
+ _exit(1); \
}
TEST_BASELINE_SIGSYS(__NR_syslog);
@@ -277,7 +284,7 @@
BPF_DEATH_TEST_C(BaselinePolicy,
PrctlSigsys,
- DEATH_MESSAGE(GetPrctlErrorMessageContentForTests()),
+ DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()),
BaselinePolicy) {
prctl(PR_CAPBSET_READ, 0, 0, 0, 0);
_exit(1);
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index 57dc24e..85d3f70 100644
--- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -45,6 +45,26 @@
}
}
+// Invalid syscall values are truncated to zero.
+// On architectures where base value is zero (Intel and Arm),
+// syscall number is the same as offset from base.
+// This function returns values between 0 and 1023 on all architectures.
+// On architectures where base value is different than zero (currently only
+// Mips), we are truncating valid syscall values to offset from base.
+uint32_t SyscallNumberToOffsetFromBase(uint32_t sysno) {
+#if defined(__mips__)
+ // On MIPS syscall numbers are in different range than on x86 and ARM.
+ // Valid MIPS O32 ABI syscall __NR_syscall will be truncated to zero for
+ // simplicity.
+ sysno = sysno - __NR_Linux;
+#endif
+
+ if (sysno >= 1024)
+ sysno = 0;
+
+ return sysno;
+}
+
// Print a seccomp-bpf failure to handle |sysno| to stderr in an
// async-signal safe way.
void PrintSyscallError(uint32_t sysno) {
@@ -60,8 +80,13 @@
rem /= 10;
sysno_base10[i] = '0' + mod;
}
+#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+ static const char kSeccompErrorPrefix[] = __FILE__
+ ":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall 4000 + ";
+#else
static const char kSeccompErrorPrefix[] =
__FILE__":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall ";
+#endif
static const char kSeccompErrorPostfix[] = "\n";
WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1);
WriteToStdErr(sysno_base10, sizeof(sysno_base10));
@@ -73,9 +98,8 @@
namespace sandbox {
intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) {
- uint32_t syscall = args.nr;
- if (syscall >= 1024)
- syscall = 0;
+ uint32_t syscall = SyscallNumberToOffsetFromBase(args.nr);
+
PrintSyscallError(syscall);
// Encode 8-bits of the 1st two arguments too, so we can discern which socket
@@ -177,6 +201,30 @@
_exit(1);
}
+bpf_dsl::ResultExpr CrashSIGSYS() {
+ return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSClone() {
+ return bpf_dsl::Trap(SIGSYSCloneFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSPrctl() {
+ return bpf_dsl::Trap(SIGSYSPrctlFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSIoctl() {
+ return bpf_dsl::Trap(SIGSYSIoctlFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSKill() {
+ return bpf_dsl::Trap(SIGSYSKillFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSFutex() {
+ return bpf_dsl::Trap(SIGSYSFutexFailure, NULL);
+}
+
const char* GetErrorMessageContentForTests() {
return SECCOMP_MESSAGE_COMMON_CONTENT;
}
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
index 280afa7..4e855c5 100644
--- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/sandbox_export.h"
// The handlers are suitable for use in Trap() error codes. They are
@@ -47,6 +48,14 @@
SANDBOX_EXPORT intptr_t
SIGSYSFutexFailure(const struct arch_seccomp_data& args, void* aux);
+// Variants of the above functions for use with bpf_dsl.
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSClone();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
+
// Following four functions return substrings of error messages used
// in the above four functions. They are useful in death tests.
SANDBOX_EXPORT const char* GetErrorMessageContentForTests();
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 16c37a0..8dd8b45 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -37,6 +37,9 @@
#define MAP_STACK 0x20000 // Daisy build environment has old headers.
#endif
+#if defined(__mips__) && !defined(MAP_STACK)
+#define MAP_STACK 0x40000
+#endif
namespace {
inline bool IsArchitectureX86_64() {
@@ -63,193 +66,145 @@
#endif
}
+inline bool IsArchitectureMips() {
+#if defined(__mips__)
+ return true;
+#else
+ return false;
+#endif
+}
+
} // namespace.
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Arg;
+using sandbox::bpf_dsl::BoolExpr;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::If;
+using sandbox::bpf_dsl::ResultExpr;
+
+// TODO(mdempsky): Make BoolExpr a standalone class so these operators can
+// be resolved via argument-dependent lookup.
+using sandbox::bpf_dsl::operator||;
+using sandbox::bpf_dsl::operator&&;
+
namespace sandbox {
// Allow Glibc's and Android pthread creation flags, crash on any other
// thread creation attempts and EPERM attempts to use neither
// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
-ErrorCode RestrictCloneToThreadsAndEPERMFork(SandboxBPF* sandbox) {
- if (!IsAndroid()) {
- const uint64_t kGlibcPthreadFlags =
- CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
- CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID |
- CLONE_CHILD_CLEARTID;
+ResultExpr RestrictCloneToThreadsAndEPERMFork() {
+ const Arg<unsigned long> flags(0);
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- kGlibcPthreadFlags,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
- CLONE_VM | CLONE_THREAD,
- sandbox->Trap(SIGSYSCloneFailure, NULL),
- ErrorCode(EPERM)));
- } else {
- const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
- CLONE_SIGHAND | CLONE_THREAD |
- CLONE_SYSVSEM;
- const uint64_t kObsoleteAndroidCloneMask =
- kAndroidCloneMask | CLONE_DETACHED;
+ // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2.
+ const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
+ CLONE_SIGHAND | CLONE_THREAD |
+ CLONE_SYSVSEM;
+ const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED;
+ const BoolExpr android_test =
+ flags == kAndroidCloneMask || flags == kObsoleteAndroidCloneMask;
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- kAndroidCloneMask,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- kObsoleteAndroidCloneMask,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
- CLONE_VM | CLONE_THREAD,
- sandbox->Trap(SIGSYSCloneFailure, NULL),
- ErrorCode(EPERM))));
- }
+ const uint64_t kGlibcPthreadFlags =
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
+ CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+ const BoolExpr glibc_test = flags == kGlibcPthreadFlags;
+
+ return If(IsAndroid() ? android_test : glibc_test, Allow())
+ .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
+ .Else(CrashSIGSYSClone());
}
-ErrorCode RestrictPrctl(SandboxBPF* sandbox) {
+ResultExpr RestrictPrctl() {
// Will need to add seccomp compositing in the future. PR_SET_PTRACER is
// used by breakpad but not needed anymore.
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- PR_SET_NAME, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- PR_SET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- PR_GET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(SIGSYSPrctlFailure, NULL))));
+ const Arg<int> option(0);
+ return If(option == PR_GET_NAME || option == PR_SET_NAME ||
+ option == PR_GET_DUMPABLE || option == PR_SET_DUMPABLE,
+ Allow()).Else(CrashSIGSYSPrctl());
}
-ErrorCode RestrictIoctl(SandboxBPF* sandbox) {
- return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, TCGETS,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, FIONREAD,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(SIGSYSIoctlFailure, NULL)));
+ResultExpr RestrictIoctl() {
+ const Arg<int> request(1);
+ return If(request == TCGETS || request == FIONREAD, Allow())
+ .Else(CrashSIGSYSIoctl());
}
-ErrorCode RestrictMmapFlags(SandboxBPF* sandbox) {
+ResultExpr RestrictMmapFlags() {
// The flags you see are actually the allowed ones, and the variable is a
// "denied" mask because of the negation operator.
// Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
// MAP_POPULATE.
// TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
- uint32_t denied_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
- MAP_STACK | MAP_NORESERVE | MAP_FIXED |
- MAP_DENYWRITE);
- return sandbox->Cond(3, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
- denied_mask,
- sandbox->Trap(CrashSIGSYS_Handler, NULL),
- ErrorCode(ErrorCode::ERR_ALLOWED));
+ const uint32_t denied_mask =
+ ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_NORESERVE |
+ MAP_FIXED | MAP_DENYWRITE);
+ const Arg<int> flags(3);
+ return If((flags & denied_mask) == 0, Allow()).Else(CrashSIGSYS());
}
-ErrorCode RestrictMprotectFlags(SandboxBPF* sandbox) {
+ResultExpr RestrictMprotectFlags() {
// The flags you see are actually the allowed ones, and the variable is a
// "denied" mask because of the negation operator.
// Significantly, we don't permit weird undocumented flags such as
// PROT_GROWSDOWN.
- uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
- return sandbox->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
- denied_mask,
- sandbox->Trap(CrashSIGSYS_Handler, NULL),
- ErrorCode(ErrorCode::ERR_ALLOWED));
+ const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
+ const Arg<int> prot(2);
+ return If((prot & denied_mask) == 0, Allow()).Else(CrashSIGSYS());
}
-ErrorCode RestrictFcntlCommands(SandboxBPF* sandbox) {
+ResultExpr RestrictFcntlCommands() {
// We also restrict the flags in F_SETFL. We don't want to permit flags with
// a history of trouble such as O_DIRECT. The flags you see are actually the
// allowed ones, and the variable is a "denied" mask because of the negation
// operator.
// Glibc overrides the kernel's O_LARGEFILE value. Account for this.
int kOLargeFileFlag = O_LARGEFILE;
- if (IsArchitectureX86_64() || IsArchitectureI386())
+ if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips())
kOLargeFileFlag = 0100000;
- // TODO(jln): add TP_LONG/TP_SIZET types.
- ErrorCode::ArgType mask_long_type;
- if (sizeof(long) == 8)
- mask_long_type = ErrorCode::TP_64BIT;
- else if (sizeof(long) == 4)
- mask_long_type = ErrorCode::TP_32BIT;
- else
- NOTREACHED();
+ const Arg<int> cmd(1);
+ const Arg<long> long_arg(2);
unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
kOLargeFileFlag | O_CLOEXEC | O_NOATIME);
- return sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_GETFL,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_SETFL,
- sandbox->Cond(2, mask_long_type,
- ErrorCode::OP_HAS_ANY_BITS, denied_mask,
- sandbox->Trap(CrashSIGSYS_Handler, NULL),
- ErrorCode(ErrorCode::ERR_ALLOWED)),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_GETFD,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_SETFD,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_DUPFD,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_SETLK,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_SETLKW,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_GETLK,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL, F_DUPFD_CLOEXEC,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(CrashSIGSYS_Handler, NULL))))))))));
+ return If(cmd == F_GETFL || cmd == F_GETFD || cmd == F_SETFD ||
+ cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK ||
+ cmd == F_DUPFD || cmd == F_DUPFD_CLOEXEC ||
+ (cmd == F_SETFL && (long_arg & denied_mask) == 0),
+ Allow()).Else(CrashSIGSYS());
}
-#if defined(__i386__)
-ErrorCode RestrictSocketcallCommand(SandboxBPF* sandbox) {
+#if defined(__i386__) || defined(__mips__)
+ResultExpr RestrictSocketcallCommand() {
// Unfortunately, we are unable to restrict the first parameter to
// socketpair(2). Whilst initially sounding bad, it's noteworthy that very
// few protocols actually support socketpair(2). The scary call that we're
// worried about, socket(2), remains blocked.
- return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_SEND, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_RECV, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_SENDTO, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_RECVFROM, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_SHUTDOWN, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
- ErrorCode(EPERM)))))))));
+ const Arg<int> call(0);
+ return If(call == SYS_SOCKETPAIR || call == SYS_SHUTDOWN ||
+ call == SYS_RECV || call == SYS_SEND ||
+ call == SYS_RECVFROM || call == SYS_SENDTO ||
+ call == SYS_RECVMSG || call == SYS_SENDMSG,
+ Allow()).Else(Error(EPERM));
}
#endif
-ErrorCode RestrictKillTarget(pid_t target_pid, SandboxBPF* sandbox, int sysno) {
+ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) {
switch (sysno) {
case __NR_kill:
- case __NR_tgkill:
- return sandbox->Cond(0,
- ErrorCode::TP_32BIT,
- ErrorCode::OP_EQUAL,
- target_pid,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(SIGSYSKillFailure, NULL));
+ case __NR_tgkill: {
+ const Arg<pid_t> pid(0);
+ return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill());
+ }
case __NR_tkill:
- return sandbox->Trap(SIGSYSKillFailure, NULL);
+ return CrashSIGSYSKill();
default:
NOTREACHED();
- return sandbox->Trap(CrashSIGSYS_Handler, NULL);
+ return CrashSIGSYS();
}
}
-ErrorCode RestrictFutex(SandboxBPF* sandbox) {
+ResultExpr RestrictFutex() {
// In futex.c, the kernel does "int cmd = op & FUTEX_CMD_MASK;". We need to
// make sure that the combination below will cover every way to get
// FUTEX_CMP_REQUEUE_PI.
@@ -258,19 +213,11 @@
COMPILE_ASSERT(0 == kBannedFutexBits,
need_to_explicitly_blacklist_more_bits);
- return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- FUTEX_CMP_REQUEUE_PI,
- sandbox->Trap(SIGSYSFutexFailure, NULL),
- sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- FUTEX_CMP_REQUEUE_PI_PRIVATE,
- sandbox->Trap(SIGSYSFutexFailure, NULL),
- sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- FUTEX_CMP_REQUEUE_PI | FUTEX_CLOCK_REALTIME,
- sandbox->Trap(SIGSYSFutexFailure, NULL),
- sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- FUTEX_CMP_REQUEUE_PI_PRIVATE | FUTEX_CLOCK_REALTIME,
- sandbox->Trap(SIGSYSFutexFailure, NULL),
- ErrorCode(ErrorCode::ERR_ALLOWED)))));
+ const Arg<int> op(1);
+ return If(op == FUTEX_CMP_REQUEUE_PI || op == FUTEX_CMP_REQUEUE_PI_PRIVATE ||
+ op == (FUTEX_CMP_REQUEUE_PI | FUTEX_CLOCK_REALTIME) ||
+ op == (FUTEX_CMP_REQUEUE_PI_PRIVATE | FUTEX_CLOCK_REALTIME),
+ CrashSIGSYSFutex()).Else(Allow());
}
} // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index bc5a1c0..5bcdde1 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -8,62 +8,59 @@
#include <unistd.h>
#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/sandbox_export.h"
// These are helpers to build seccomp-bpf policies, i.e. policies for a
-// sandbox that reduces the Linux kernel's attack surface. They return an
-// SANDBOX_EXPORT ErrorCode suitable to restrict certain system call parameters.
+// sandbox that reduces the Linux kernel's attack surface. They return a
+// bpf_dsl::ResultExpr suitable to restrict certain system call parameters.
namespace sandbox {
-class ErrorCode;
-class SandboxBPF;
-
// Allow clone(2) for threads.
// Reject fork(2) attempts with EPERM.
// Don't restrict on ASAN.
// Crash if anything else is attempted.
-SANDBOX_EXPORT ErrorCode
- RestrictCloneToThreadsAndEPERMFork(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictCloneToThreadsAndEPERMFork();
// Allow PR_SET_NAME, PR_SET_DUMPABLE, PR_GET_DUMPABLE.
// Crash if anything else is attempted.
-SANDBOX_EXPORT ErrorCode RestrictPrctl(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrctl();
// Allow TCGETS and FIONREAD.
// Crash if anything else is attempted.
-SANDBOX_EXPORT ErrorCode RestrictIoctl(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictIoctl();
// Restrict the flags argument in mmap(2).
// Only allow: MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
// MAP_STACK | MAP_NORESERVE | MAP_FIXED | MAP_DENYWRITE.
// Crash if any other flag is used.
-SANDBOX_EXPORT ErrorCode RestrictMmapFlags(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMmapFlags();
// Restrict the prot argument in mprotect(2).
// Only allow: PROT_READ | PROT_WRITE | PROT_EXEC.
-SANDBOX_EXPORT ErrorCode RestrictMprotectFlags(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMprotectFlags();
// Restrict fcntl(2) cmd argument to:
// We allow F_GETFL, F_SETFL, F_GETFD, F_SETFD, F_DUPFD, F_DUPFD_CLOEXEC,
// F_SETLK, F_SETLKW and F_GETLK.
// Also, in F_SETFL, restrict the allowed flags to: O_ACCMODE | O_APPEND |
// O_NONBLOCK | O_SYNC | O_LARGEFILE | O_CLOEXEC | O_NOATIME.
-SANDBOX_EXPORT ErrorCode RestrictFcntlCommands(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictFcntlCommands();
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
// Restrict socketcall(2) to only allow socketpair(2), send(2), recv(2),
// sendto(2), recvfrom(2), shutdown(2), sendmsg(2) and recvmsg(2).
-SANDBOX_EXPORT ErrorCode RestrictSocketcallCommand(SandboxBPF* sandbox);
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSocketcallCommand();
#endif
// Restrict |sysno| (which must be kill, tkill or tgkill) by allowing tgkill or
// kill iff the first parameter is |target_pid|, crashing otherwise or if
// |sysno| is tkill.
-ErrorCode RestrictKillTarget(pid_t target_pid, SandboxBPF* sandbox, int sysno);
+bpf_dsl::ResultExpr RestrictKillTarget(pid_t target_pid, int sysno);
// Crash if FUTEX_CMP_REQUEUE_PI is used in the second argument of futex(2).
-ErrorCode RestrictFutex(SandboxBPF* sandbox);
+bpf_dsl::ResultExpr RestrictFutex();
} // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index e3db231..f31695f 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -29,7 +29,7 @@
switch (sysno) {
case __NR_clock_gettime:
case __NR_gettimeofday:
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_time:
#endif
return true;
@@ -38,11 +38,11 @@
case __NR_clock_getres: // Could be allowed.
case __NR_clock_nanosleep: // Could be allowed.
case __NR_clock_settime: // Privileged.
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_ftime: // Obsolete.
#endif
case __NR_settimeofday: // Privileged.
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_stime:
#endif
default:
@@ -89,7 +89,7 @@
case __NR_fchownat: // Should be called chownat ?
#if defined(__x86_64__)
case __NR_newfstatat: // fstatat(). EPERM not a valid errno.
-#elif defined(__i386__) || defined(__arm__)
+#elif defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_fstatat64:
#endif
case __NR_futimesat: // Should be called utimesat ?
@@ -104,7 +104,7 @@
#if defined(__i386__)
case __NR_oldlstat:
#endif
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_lstat64:
#endif
case __NR_mkdir:
@@ -122,24 +122,24 @@
#if defined(__i386__)
case __NR_oldstat:
#endif
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_stat64:
#endif
case __NR_statfs: // EPERM not a valid errno.
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_statfs64:
#endif
case __NR_symlink:
case __NR_symlinkat:
case __NR_truncate:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_truncate64:
#endif
case __NR_unlink:
case __NR_unlinkat:
case __NR_uselib: // Neither EPERM, nor ENOENT are valid errno.
case __NR_ustat: // Same as above. Deprecated.
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_utime:
#endif
case __NR_utimensat: // New.
@@ -153,12 +153,12 @@
bool SyscallSets::IsAllowedFileSystemAccessViaFd(int sysno) {
switch (sysno) {
case __NR_fstat:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_fstat64:
#endif
return true;
// TODO(jln): these should be denied gracefully as well (moved below).
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_fadvise64: // EPERM not a valid errno.
#endif
#if defined(__i386__)
@@ -170,14 +170,14 @@
case __NR_fdatasync: // EPERM not a valid errno.
case __NR_flock: // EPERM not a valid errno.
case __NR_fstatfs: // Give information about the whole filesystem.
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_fstatfs64:
#endif
case __NR_fsync: // EPERM not a valid errno.
#if defined(__i386__)
case __NR_oldfstat:
#endif
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_sync_file_range: // EPERM not a valid errno.
#elif defined(__arm__)
case __NR_arm_sync_file_range: // EPERM not a valid errno.
@@ -196,11 +196,13 @@
case __NR_ftruncate:
#if defined(__i386__) || defined(__arm__)
case __NR_fchown32:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_ftruncate64:
#endif
case __NR_getdents: // EPERM not a valid errno.
case __NR_getdents64: // EPERM not a valid errno.
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_readdir:
#endif
return true;
@@ -288,7 +290,7 @@
case __NR_rt_sigaction:
case __NR_rt_sigprocmask:
case __NR_rt_sigreturn:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_sigaction:
case __NR_sigprocmask:
case __NR_sigreturn:
@@ -302,11 +304,11 @@
case __NR_sigaltstack:
case __NR_signalfd:
case __NR_signalfd4:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_sigpending:
case __NR_sigsuspend:
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_signal:
case __NR_sgetmask: // Obsolete.
case __NR_ssetmask:
@@ -322,12 +324,12 @@
case __NR_dup:
case __NR_dup2:
case __NR_dup3:
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
case __NR_shutdown:
#endif
return true;
case __NR_fcntl:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_fcntl64:
#endif
default:
@@ -363,11 +365,15 @@
case __NR_fork:
#if defined(__i386__) || defined(__x86_64__)
case __NR_get_thread_area:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_set_thread_area:
#endif
case __NR_set_tid_address:
case __NR_unshare:
+#if !defined(__mips__)
case __NR_vfork:
+#endif
default:
return false;
}
@@ -410,7 +416,7 @@
case __NR_pipe2:
return true;
default:
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
case __NR_socketpair: // We will want to inspect its argument.
#endif
return false;
@@ -419,7 +425,7 @@
bool SyscallSets::IsDeniedGetOrModifySocket(int sysno) {
switch (sysno) {
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
case __NR_accept:
case __NR_accept4:
case __NR_bind:
@@ -433,7 +439,7 @@
}
}
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
// Big multiplexing system call for sockets.
bool SyscallSets::IsSocketCall(int sysno) {
switch (sysno) {
@@ -445,7 +451,7 @@
}
#endif
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
bool SyscallSets::IsNetworkSocketInformation(int sysno) {
switch (sysno) {
case __NR_getpeername:
@@ -469,13 +475,13 @@
case __NR_madvise:
case __NR_mincore:
case __NR_mlockall:
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_mmap:
#endif
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_mmap2:
#endif
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_modify_ldt:
#endif
case __NR_mprotect:
@@ -496,7 +502,7 @@
bool SyscallSets::IsAllowedGeneralIo(int sysno) {
switch (sysno) {
case __NR_lseek:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR__llseek:
#endif
case __NR_poll:
@@ -504,23 +510,23 @@
case __NR_pselect6:
case __NR_read:
case __NR_readv:
-#if defined(__arm__)
+#if defined(__arm__) || defined(__mips__)
case __NR_recv:
#endif
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
case __NR_recvfrom: // Could specify source.
case __NR_recvmsg: // Could specify source.
#endif
#if defined(__i386__) || defined(__x86_64__)
case __NR_select:
#endif
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR__newselect:
#endif
#if defined(__arm__)
case __NR_send:
#endif
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
case __NR_sendmsg: // Could specify destination.
case __NR_sendto: // Could specify destination.
#endif
@@ -534,7 +540,7 @@
case __NR_pwritev:
case __NR_recvmmsg: // Could specify source.
case __NR_sendfile:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_sendfile64:
#endif
case __NR_sendmmsg: // Could specify destination.
@@ -565,7 +571,7 @@
case __NR_nanosleep:
return true;
case __NR_getpriority:
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_nice:
#endif
case __NR_setpriority:
@@ -576,7 +582,7 @@
bool SyscallSets::IsAdminOperation(int sysno) {
switch (sysno) {
-#if defined(__i386__) || defined(__arm__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
case __NR_bdflush:
#endif
case __NR_kexec_load:
@@ -592,7 +598,7 @@
bool SyscallSets::IsKernelModule(int sysno) {
switch (sysno) {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_create_module:
case __NR_get_kernel_syms: // Should ENOSYS.
case __NR_query_module:
@@ -623,7 +629,7 @@
case __NR_quotactl:
case __NR_swapoff:
case __NR_swapon:
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_umount:
#endif
case __NR_umount2:
@@ -638,7 +644,7 @@
case __NR_get_mempolicy:
case __NR_getcpu:
case __NR_mbind:
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_migrate_pages:
#endif
case __NR_move_pages:
@@ -666,13 +672,13 @@
bool SyscallSets::IsGlobalProcessEnvironment(int sysno) {
switch (sysno) {
case __NR_acct: // Privileged.
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_getrlimit:
#endif
#if defined(__i386__) || defined(__arm__)
case __NR_ugetrlimit:
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_ulimit:
#endif
case __NR_getrusage:
@@ -691,7 +697,7 @@
case __NR_ptrace:
case __NR_process_vm_readv:
case __NR_process_vm_writev:
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_kcmp:
#endif
return true;
@@ -794,7 +800,7 @@
}
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
// Big system V multiplexing system call.
bool SyscallSets::IsSystemVIpc(int sysno) {
switch (sysno) {
@@ -810,7 +816,7 @@
#if defined(__x86_64__) || defined(__arm__)
return IsSystemVMessageQueue(sysno) || IsSystemVSemaphores(sysno) ||
IsSystemVSharedMemory(sysno);
-#elif defined(__i386__)
+#elif defined(__i386__) || defined(__mips__)
return IsSystemVIpc(sysno);
#endif
}
@@ -859,7 +865,7 @@
bool SyscallSets::IsTimer(int sysno) {
switch (sysno) {
case __NR_getitimer:
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_alarm:
#endif
case __NR_setitimer:
@@ -915,16 +921,16 @@
case __NR_syncfs:
case __NR_vhangup:
// The system calls below are not implemented.
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_afs_syscall:
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_break:
#endif
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_getpmsg:
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_gtty:
case __NR_idle:
case __NR_lock:
@@ -932,13 +938,13 @@
case __NR_prof:
case __NR_profil:
#endif
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
case __NR_putpmsg:
#endif
#if defined(__x86_64__)
case __NR_security:
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
case __NR_stty:
#endif
#if defined(__x86_64__)
@@ -977,4 +983,25 @@
}
#endif // defined(__arm__)
+#if defined(__mips__)
+bool SyscallSets::IsMipsPrivate(int sysno) {
+ switch (sysno) {
+ case __NR_cacheflush:
+ case __NR_cachectl:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool SyscallSets::IsMipsMisc(int sysno) {
+ switch (sysno) {
+ case __NR_sysmips:
+ case __NR_unused150:
+ return true;
+ default:
+ return false;
+ }
+}
+#endif // defined(__mips__)
} // namespace sandbox.
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
index c1e412e..b0cf10c 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
@@ -42,12 +42,12 @@
static bool IsAllowedGetOrModifySocket(int sysno);
static bool IsDeniedGetOrModifySocket(int sysno);
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
// Big multiplexing system call for sockets.
static bool IsSocketCall(int sysno);
#endif
-#if defined(__x86_64__) || defined(__arm__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
static bool IsNetworkSocketInformation(int sysno);
#endif
@@ -80,7 +80,7 @@
static bool IsSystemVMessageQueue(int sysno);
#endif
-#if defined(__i386__)
+#if defined(__i386__) || defined(__mips__)
// Big system V multiplexing system call.
static bool IsSystemVIpc(int sysno);
#endif
@@ -97,6 +97,10 @@
static bool IsArmPciConfig(int sysno);
static bool IsArmPrivate(int sysno);
#endif // defined(__arm__)
+#if defined(__mips__)
+ static bool IsMipsPrivate(int sysno);
+ static bool IsMipsMisc(int sysno);
+#endif // defined(__mips__)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(SyscallSets);
};
diff --git a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
index bd18412..eaa9ff3 100644
--- a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
@@ -134,6 +134,16 @@
BPF_ASSERT(ENOSYS == errno);
}
+const char kHelloMessage[] = "Hello";
+
+BPF_DEATH_TEST_C(BPFTest,
+ BPFDeathTestWithInlineTest,
+ DEATH_MESSAGE(kHelloMessage),
+ EnosysPtracePolicy) {
+ LOG(ERROR) << kHelloMessage;
+ _exit(1);
+}
+
} // namespace
} // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/errorcode.h b/sandbox/linux/seccomp-bpf/errorcode.h
index 2e51381..2cc001c 100644
--- a/sandbox/linux/seccomp-bpf/errorcode.h
+++ b/sandbox/linux/seccomp-bpf/errorcode.h
@@ -41,9 +41,14 @@
// indicate success, but it won't actually run the system call.
// This is very different from return ERR_ALLOWED.
ERR_MIN_ERRNO = 0,
+#if defined(__mips__)
+ // MIPS only supports errno up to 1133
+ ERR_MAX_ERRNO = 1133,
+#else
// TODO(markus): Android only supports errno up to 255
// (crbug.com/181647).
ERR_MAX_ERRNO = 4095,
+#endif
};
// While BPF filter programs always operate on 32bit quantities, the kernel
diff --git a/sandbox/linux/seccomp-bpf/linux_seccomp.h b/sandbox/linux/seccomp-bpf/linux_seccomp.h
index b3d7a55..1716655 100644
--- a/sandbox/linux/seccomp-bpf/linux_seccomp.h
+++ b/sandbox/linux/seccomp-bpf/linux_seccomp.h
@@ -23,6 +23,10 @@
#if !defined(__BIONIC__) || defined(__x86_64__)
#include <sys/types.h> // Fix for gcc 4.7, make sure __uint16_t is defined.
#include <sys/user.h>
+#if defined(__mips__)
+// sys/user.h in eglibc misses size_t definition
+#include <stddef.h>
+#endif
#endif
// For audit.h
@@ -35,6 +39,9 @@
#ifndef EM_X86_64
#define EM_X86_64 62
#endif
+#ifndef EM_MIPS
+#define EM_MIPS 8
+#endif
#ifndef __AUDIT_ARCH_64BIT
#define __AUDIT_ARCH_64BIT 0x80000000
@@ -51,6 +58,9 @@
#ifndef AUDIT_ARCH_X86_64
#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
#endif
+#ifndef AUDIT_ARCH_MIPSEL
+#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE)
+#endif
// For prctl.h
#ifndef PR_SET_SECCOMP
@@ -287,6 +297,63 @@
#define SECCOMP_PT_PARM5(_regs) (_regs).REG_r4
#define SECCOMP_PT_PARM6(_regs) (_regs).REG_r5
+#elif defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+#define MIN_SYSCALL __NR_O32_Linux
+#define MAX_PUBLIC_SYSCALL (MIN_SYSCALL + __NR_Linux_syscalls)
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+#define SECCOMP_ARCH AUDIT_ARCH_MIPSEL
+#define SYSCALL_EIGHT_ARGS
+// MIPS sigcontext_t is different from i386/x86_64 and ARM.
+// See </arch/mips/include/uapi/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[_reg])
+// Based on MIPS o32 ABI syscall convention.
+// On MIPS, when indirect syscall is being made (syscall(__NR_foo)),
+// real identificator (__NR_foo) is not in v0, but in a0
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 5)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 6)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 7)
+// Only the first 4 arguments of syscall are in registers.
+// The rest are on the stack.
+#define SECCOMP_STACKPARM(_ctx, n) (((long *)SECCOMP_REG(_ctx, 29))[(n)])
+#define SECCOMP_PARM5(_ctx) SECCOMP_STACKPARM(_ctx, 4)
+#define SECCOMP_PARM6(_ctx) SECCOMP_STACKPARM(_ctx, 5)
+#define SECCOMP_PARM7(_ctx) SECCOMP_STACKPARM(_ctx, 6)
+#define SECCOMP_PARM8(_ctx) SECCOMP_STACKPARM(_ctx, 7)
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 0)
+
+// On Mips we don't have structures like user_regs or user_regs_struct in
+// sys/user.h that we could use, so we just define regs_struct directly.
+struct regs_struct {
+ unsigned long long regs[32];
+};
+
+#define REG_a3 regs[7]
+#define REG_a2 regs[6]
+#define REG_a1 regs[5]
+#define REG_a0 regs[4]
+#define REG_v1 regs[3]
+#define REG_v0 regs[2]
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).REG_v0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_v0
+#define SECCOMP_PT_PARM1(_regs) (_regs).REG_a0
+#define SECCOMP_PT_PARM2(_regs) (_regs).REG_a1
+#define SECCOMP_PT_PARM3(_regs) (_regs).REG_a2
+#define SECCOMP_PT_PARM4(_regs) (_regs).REG_a3
+
#else
#error Unsupported target platform
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
index 95fcbc6..c25d6cf 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc
@@ -13,6 +13,7 @@
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
+#include <sys/socket.h>
#if defined(ANDROID)
// Work-around for buggy headers in Android's NDK
@@ -246,11 +247,8 @@
ErrorCode ErrnoTestPolicy::EvaluateSyscall(SandboxBPF*, int sysno) const {
DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
switch (sysno) {
-#if defined(ANDROID)
case __NR_dup3: // dup2 is a wrapper of dup3 in android
-#else
case __NR_dup2:
-#endif
// Pretend that dup2() worked, but don't actually do anything.
return ErrorCode(0);
case __NR_setuid:
@@ -662,7 +660,7 @@
// more complex uses of signals where our use of the SIGBUS mask is not
// 100% transparent. This is expected behavior.
int fds[2];
- BPF_ASSERT(pipe(fds) == 0);
+ BPF_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
bus_handler_fd_ = fds[1];
struct sigaction sa = {};
sa.sa_sigaction = SigBusHandler;
@@ -760,15 +758,13 @@
BPF_ASSERT(aux);
BrokerProcess* broker_process = static_cast<BrokerProcess*>(aux);
switch (args.nr) {
-#if defined(ANDROID)
case __NR_faccessat: // access is a wrapper of faccessat in android
+ BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD);
return broker_process->Access(reinterpret_cast<const char*>(args.args[1]),
static_cast<int>(args.args[2]));
-#else
case __NR_access:
return broker_process->Access(reinterpret_cast<const char*>(args.args[0]),
static_cast<int>(args.args[1]));
-#endif
case __NR_open:
return broker_process->Open(reinterpret_cast<const char*>(args.args[0]),
static_cast<int>(args.args[1]));
@@ -792,11 +788,8 @@
}
switch (sysno) {
-#if defined(ANDROID)
case __NR_faccessat:
-#else
case __NR_access:
-#endif
case __NR_open:
case __NR_openat:
// We get a InitializedOpenBroker class, but our trap handler wants
@@ -874,28 +867,23 @@
// We deliberately return unusual errno values upon failure, so that we
// can uniquely test for these values. In a "real" policy, you would want
// to return more traditional values.
+ int flags_argument_position = -1;
switch (sysno) {
-#if defined(ANDROID)
- case __NR_openat: // open is a wrapper of openat in android
- // Allow opening files for reading, but don't allow writing.
- COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_be_all_zero_bits);
- return sandbox->Cond(2,
- ErrorCode::TP_32BIT,
- ErrorCode::OP_HAS_ANY_BITS,
- O_ACCMODE /* 0x3 */,
- ErrorCode(EROFS),
- ErrorCode(ErrorCode::ERR_ALLOWED));
-#else
case __NR_open:
+ case __NR_openat: // open can be a wrapper for openat(2).
+ if (sysno == __NR_open) {
+ flags_argument_position = 1;
+ } else if (sysno == __NR_openat) {
+ flags_argument_position = 2;
+ }
// Allow opening files for reading, but don't allow writing.
COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_be_all_zero_bits);
- return sandbox->Cond(1,
+ return sandbox->Cond(flags_argument_position,
ErrorCode::TP_32BIT,
ErrorCode::OP_HAS_ANY_BITS,
O_ACCMODE /* 0x3 */,
ErrorCode(EROFS),
ErrorCode(ErrorCode::ERR_ALLOWED));
-#endif
case __NR_prctl:
// Allow prctl(PR_SET_DUMPABLE) and prctl(PR_GET_DUMPABLE), but
// disallow everything else.
@@ -1990,6 +1978,13 @@
return;
#endif
+#if defined(__mips__)
+ // TODO: Figure out how to support specificity of handling indirect syscalls
+ // in this test and enable it.
+ printf("This test is currently disabled on MIPS.");
+ return;
+#endif
+
pid_t pid = fork();
BPF_ASSERT_NE(-1, pid);
if (pid == 0) {
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
index 0a028b7..b0a41b0 100644
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -9,11 +9,20 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
namespace sandbox {
namespace {
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+ defined(ARCH_CPU_MIPS_FAMILY)
+// Number that's not currently used by any Linux kernel ABIs.
+const int kInvalidSyscallNumber = 0x351d3;
+#else
+#error Unrecognized architecture
+#endif
+
asm(// We need to be able to tell the kernel exactly where we made a
// system call. The C++ compiler likes to sometimes clone or
// inline code, which would inadvertently end up duplicating
@@ -50,10 +59,10 @@
// that are used internally (e.g. %ebx for position-independent
// code, and %ebp for the frame pointer), and as we need to keep at
// least a few registers available for the register allocator.
- "1:push %esi; .cfi_adjust_cfa_offset 4\n"
- "push %edi; .cfi_adjust_cfa_offset 4\n"
- "push %ebx; .cfi_adjust_cfa_offset 4\n"
- "push %ebp; .cfi_adjust_cfa_offset 4\n"
+ "1:push %esi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset esi, 0\n"
+ "push %edi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset edi, 0\n"
+ "push %ebx; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebx, 0\n"
+ "push %ebp; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebp, 0\n"
// Copy entries from the array holding the arguments into the
// correct CPU registers.
"movl 0(%edi), %ebx\n"
@@ -68,10 +77,10 @@
"2:"
// Restore any clobbered registers that we didn't declare to the
// compiler.
- "pop %ebp; .cfi_adjust_cfa_offset -4\n"
- "pop %ebx; .cfi_adjust_cfa_offset -4\n"
- "pop %edi; .cfi_adjust_cfa_offset -4\n"
- "pop %esi; .cfi_adjust_cfa_offset -4\n"
+ "pop %ebp; .cfi_restore ebp; .cfi_adjust_cfa_offset -4\n"
+ "pop %ebx; .cfi_restore ebx; .cfi_adjust_cfa_offset -4\n"
+ "pop %edi; .cfi_restore edi; .cfi_adjust_cfa_offset -4\n"
+ "pop %esi; .cfi_restore esi; .cfi_adjust_cfa_offset -4\n"
"ret\n"
".cfi_endproc\n"
"9:.size SyscallAsm, 9b-SyscallAsm\n"
@@ -171,11 +180,61 @@
#endif
".fnend\n"
"9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__mips__)
+ ".text\n"
+ ".align 4\n"
+ ".type SyscallAsm, @function\n"
+ "SyscallAsm:.ent SyscallAsm\n"
+ ".frame $sp, 40, $ra\n"
+ ".set push\n"
+ ".set noreorder\n"
+ "addiu $sp, $sp, -40\n"
+ "sw $ra, 36($sp)\n"
+ // Check if "v0" is negative. If so, do not attempt to make a
+ // system call. Instead, compute the return address that is visible
+ // to the kernel after we execute "syscall". This address can be
+ // used as a marker that BPF code inspects.
+ "bgez $v0, 1f\n"
+ " nop\n"
+ "la $v0, 2f\n"
+ "b 2f\n"
+ " nop\n"
+ // On MIPS first four arguments go to registers a0 - a3 and any
+ // argument after that goes to stack. We can go ahead and directly
+ // copy the entries from the arguments array into the appropriate
+ // CPU registers and on the stack.
+ "1:lw $a3, 28($a0)\n"
+ "lw $a2, 24($a0)\n"
+ "lw $a1, 20($a0)\n"
+ "lw $t0, 16($a0)\n"
+ "sw $a3, 28($sp)\n"
+ "sw $a2, 24($sp)\n"
+ "sw $a1, 20($sp)\n"
+ "sw $t0, 16($sp)\n"
+ "lw $a3, 12($a0)\n"
+ "lw $a2, 8($a0)\n"
+ "lw $a1, 4($a0)\n"
+ "lw $a0, 0($a0)\n"
+ // Enter the kernel
+ "syscall\n"
+ // This is our "magic" return address that the BPF filter sees.
+ // Restore the return address from the stack.
+ "2:lw $ra, 36($sp)\n"
+ "jr $ra\n"
+ " addiu $sp, $sp, 40\n"
+ ".set pop\n"
+ ".end SyscallAsm\n"
+ ".size SyscallAsm,.-SyscallAsm\n"
#endif
); // asm
} // namespace
+intptr_t Syscall::InvalidCall() {
+ // Explicitly pass eight zero arguments just in case.
+ return Call(kInvalidSyscallNumber, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
intptr_t Syscall::Call(int nr,
intptr_t p0,
intptr_t p1,
@@ -197,11 +256,15 @@
// TODO(nedeljko): Enable use of more than six parameters on architectures
// where that makes sense.
+#if defined(__mips__)
+ const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7};
+#else
DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not "
"added for this architecture";
DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not "
"added for this architecture";
const intptr_t args[6] = {p0, p1, p2, p3, p4, p5};
+#endif // defined(__mips__)
// Invoke our file-scope assembly code. The constraints have been picked
// carefully to match what the rest of the assembly code expects in input,
@@ -268,10 +331,64 @@
);
ret = inout;
}
+#elif defined(__mips__)
+ int err_status;
+ intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status);
+
+ if (err_status) {
+ // On error, MIPS returns errno from syscall instead of -errno.
+ // The purpose of this negation is for SandboxSyscall() to behave
+ // more like it would on other architectures.
+ ret = -ret;
+ }
#else
#error "Unimplemented architecture"
#endif
return ret;
}
+void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) {
+#if defined(__mips__)
+ // Mips ABI states that on error a3 CPU register has non zero value and if
+ // there is no error, it should be zero.
+ if (ret_val <= -1 && ret_val >= -4095) {
+ // |ret_val| followes the Syscall::Call() convention of being -errno on
+ // errors. In order to write correct value to return register this sign
+ // needs to be changed back.
+ ret_val = -ret_val;
+ SECCOMP_PARM4(ctx) = 1;
+ } else
+ SECCOMP_PARM4(ctx) = 0;
+#endif
+ SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val);
+}
+
+#if defined(__mips__)
+intptr_t Syscall::SandboxSyscallRaw(int nr,
+ const intptr_t* args,
+ intptr_t* err_ret) {
+ register intptr_t ret __asm__("v0") = nr;
+ // a3 register becomes non zero on error.
+ register intptr_t err_stat __asm__("a3") = 0;
+ {
+ register const intptr_t* data __asm__("a0") = args;
+ asm volatile(
+ "la $t9, SyscallAsm\n"
+ "jalr $t9\n"
+ " nop\n"
+ : "=r"(ret), "=r"(err_stat)
+ : "0"(ret),
+ "r"(data)
+ // a2 is in the clober list so inline assembly can not change its
+ // value.
+ : "memory", "ra", "t9", "a2");
+ }
+
+ // Set an error status so it can be used outside of this function
+ *err_ret = err_stat;
+
+ return ret;
+}
+#endif // defined(__mips__)
+
} // namespace sandbox
diff --git a/sandbox/linux/seccomp-bpf/syscall.h b/sandbox/linux/seccomp-bpf/syscall.h
index 10a1253..3686df5 100644
--- a/sandbox/linux/seccomp-bpf/syscall.h
+++ b/sandbox/linux/seccomp-bpf/syscall.h
@@ -5,17 +5,30 @@
#ifndef SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
#define SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+#include <signal.h>
#include <stdint.h>
#include "base/macros.h"
#include "sandbox/sandbox_export.h"
+// Android's signal.h doesn't define ucontext etc.
+#if defined(OS_ANDROID)
+#include "sandbox/linux/services/android_ucontext.h"
+#endif
+
namespace sandbox {
// This purely static class can be used to perform system calls with some
// low-level control.
class SANDBOX_EXPORT Syscall {
public:
+ // InvalidCall() invokes Call() with a platform-appropriate syscall
+ // number that is guaranteed to not be implemented (i.e., normally
+ // returns -ENOSYS).
+ // This is primarily meant to be useful for writing sandbox policy
+ // unit tests.
+ static intptr_t InvalidCall();
+
// System calls can take up to six parameters (up to eight on some
// architectures). Traditionally, glibc
// implements this property by using variadic argument lists. This works, but
@@ -112,6 +125,11 @@
return Call(nr, 0, 0, 0, 0, 0, 0, 0, 0);
}
+ // Set the registers in |ctx| to match what they would be after a system call
+ // returning |ret_val|. |ret_val| must follow the Syscall::Call() convention
+ // of being -errno on errors.
+ static void PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx);
+
private:
// This performs system call |nr| with the arguments p0 to p7 from a constant
// userland address, which is for instance observable by seccomp-bpf filters.
@@ -129,6 +147,21 @@
intptr_t p6,
intptr_t p7);
+#if defined(__mips__)
+ // This function basically does on MIPS what SandboxSyscall() is doing on
+ // other architectures. However, because of specificity of MIPS regarding
+ // handling syscall errors, SandboxSyscall() is made as a wrapper for this
+ // function in order for SandboxSyscall() to behave more like on other
+ // architectures on places where return value from SandboxSyscall() is used
+ // directly (like in most tests).
+ // The syscall "nr" is called with arguments that are set in an array on which
+ // pointer "args" points to and an information weather there is an error or no
+ // is returned to SandboxSyscall() by err_stat.
+ static intptr_t SandboxSyscallRaw(int nr,
+ const intptr_t* args,
+ intptr_t* err_stat);
+#endif // defined(__mips__)
+
DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall);
};
diff --git a/sandbox/linux/seccomp-bpf/syscall_iterator.cc b/sandbox/linux/seccomp-bpf/syscall_iterator.cc
index 89cc1cb..d1c383b 100644
--- a/sandbox/linux/seccomp-bpf/syscall_iterator.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_iterator.cc
@@ -16,14 +16,25 @@
uint32_t val;
do {
+#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+ // |num_| has been initialized to 4000, which we assume is also MIN_SYSCALL.
+ // This is true for Mips O32 ABI.
+ COMPILE_ASSERT(MIN_SYSCALL == __NR_Linux, min_syscall_should_be_4000);
+#else
// |num_| has been initialized to 0, which we assume is also MIN_SYSCALL.
// This true for supported architectures (Intel and ARM EABI).
COMPILE_ASSERT(MIN_SYSCALL == 0u, min_syscall_should_always_be_zero);
+#endif
val = num_;
+ // The syscall iterator always starts at zero.
+ // If zero is not a valid system call, iterator first returns MIN_SYSCALL -1
+ // before continuing to iterate.
+ if (num_ == 0 && MIN_SYSCALL != num_) {
+ num_ = MIN_SYSCALL - 1;
// First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL
// on Intel architectures, but leaves room for private syscalls on ARM.
- if (num_ <= MAX_PUBLIC_SYSCALL) {
+ } else if (num_ <= MAX_PUBLIC_SYSCALL) {
if (invalid_only_ && num_ < MAX_PUBLIC_SYSCALL) {
num_ = MAX_PUBLIC_SYSCALL;
} else {
diff --git a/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc
index 08a857a..6d553c8 100644
--- a/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_iterator_unittest.cc
@@ -29,7 +29,25 @@
}
}
-SANDBOX_TEST(SyscallIterator, PublicSyscallRange) {
+#if defined(__mips__)
+SANDBOX_TEST(SyscallIterator, PublicSyscallRangeMIPS) {
+ SyscallIterator iter(false);
+ uint32_t next = iter.Next();
+ SANDBOX_ASSERT(next == 0);
+
+ // Since on MIPS MIN_SYSCALL != 0 we need to move iterator to valid range.
+ next = iter.Next();
+ SANDBOX_ASSERT(next == MIN_SYSCALL - 1);
+
+ // The iterator should cover the public syscall range
+ // MIN_SYSCALL..MAX_PUBLIC_SYSCALL, without skipping syscalls.
+ for (uint32_t last = next; next < MAX_PUBLIC_SYSCALL + 1; last = next) {
+ SANDBOX_ASSERT((next = iter.Next()) == last + 1);
+ }
+ SANDBOX_ASSERT(next == MAX_PUBLIC_SYSCALL + 1);
+}
+#else
+SANDBOX_TEST(SyscallIterator, PublicSyscallRangeIntelArm) {
SyscallIterator iter(false);
uint32_t next = iter.Next();
@@ -44,6 +62,7 @@
}
SANDBOX_ASSERT(next == MAX_PUBLIC_SYSCALL + 1);
}
+#endif // defined(__mips__)
#if defined(__arm__)
SANDBOX_TEST(SyscallIterator, ARMPrivateSyscallRange) {
@@ -103,7 +122,27 @@
}
}
-SANDBOX_TEST(SyscallIterator, InvalidOnly) {
+#if defined(__mips__)
+SANDBOX_TEST(SyscallIterator, InvalidOnlyMIPS) {
+ bool invalid_only = true;
+ SyscallIterator iter(invalid_only);
+ uint32_t next = iter.Next();
+ SANDBOX_ASSERT(next == 0);
+ // For Mips O32 ABI we're assuming MIN_SYSCALL == 4000.
+ SANDBOX_ASSERT(MIN_SYSCALL == 4000);
+
+ // Since on MIPS MIN_SYSCALL != 0, we need to move iterator to valid range
+ // The iterator should skip until the last invalid syscall in this range.
+ next = iter.Next();
+ SANDBOX_ASSERT(next == MIN_SYSCALL - 1);
+ next = iter.Next();
+ // First next invalid syscall should then be |MAX_PUBLIC_SYSCALL + 1|.
+ SANDBOX_ASSERT(next == MAX_PUBLIC_SYSCALL + 1);
+}
+
+#else
+
+SANDBOX_TEST(SyscallIterator, InvalidOnlyIntelArm) {
bool invalid_only = true;
SyscallIterator iter(invalid_only);
uint32_t next = iter.Next();
@@ -128,8 +167,9 @@
next = iter.Next();
}
SANDBOX_ASSERT(next == MAX_SYSCALL + 1);
-#endif
+#endif // defined(__arm__)
}
+#endif // defined(__mips__)
} // namespace
diff --git a/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
index 4e142f4..38f31e0 100644
--- a/sandbox/linux/seccomp-bpf/syscall_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -33,6 +33,10 @@
const int kMMapNr = __NR_mmap;
#endif
+TEST(Syscall, InvalidCallReturnsENOSYS) {
+ EXPECT_EQ(-ENOSYS, Syscall::InvalidCall());
+}
+
TEST(Syscall, WellKnownEntryPoint) {
// Test that Syscall::Call(-1) is handled specially. Don't do this on ARM,
// where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
@@ -54,6 +58,9 @@
#else
EXPECT_EQ(0xEF000000u, ((uint32_t*)Syscall::Call(-1))[-1]); // SVC 0
#endif
+#elif defined(__mips__)
+ // Opcode for MIPS sycall is in the lower 16-bits
+ EXPECT_EQ(0x0cu, (((uint32_t*)Syscall::Call(-1))[-1]) & 0x0000FFFF);
#else
#warning Incomplete test case; need port for target platform
#endif
diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc
index 4c42111..ce906fc 100644
--- a/sandbox/linux/seccomp-bpf/trap.cc
+++ b/sandbox/linux/seccomp-bpf/trap.cc
@@ -150,10 +150,19 @@
struct arch_sigsys sigsys;
memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
+#if defined(__mips__)
+ // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
+ // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
+ // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
+ bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) &&
+ sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx));
+#else
+ bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx));
+#endif
+
// Some more sanity checks.
if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)) ||
- sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) ||
- sigsys.arch != SECCOMP_ARCH) {
+ sigsys_nr_is_bad || sigsys.arch != SECCOMP_ARCH) {
// TODO(markus):
// SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
// safe and can lead to bugs. We should eventually implement a different
@@ -168,13 +177,28 @@
if (sigsys.nr == __NR_clone) {
RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
}
- rc = Syscall::Call(sigsys.nr,
+#if defined(__mips__)
+ // Mips supports up to eight arguments for syscall.
+ // However, seccomp bpf can filter only up to six arguments, so using eight
+ // arguments has sense only when using UnsafeTrap() handler.
+ rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+ SECCOMP_PARM1(ctx),
+ SECCOMP_PARM2(ctx),
+ SECCOMP_PARM3(ctx),
+ SECCOMP_PARM4(ctx),
+ SECCOMP_PARM5(ctx),
+ SECCOMP_PARM6(ctx),
+ SECCOMP_PARM7(ctx),
+ SECCOMP_PARM8(ctx));
+#else
+ rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
SECCOMP_PARM1(ctx),
SECCOMP_PARM2(ctx),
SECCOMP_PARM3(ctx),
SECCOMP_PARM4(ctx),
SECCOMP_PARM5(ctx),
SECCOMP_PARM6(ctx));
+#endif // defined(__mips__)
} else {
const ErrorCode& err = trap_array_[info->si_errno - 1];
if (!err.safe_) {
@@ -185,7 +209,9 @@
// is what we are showing to TrapFnc callbacks that the system call
// evaluator registered with the sandbox.
struct arch_seccomp_data data = {
- sigsys.nr, SECCOMP_ARCH, reinterpret_cast<uint64_t>(sigsys.ip),
+ static_cast<int>(SECCOMP_SYSCALL(ctx)),
+ SECCOMP_ARCH,
+ reinterpret_cast<uint64_t>(sigsys.ip),
{static_cast<uint64_t>(SECCOMP_PARM1(ctx)),
static_cast<uint64_t>(SECCOMP_PARM2(ctx)),
static_cast<uint64_t>(SECCOMP_PARM3(ctx)),
@@ -201,7 +227,7 @@
// Update the CPU register that stores the return code of the system call
// that we just handled, and restore "errno" to the value that it had
// before entering the signal handler.
- SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc);
+ Syscall::PutValueInUcontext(rc, ctx);
errno = old_errno;
return;
diff --git a/sandbox/linux/services/android_mips_ucontext.h b/sandbox/linux/services/android_mips_ucontext.h
new file mode 100644
index 0000000..e23f1a7
--- /dev/null
+++ b/sandbox/linux/services/android_mips_ucontext.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_ANDROID_MIPS_UCONTEXT_H_
+#define SANDBOX_LINUX_SERVICES_ANDROID_MIPS_UCONTEXT_H_
+
+// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
+// except we do use sigset_t for uc_sigmask instead of a custom type.
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+// Ensure that 'stack_t' is defined.
+#include <asm/signal.h>
+
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef unsigned long greg_t;
+
+typedef struct {
+ uint32_t regmask;
+ uint32_t status;
+ uint64_t pc;
+ uint64_t gregs[32];
+ uint64_t fpregs[32];
+ uint32_t acx;
+ uint32_t fpc_csr;
+ uint32_t fpc_eir;
+ uint32_t used_math;
+ uint32_t dsp;
+ uint64_t mdhi;
+ uint64_t mdlo;
+ uint32_t hi1;
+ uint32_t lo1;
+ uint32_t hi2;
+ uint32_t lo2;
+ uint32_t hi3;
+ uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ sigset_t uc_sigmask;
+ // Other fields are not used by Google Breakpad. Don't define them.
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif // __BIONIC_HAVE_UCONTEXT_T
+
+#endif // SANDBOX_LINUX_SERVICES_ANDROID_MIPS_UCONTEXT_H_
diff --git a/sandbox/linux/services/android_ucontext.h b/sandbox/linux/services/android_ucontext.h
index caabaf5..a2df75c 100644
--- a/sandbox/linux/services/android_ucontext.h
+++ b/sandbox/linux/services/android_ucontext.h
@@ -13,6 +13,8 @@
#include "sandbox/linux/services/android_i386_ucontext.h"
#elif defined(__x86_64__)
#include "sandbox/linux/services/android_x86_64_ucontext.h"
+#elif defined(__mips__)
+#include "sandbox/linux/services/android_mips_ucontext.h"
#else
#error "No support for your architecture in Android header"
#endif
diff --git a/sandbox/linux/services/broker_process_unittest.cc b/sandbox/linux/services/broker_process_unittest.cc
index 63535cb..515dccc 100644
--- a/sandbox/linux/services/broker_process_unittest.cc
+++ b/sandbox/linux/services/broker_process_unittest.cc
@@ -416,6 +416,11 @@
// We need to allow noise because the broker will log when it receives our
// bogus IPCs.
SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, RecvMsgDescriptorLeak) {
+ // Android creates a socket on first use of the LOG call.
+ // We need to ensure this socket is open before we
+ // begin the test.
+ LOG(INFO) << "Ensure Android LOG socket is allocated";
+
// Find the four lowest available file descriptors.
int available_fds[4];
SANDBOX_ASSERT(0 == pipe(available_fds));
diff --git a/sandbox/linux/services/linux_syscalls.h b/sandbox/linux/services/linux_syscalls.h
index 77c1be8..65005ce 100644
--- a/sandbox/linux/services/linux_syscalls.h
+++ b/sandbox/linux/services/linux_syscalls.h
@@ -21,5 +21,9 @@
#include "sandbox/linux/services/arm_linux_syscalls.h"
#endif
+#if defined(__mips__)
+#include "sandbox/linux/services/mips_linux_syscalls.h"
+#endif
+
#endif // SANDBOX_LINUX_SERVICES_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/services/mips_linux_syscalls.h b/sandbox/linux/services/mips_linux_syscalls.h
new file mode 100644
index 0000000..ef609f7
--- /dev/null
+++ b/sandbox/linux/services/mips_linux_syscalls.h
@@ -0,0 +1,1412 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SERVICES_MIPS_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SERVICES_MIPS_LINUX_SYSCALLS_H_
+
+#if !defined(__mips__) || !defined(_ABIO32)
+#error "Including header on wrong architecture"
+#endif
+
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+
+#if !defined(__NR_syscall)
+#define __NR_syscall (__NR_Linux + 0)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_Linux + 1)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_Linux + 2)
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_Linux + 3)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_Linux + 4)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_Linux + 5)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_Linux + 6)
+#endif
+
+#if !defined(__NR_waitpid)
+#define __NR_waitpid (__NR_Linux + 7)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_Linux + 8)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_Linux + 9)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_Linux + 10)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_Linux + 11)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_Linux + 12)
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time (__NR_Linux + 13)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_Linux + 14)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_Linux + 15)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_Linux + 16)
+#endif
+
+#if !defined(__NR_break)
+#define __NR_break (__NR_Linux + 17)
+#endif
+
+#if !defined(__NR_unused18)
+#define __NR_unused18 (__NR_Linux + 18)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_Linux + 19)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_Linux + 20)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_Linux + 21)
+#endif
+
+#if !defined(__NR_umount)
+#define __NR_umount (__NR_Linux + 22)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_Linux + 23)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_Linux + 24)
+#endif
+
+#if !defined(__NR_stime)
+#define __NR_stime (__NR_Linux + 25)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_Linux + 26)
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm (__NR_Linux + 27)
+#endif
+
+#if !defined(__NR_unused28)
+#define __NR_unused28 (__NR_Linux + 28)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_Linux + 29)
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime (__NR_Linux + 30)
+#endif
+
+#if !defined(__NR_stty)
+#define __NR_stty (__NR_Linux + 31)
+#endif
+
+#if !defined(__NR_gtty)
+#define __NR_gtty (__NR_Linux + 32)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_Linux + 33)
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice (__NR_Linux + 34)
+#endif
+
+#if !defined(__NR_ftime)
+#define __NR_ftime (__NR_Linux + 35)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_Linux + 36)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_Linux + 37)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_Linux + 38)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_Linux + 39)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_Linux + 40)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_Linux + 41)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_Linux + 42)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_Linux + 43)
+#endif
+
+#if !defined(__NR_prof)
+#define __NR_prof (__NR_Linux + 44)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_Linux + 45)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_Linux + 46)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_Linux + 47)
+#endif
+
+#if !defined(__NR_signal)
+#define __NR_signal (__NR_Linux + 48)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_Linux + 49)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_Linux + 50)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_Linux + 51)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_Linux + 52)
+#endif
+
+#if !defined(__NR_lock)
+#define __NR_lock (__NR_Linux + 53)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_Linux + 54)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_Linux + 55)
+#endif
+
+#if !defined(__NR_mpx)
+#define __NR_mpx (__NR_Linux + 56)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_Linux + 57)
+#endif
+
+#if !defined(__NR_ulimit)
+#define __NR_ulimit (__NR_Linux + 58)
+#endif
+
+#if !defined(__NR_unused59)
+#define __NR_unused59 (__NR_Linux + 59)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_Linux + 60)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_Linux + 61)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_Linux + 62)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_Linux + 63)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_Linux + 64)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_Linux + 65)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_Linux + 66)
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction (__NR_Linux + 67)
+#endif
+
+#if !defined(__NR_sgetmask)
+#define __NR_sgetmask (__NR_Linux + 68)
+#endif
+
+#if !defined(__NR_ssetmask)
+#define __NR_ssetmask (__NR_Linux + 69)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_Linux + 70)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_Linux + 71)
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend (__NR_Linux + 72)
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending (__NR_Linux + 73)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_Linux + 74)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_Linux + 75)
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit (__NR_Linux + 76)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_Linux + 77)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_Linux + 78)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_Linux + 79)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_Linux + 80)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_Linux + 81)
+#endif
+
+#if !defined(__NR_reserved82)
+#define __NR_reserved82 (__NR_Linux + 82)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_Linux + 83)
+#endif
+
+#if !defined(__NR_unused84)
+#define __NR_unused84 (__NR_Linux + 84)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_Linux + 85)
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib (__NR_Linux + 86)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_Linux + 87)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_Linux + 88)
+#endif
+
+#if !defined(__NR_readdir)
+#define __NR_readdir (__NR_Linux + 89)
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap (__NR_Linux + 90)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_Linux + 91)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_Linux + 92)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_Linux + 93)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_Linux + 94)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_Linux + 95)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_Linux + 96)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_Linux + 97)
+#endif
+
+#if !defined(__NR_profil)
+#define __NR_profil (__NR_Linux + 98)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_Linux + 99)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_Linux + 100)
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm (__NR_Linux + 101)
+#endif
+
+#if !defined(__NR_socketcall)
+#define __NR_socketcall (__NR_Linux + 102)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_Linux + 103)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_Linux + 104)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_Linux + 105)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_Linux + 106)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_Linux + 107)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_Linux + 108)
+#endif
+
+#if !defined(__NR_unused109)
+#define __NR_unused109 (__NR_Linux + 109)
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl (__NR_Linux + 110)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_Linux + 111)
+#endif
+
+#if !defined(__NR_idle)
+#define __NR_idle (__NR_Linux + 112)
+#endif
+
+#if !defined(__NR_vm86)
+#define __NR_vm86 (__NR_Linux + 113)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_Linux + 114)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_Linux + 115)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_Linux + 116)
+#endif
+
+#if !defined(__NR_ipc)
+#define __NR_ipc (__NR_Linux + 117)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_Linux + 118)
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn (__NR_Linux + 119)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_Linux + 120)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_Linux + 121)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_Linux + 122)
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt (__NR_Linux + 123)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_Linux + 124)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_Linux + 125)
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask (__NR_Linux + 126)
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module (__NR_Linux + 127)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_Linux + 128)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_Linux + 129)
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms (__NR_Linux + 130)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_Linux + 131)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_Linux + 132)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_Linux + 133)
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush (__NR_Linux + 134)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_Linux + 135)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_Linux + 136)
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall \
+ (__NR_Linux + 137) /* Syscall for Andrew File System \
+ */
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_Linux + 138)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_Linux + 139)
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek (__NR_Linux + 140)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_Linux + 141)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_Linux + 142)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_Linux + 143)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_Linux + 144)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_Linux + 145)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_Linux + 146)
+#endif
+
+#if !defined(__NR_cacheflush)
+#define __NR_cacheflush (__NR_Linux + 147)
+#endif
+
+#if !defined(__NR_cachectl)
+#define __NR_cachectl (__NR_Linux + 148)
+#endif
+
+#if !defined(__NR_sysmips)
+#define __NR_sysmips (__NR_Linux + 149)
+#endif
+
+#if !defined(__NR_unused150)
+#define __NR_unused150 (__NR_Linux + 150)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_Linux + 151)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_Linux + 152)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_Linux + 153)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_Linux + 154)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_Linux + 155)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_Linux + 156)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_Linux + 157)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_Linux + 158)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_Linux + 159)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_Linux + 160)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_Linux + 161)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_Linux + 162)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_Linux + 163)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_Linux + 164)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_Linux + 165)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_Linux + 166)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_Linux + 167)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_Linux + 168)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_Linux + 169)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_Linux + 170)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_Linux + 171)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_Linux + 172)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_Linux + 173)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_Linux + 174)
+#endif
+
+#if !defined(__NR_recv)
+#define __NR_recv (__NR_Linux + 175)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_Linux + 176)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_Linux + 177)
+#endif
+
+#if !defined(__NR_send)
+#define __NR_send (__NR_Linux + 178)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_Linux + 179)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_Linux + 180)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_Linux + 181)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_Linux + 182)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_Linux + 183)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_Linux + 184)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_Linux + 185)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_Linux + 186)
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module (__NR_Linux + 187)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_Linux + 188)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_Linux + 189)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_Linux + 190)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_Linux + 191)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_Linux + 192)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_Linux + 193)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_Linux + 194)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_Linux + 195)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_Linux + 196)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_Linux + 197)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_Linux + 198)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_Linux + 199)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_Linux + 200)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_Linux + 201)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_Linux + 202)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_Linux + 203)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_Linux + 204)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_Linux + 205)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_Linux + 206)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_Linux + 207)
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg (__NR_Linux + 208)
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg (__NR_Linux + 209)
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 (__NR_Linux + 210)
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 (__NR_Linux + 211)
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 (__NR_Linux + 212)
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 (__NR_Linux + 213)
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 (__NR_Linux + 214)
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 (__NR_Linux + 215)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_Linux + 216)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_Linux + 217)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_Linux + 218)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_Linux + 219)
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 (__NR_Linux + 220)
+#endif
+
+#if !defined(__NR_reserved221)
+#define __NR_reserved221 (__NR_Linux + 221)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_Linux + 222)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_Linux + 223)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_Linux + 224)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_Linux + 225)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_Linux + 226)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_Linux + 227)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_Linux + 228)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_Linux + 229)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_Linux + 230)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_Linux + 231)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_Linux + 232)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_Linux + 233)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_Linux + 234)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_Linux + 235)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_Linux + 236)
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 (__NR_Linux + 237)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_Linux + 238)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_Linux + 239)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_Linux + 240)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_Linux + 241)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_Linux + 242)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_Linux + 243)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_Linux + 244)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_Linux + 245)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_Linux + 246)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_Linux + 247)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_Linux + 248)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_Linux + 249)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_Linux + 250)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_Linux + 251)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_Linux + 252)
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_Linux + 253)
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 (__NR_Linux + 254)
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 (__NR_Linux + 255)
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 (__NR_Linux + 256)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_Linux + 257)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_Linux + 258)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_Linux + 259)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_Linux + 260)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_Linux + 261)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_Linux + 262)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_Linux + 263)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_Linux + 264)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_Linux + 265)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_Linux + 266)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_Linux + 267)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_Linux + 268)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_Linux + 269)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_Linux + 270)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_Linux + 271)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_Linux + 272)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_Linux + 273)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_Linux + 274)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_Linux + 275)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_Linux + 276)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_Linux + 277)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_Linux + 278)
+#endif
+
+/* #define __NR_sys_setaltroot (__NR_Linux + 279) */
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_Linux + 280)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_Linux + 281)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_Linux + 282)
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area (__NR_Linux + 283)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_Linux + 284)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_Linux + 285)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_Linux + 286)
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages (__NR_Linux + 287)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_Linux + 288)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_Linux + 289)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_Linux + 290)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_Linux + 291)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_Linux + 292)
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 (__NR_Linux + 293)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_Linux + 294)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_Linux + 295)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_Linux + 296)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_Linux + 297)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_Linux + 298)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_Linux + 299)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_Linux + 300)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_Linux + 301)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_Linux + 302)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_Linux + 303)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_Linux + 304)
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range (__NR_Linux + 305)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_Linux + 306)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_Linux + 307)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_Linux + 308)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_Linux + 309)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_Linux + 310)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_Linux + 311)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_Linux + 312)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_Linux + 313)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_Linux + 314)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_Linux + 315)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_Linux + 316)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_Linux + 317)
+#endif
+
+#if !defined(__NR_timerfd)
+#define __NR_timerfd (__NR_Linux + 318)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 319)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 320)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_Linux + 321)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_Linux + 322)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_Linux + 323)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_Linux + 324)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_Linux + 325)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_Linux + 326)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_Linux + 327)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_Linux + 328)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_Linux + 329)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_Linux + 330)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_Linux + 331)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 332)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_Linux + 333)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_Linux + 334)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_Linux + 335)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_Linux + 336)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_Linux + 337)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_Linux + 338)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_Linux + 339)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_Linux + 340)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_Linux + 341)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_Linux + 342)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_Linux + 343)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_Linux + 344)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_Linux + 345)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_Linux + 346)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_Linux + 347)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_Linux + 348)
+#endif
+
+#endif // SANDBOX_LINUX_SERVICES_MIPS_LINUX_SYSCALLS_H_
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc
index 6f3ea32..25b6dc6 100644
--- a/sandbox/linux/tests/unit_tests.cc
+++ b/sandbox/linux/tests/unit_tests.cc
@@ -69,6 +69,12 @@
static const int kExitWithAssertionFailure = 1;
static const int kExitForTimeout = 2;
+#if !defined(OS_ANDROID)
+// This is due to StackDumpSignalHandler() performing _exit(1).
+// TODO(jln): get rid of the collision with kExitWithAssertionFailure.
+const int kExitAfterSIGSEGV = 1;
+#endif
+
static void SigAlrmHandler(int) {
const char failure_message[] = "Timeout reached!\n";
// Make sure that we never block here.
@@ -250,9 +256,33 @@
const char* expected_msg = static_cast<const char*>(aux);
bool subprocess_terminated_normally = WIFEXITED(status);
- ASSERT_TRUE(subprocess_terminated_normally) << details;
+ ASSERT_TRUE(subprocess_terminated_normally) << "Exit status: " << status
+ << " " << details;
int subprocess_exit_status = WEXITSTATUS(status);
- ASSERT_EQ(kExitWithAssertionFailure, subprocess_exit_status) << details;
+ ASSERT_EQ(1, subprocess_exit_status) << details;
+
+ bool subprocess_exited_without_matching_message =
+ msg.find(expected_msg) == std::string::npos;
+ EXPECT_FALSE(subprocess_exited_without_matching_message) << details;
+}
+
+void UnitTests::DeathSEGVMessage(int status,
+ const std::string& msg,
+ const void* aux) {
+ std::string details(TestFailedMessage(msg));
+ const char* expected_msg = static_cast<const char*>(aux);
+
+#if defined(OS_ANDROID)
+ const bool subprocess_got_sigsegv =
+ WIFSIGNALED(status) && (SIGSEGV == WTERMSIG(status));
+#else
+ const bool subprocess_got_sigsegv =
+ WIFEXITED(status) && (kExitAfterSIGSEGV == WEXITSTATUS(status));
+#endif
+
+ ASSERT_TRUE(subprocess_got_sigsegv) << "Exit status: " << status
+ << " " << details;
+
bool subprocess_exited_without_matching_message =
msg.find(expected_msg) == std::string::npos;
EXPECT_FALSE(subprocess_exited_without_matching_message) << details;
diff --git a/sandbox/linux/tests/unit_tests.h b/sandbox/linux/tests/unit_tests.h
index 7003e6c..f745e13 100644
--- a/sandbox/linux/tests/unit_tests.h
+++ b/sandbox/linux/tests/unit_tests.h
@@ -58,6 +58,9 @@
#define DEATH_MESSAGE(msg) \
sandbox::UnitTests::DeathMessage, \
static_cast<const void*>(static_cast<const char*>(msg))
+#define DEATH_SEGV_MESSAGE(msg) \
+ sandbox::UnitTests::DeathSEGVMessage, \
+ static_cast<const void*>(static_cast<const char*>(msg))
#define DEATH_EXIT_CODE(rc) \
sandbox::UnitTests::DeathExitCode, \
reinterpret_cast<void*>(static_cast<intptr_t>(rc))
@@ -148,6 +151,16 @@
// in SANDBOX_ASSERT() and/or SANDBOX_DIE().
static void DeathMessage(int status, const std::string& msg, const void* aux);
+ // Like DeathMessage() but the process must be terminated with a segmentation
+ // fault.
+ // Implementation detail: On Linux (but not on Android), this does check for
+ // the return value of our default signal handler rather than for the actual
+ // reception of a SIGSEGV.
+ // TODO(jln): make this more robust.
+ static void DeathSEGVMessage(int status,
+ const std::string& msg,
+ const void* aux);
+
// A DeathCheck method that verifies that the test completed with a
// particular exit code. If the test output any messages to stderr, they are
// silently ignored. The expected exit code should be passed in by
diff --git a/sandbox/linux/tests/unit_tests_unittest.cc b/sandbox/linux/tests/unit_tests_unittest.cc
index 8d8b28e..57799b1 100644
--- a/sandbox/linux/tests/unit_tests_unittest.cc
+++ b/sandbox/linux/tests/unit_tests_unittest.cc
@@ -34,6 +34,25 @@
raise(kExpectedSignalNumber);
}
+SANDBOX_DEATH_TEST(UnitTests,
+ DeathWithMessage,
+ DEATH_MESSAGE("Hello")) {
+ LOG(ERROR) << "Hello";
+ _exit(1);
+}
+
+SANDBOX_DEATH_TEST(UnitTests,
+ SEGVDeathWithMessage,
+ DEATH_SEGV_MESSAGE("Hello")) {
+ LOG(ERROR) << "Hello";
+ while (1) {
+ volatile char* addr = reinterpret_cast<volatile char*>(NULL);
+ *addr = '\0';
+ }
+
+ _exit(2);
+}
+
SANDBOX_TEST_ALLOW_NOISE(UnitTests, NoisyTest) {
LOG(ERROR) << "The cow says moo!";
}