From d49a019f05d0daead9859dbf21a9f159a8d13e54 Mon Sep 17 00:00:00 2001
From: Wang Qing <wangqing-hf@loongson.cn>
Date: Fri, 14 Jul 2017 16:21:21 +0800
Subject: [PATCH] Add support for using seccomp_bpf on mips64el.

Currently, seccomp_bpf is not supported on mips64el, and the build
configuration sets use_seccomp_bpf=false on mips64el. This CL adds
support for seccomp-bpf on mips64el, and resolves many compiler errors
when compiling on mips64el.

This patch merge into chromium master branch:
https://chromium.googlesource.com/chromium/src/+/534d7ce2af699715acfc4fe516ef3c2ffee65bc5

BUG: 742738
R= machenbach@chromium.org, brettw@chromium.org
---
 base/macros.h                                      | 10 +++
 .../sandbox_linux/sandbox_seccomp_bpf_linux.cc     |  4 +-
 sandbox/features.gni                               |  5 +-
 sandbox/linux/BUILD.gn                             |  1 +
 sandbox/linux/bpf_dsl/linux_syscall_ranges.h       |  9 ++-
 sandbox/linux/bpf_dsl/seccomp_macros.h             | 63 +++++++++++++++-
 sandbox/linux/bpf_dsl/syscall_set.cc               |  5 +-
 .../linux/seccomp-bpf-helpers/baseline_policy.cc   |  8 +-
 .../linux/seccomp-bpf-helpers/sigsys_handlers.cc   |  2 +-
 sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc  | 88 ++++++++++++----------
 sandbox/linux/seccomp-bpf-helpers/syscall_sets.h   | 13 ++--
 sandbox/linux/seccomp-bpf/syscall.cc               | 51 ++++++++++++-
 sandbox/linux/system_headers/linux_seccomp.h       |  3 +
 sandbox/linux/system_headers/linux_signal.h        |  9 ++-
 sandbox/linux/system_headers/linux_syscalls.h      |  4 +-
 sandbox/linux/system_headers/linux_ucontext.h      |  4 +-
 .../linux/system_headers/mips64_linux_syscalls.h   |  2 +-
 .../linux/system_headers/mips64_linux_ucontext.h   | 50 ++++++++++++
 sandbox/linux/system_headers/mips_linux_syscalls.h |  2 +-
 20 files changed, 267 insertions(+), 67 deletions(-)
 create mode 100644 sandbox/linux/system_headers/mips64_linux_ucontext.h

diff --git a/base/macros.h b/base/macros.h
index 154d4b0..d88119a 100644
--- a/base/macros.h
+++ b/base/macros.h
@@ -12,6 +12,16 @@
 
 #include <stddef.h>  // For size_t.
 
+// Distinguish mips32.
+#if defined(__mips__) && (_MIPS_SIM == _ABIO32)
+#define __mips32__
+#endif
+
+// Distinguish mips64.
+#if defined(__mips__) && (_MIPS_SIM == _ABI64)
+#define __mips64__
+#endif
+
 // Put this in the declarations for a class to be uncopyable.
 #define DISALLOW_COPY(TypeName) \
   TypeName(const TypeName&) = delete
diff --git a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
index 9b27f94..1ab05a7 100644
--- a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
+++ b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc
@@ -47,9 +47,9 @@ using sandbox::bpf_dsl::ResultExpr;
 
 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure
 // that we think twice about this when adding a new architecture.
-#if !defined(ARCH_CPU_ARM64)
+#if !defined(ARCH_CPU_ARM64) && !defined(ARCH_CPU_MIPS64EL)
 #error "Seccomp-bpf disabled on supported architecture!"
-#endif  // !defined(ARCH_CPU_ARM64)
+#endif  // !defined(ARCH_CPU_ARM64) && !defined(ARCH_CPU_MIPS64EL)
 
 #endif  //
 
diff --git a/sandbox/features.gni b/sandbox/features.gni
index aa18c04..89693c5 100644
--- a/sandbox/features.gni
+++ b/sandbox/features.gni
@@ -4,13 +4,14 @@
 
 import("//build/config/nacl/config.gni")
 
-# The seccomp-bpf sandbox is only supported on five architectures
+# The seccomp-bpf sandbox is only supported on six architectures
 # currently.
 # Do not disable seccomp_bpf anywhere without talking to
 # security@chromium.org!
 use_seccomp_bpf =
     (is_linux || is_android) &&
     (current_cpu == "x86" || current_cpu == "x64" || current_cpu == "arm" ||
-     current_cpu == "arm64" || current_cpu == "mipsel")
+     current_cpu == "arm64" || current_cpu == "mipsel" ||
+     current_cpu == "mips64el")
 
 use_seccomp_bpf = use_seccomp_bpf || is_nacl_nonsfi
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index 421d8b0..4b321e2 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -431,6 +431,7 @@ source_set("sandbox_services_headers") {
     "system_headers/linux_time.h",
     "system_headers/linux_ucontext.h",
     "system_headers/mips64_linux_syscalls.h",
+    "system_headers/mips64_linux_ucontext.h",
     "system_headers/mips_linux_syscalls.h",
     "system_headers/mips_linux_ucontext.h",
     "system_headers/x86_32_linux_syscalls.h",
diff --git a/sandbox/linux/bpf_dsl/linux_syscall_ranges.h b/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
index a747770..334a00b 100644
--- a/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
+++ b/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
@@ -33,16 +33,19 @@
 #define MIN_GHOST_SYSCALL   (MIN_PRIVATE_SYSCALL + 0xfff0u)
 #define MAX_SYSCALL         (MIN_GHOST_SYSCALL + 4u)
 
-#elif defined(__mips__) && (_MIPS_SIM == _ABIO32)
+#elif defined(__mips32__)
 
 #include <asm/unistd.h>  // for __NR_O32_Linux and __NR_Linux_syscalls
 #define MIN_SYSCALL         __NR_O32_Linux
 #define MAX_PUBLIC_SYSCALL  (MIN_SYSCALL + __NR_Linux_syscalls)
 #define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
 
-#elif defined(__mips__) && (_MIPS_SIM == _ABI64)
+#elif defined(__mips64__)
 
-#error "Add support to header file"
+#include <asm/unistd.h>  // for __NR_64_Linux and __NR_64_Linux_syscalls
+#define MIN_SYSCALL         __NR_64_Linux
+#define MAX_PUBLIC_SYSCALL  (MIN_SYSCALL + __NR_64_Linux_syscalls)
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
 
 #elif defined(__aarch64__)
 
diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h
index af70f21..e4e8142 100644
--- a/sandbox/linux/bpf_dsl/seccomp_macros.h
+++ b/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -190,7 +190,7 @@ typedef user_regs regs_struct;
 #define SECCOMP_PT_PARM5(_regs)   (_regs).REG_r4
 #define SECCOMP_PT_PARM6(_regs)   (_regs).REG_r5
 
-#elif defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+#elif defined(__mips32__)
 #define SECCOMP_ARCH        AUDIT_ARCH_MIPSEL
 #define SYSCALL_EIGHT_ARGS
 // MIPS sigcontext_t is different from i386/x86_64 and ARM.
@@ -224,7 +224,7 @@ typedef user_regs regs_struct;
 #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
+// 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];
@@ -244,6 +244,65 @@ struct regs_struct {
 #define SECCOMP_PT_PARM3(_regs)   (_regs).REG_a2
 #define SECCOMP_PT_PARM4(_regs)   (_regs).REG_a3
 
+#elif defined(__mips64__)
+#define SECCOMP_ARCH        AUDIT_ARCH_MIPSEL64
+#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 n64 ABI syscall convention.
+// On MIPS, when an indirect syscall is being made (syscall(__NR_foo)),
+// the real identifier (__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)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, 8)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, 9)
+#define SECCOMP_PARM7(_ctx)     SECCOMP_REG(_ctx, 10)
+#define SECCOMP_PARM8(_ctx)     SECCOMP_REG(_ctx, 11)
+#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_a7 regs[11]
+#define REG_a6 regs[10]
+#define REG_a5 regs[9]
+#define REG_a4 regs[8]
+#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
+#define SECCOMP_PT_PARM5(_regs)   (_regs).REG_a4
+#define SECCOMP_PT_PARM6(_regs)   (_regs).REG_a5
+#define SECCOMP_PT_PARM7(_regs)   (_regs).REG_a6
+#define SECCOMP_PT_PARM8(_regs)   (_regs).REG_a7
+
 #elif defined(__aarch64__)
 struct regs_struct {
   unsigned long long regs[31];
diff --git a/sandbox/linux/bpf_dsl/syscall_set.cc b/sandbox/linux/bpf_dsl/syscall_set.cc
index 3d61fa3..b975a2b 100644
--- a/sandbox/linux/bpf_dsl/syscall_set.cc
+++ b/sandbox/linux/bpf_dsl/syscall_set.cc
@@ -14,9 +14,12 @@ namespace sandbox {
 
 namespace {
 
-#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+#if defined(__mips32__)
 // This is true for Mips O32 ABI.
 static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000");
+#elif defined(__mips64__)
+// This is true for MIPS N64 ABI.
+static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 5000");
 #else
 // This true for supported architectures (Intel and ARM EABI).
 static_assert(MIN_SYSCALL == 0u,
diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
index 4889a9a..d06e765 100644
--- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -86,7 +86,7 @@ bool IsBaselinePolicyWatched(int sysno) {
          SyscallSets::IsNuma(sysno) ||
          SyscallSets::IsPrctl(sysno) ||
          SyscallSets::IsProcessGroupOrSession(sysno) ||
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
          SyscallSets::IsSocketCall(sysno) ||
 #endif
 #if defined(__arm__)
@@ -147,7 +147,7 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
   if (sysno == __NR_fcntl)
     return RestrictFcntlCommands();
 
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
   if (sysno == __NR_fcntl64)
     return RestrictFcntlCommands();
 #endif
@@ -191,7 +191,7 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
     return RestrictMmapFlags();
 #endif
 
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
   if (sysno == __NR_mmap2)
     return RestrictMmapFlags();
 #endif
@@ -241,7 +241,7 @@ ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
     return Error(EPERM);
   }
 
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
   if (SyscallSets::IsSocketCall(sysno))
     return RestrictSocketcallCommand();
 #endif
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index e6c64de..68890d2 100644
--- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -95,7 +95,7 @@ void PrintSyscallError(uint32_t sysno) {
     sysno_base10[i] = '0' + mod;
   }
 
-#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+#if defined(__mips32__)
   static const char kSeccompErrorPrefix[] = __FILE__
       ":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall 4000 + ";
 #else
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
index 1d9f95c..9f1cdef 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -28,7 +28,7 @@ bool SyscallSets::IsKill(int sysno) {
 bool SyscallSets::IsAllowedGettime(int sysno) {
   switch (sysno) {
     case __NR_gettimeofday:
-#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips32__)
     case __NR_time:
 #endif
       return true;
@@ -38,11 +38,11 @@ bool SyscallSets::IsAllowedGettime(int sysno) {
     case __NR_clock_gettime:
     case __NR_clock_nanosleep:  // Could be allowed.
     case __NR_clock_settime:    // Privileged.
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_ftime:  // Obsolete.
 #endif
     case __NR_settimeofday:  // Privileged.
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_stime:
 #endif
     default:
@@ -97,7 +97,9 @@ bool SyscallSets::IsFileSystem(int sysno) {
     case __NR_stat:  // EPERM not a valid errno.
     case __NR_symlink:
     case __NR_unlink:
+#if !defined(__mips64__)
     case __NR_uselib:  // Neither EPERM, nor ENOENT are valid errno.
+#endif
     case __NR_ustat:   // Same as above. Deprecated.
     case __NR_utimes:
 #endif  // !defined(__aarch64__)
@@ -108,7 +110,7 @@ bool SyscallSets::IsFileSystem(int sysno) {
     case __NR_fchownat:  // Should be called chownat ?
 #if defined(__x86_64__) || defined(__aarch64__)
     case __NR_newfstatat:  // fstatat(). EPERM not a valid errno.
-#elif defined(__i386__) || defined(__arm__) || defined(__mips__)
+#elif defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_fstatat64:
 #endif
 #if defined(__i386__) || defined(__arm__)
@@ -117,7 +119,7 @@ bool SyscallSets::IsFileSystem(int sysno) {
     case __NR_linkat:
     case __NR_lookup_dcookie:  // ENOENT not a valid errno.
 
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_lstat64:
 #endif
     case __NR_memfd_create:
@@ -131,16 +133,16 @@ bool SyscallSets::IsFileSystem(int sysno) {
     case __NR_readlinkat:
     case __NR_renameat:
     case __NR_renameat2:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_stat64:
 #endif
     case __NR_statfs:  // EPERM not a valid errno.
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_statfs64:
 #endif
     case __NR_symlinkat:
     case __NR_truncate:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_truncate64:
 #endif
     case __NR_unlinkat:
@@ -157,7 +159,7 @@ bool SyscallSets::IsFileSystem(int sysno) {
 bool SyscallSets::IsAllowedFileSystemAccessViaFd(int sysno) {
   switch (sysno) {
     case __NR_fstat:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_fstat64:
 #endif
       return true;
@@ -174,7 +176,7 @@ bool SyscallSets::IsAllowedFileSystemAccessViaFd(int sysno) {
     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__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_fstatfs64:
 #endif
     case __NR_fsync:  // EPERM not a valid errno.
@@ -202,14 +204,14 @@ bool SyscallSets::IsDeniedFileSystemAccessViaFd(int sysno) {
 #if defined(__i386__) || defined(__arm__)
     case __NR_fchown32:
 #endif
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_ftruncate64:
 #endif
 #if !defined(__aarch64__)
     case __NR_getdents:    // EPERM not a valid errno.
 #endif
     case __NR_getdents64:  // EPERM not a valid errno.
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_readdir:
 #endif
       return true;
@@ -299,7 +301,7 @@ bool SyscallSets::IsAllowedSignalHandling(int sysno) {
     case __NR_rt_sigaction:
     case __NR_rt_sigprocmask:
     case __NR_rt_sigreturn:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_sigaction:
     case __NR_sigprocmask:
     case __NR_sigreturn:
@@ -315,11 +317,11 @@ bool SyscallSets::IsAllowedSignalHandling(int sysno) {
     case __NR_signalfd:
 #endif
     case __NR_signalfd4:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_sigpending:
     case __NR_sigsuspend:
 #endif
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_signal:
     case __NR_sgetmask:  // Obsolete.
     case __NR_ssetmask:
@@ -343,7 +345,7 @@ bool SyscallSets::IsAllowedOperationOnFd(int sysno) {
 #endif
       return true;
     case __NR_fcntl:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_fcntl64:
 #endif
     default:
@@ -460,12 +462,14 @@ bool SyscallSets::IsDeniedGetOrModifySocket(int sysno) {
   }
 }
 
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
 // Big multiplexing system call for sockets.
 bool SyscallSets::IsSocketCall(int sysno) {
   switch (sysno) {
+#if !defined(__mips64__)
     case __NR_socketcall:
       return true;
+#endif
     default:
       return false;
   }
@@ -500,10 +504,10 @@ bool SyscallSets::IsAllowedAddressSpaceAccess(int sysno) {
     defined(__aarch64__)
     case __NR_mmap:
 #endif
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_mmap2:
 #endif
-#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips32__)
     case __NR_modify_ldt:
 #endif
     case __NR_mprotect:
@@ -524,7 +528,7 @@ bool SyscallSets::IsAllowedAddressSpaceAccess(int sysno) {
 bool SyscallSets::IsAllowedGeneralIo(int sysno) {
   switch (sysno) {
     case __NR_lseek:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR__llseek:
 #endif
 #if !defined(__aarch64__)
@@ -534,7 +538,7 @@ bool SyscallSets::IsAllowedGeneralIo(int sysno) {
     case __NR_pselect6:
     case __NR_read:
     case __NR_readv:
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips32__)
     case __NR_recv:
 #endif
 #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
@@ -548,7 +552,7 @@ bool SyscallSets::IsAllowedGeneralIo(int sysno) {
 #if defined(__i386__) || defined(__arm__) || defined(__mips__)
     case __NR__newselect:
 #endif
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips32__)
     case __NR_send:
 #endif
 #if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
@@ -566,7 +570,7 @@ bool SyscallSets::IsAllowedGeneralIo(int sysno) {
     case __NR_pwritev:
     case __NR_recvmmsg:  // Could specify source.
     case __NR_sendfile:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_sendfile64:
 #endif
     case __NR_sendmmsg:  // Could specify destination.
@@ -608,7 +612,7 @@ bool SyscallSets::IsAllowedBasicScheduler(int sysno) {
     case __NR_nanosleep:
       return true;
     case __NR_getpriority:
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_nice:
 #endif
     case __NR_setpriority:
@@ -619,7 +623,7 @@ bool SyscallSets::IsAllowedBasicScheduler(int sysno) {
 
 bool SyscallSets::IsAdminOperation(int sysno) {
   switch (sysno) {
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || defined(__mips32__)
     case __NR_bdflush:
 #endif
     case __NR_kexec_load:
@@ -667,7 +671,7 @@ bool SyscallSets::IsFsControl(int sysno) {
     case __NR_quotactl:
     case __NR_swapoff:
     case __NR_swapon:
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_umount:
 #endif
     case __NR_umount2:
@@ -718,7 +722,7 @@ bool SyscallSets::IsGlobalProcessEnvironment(int sysno) {
 #if defined(__i386__) || defined(__arm__)
     case __NR_ugetrlimit:
 #endif
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_ulimit:
 #endif
     case __NR_getrusage:
@@ -799,10 +803,9 @@ bool SyscallSets::IsKeyManagement(int sysno) {
   }
 }
 
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
-bool SyscallSets::IsSystemVSemaphores(int sysno) {
-  switch (sysno) {
-    case __NR_semctl:
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__mips64__)
+bool SyscallSets::IsSystemVSemaphores(int sysno) { switch (sysno) { case __NR_semctl:
     case __NR_semget:
     case __NR_semop:
     case __NR_semtimedop:
@@ -813,7 +816,8 @@ bool SyscallSets::IsSystemVSemaphores(int sysno) {
 }
 #endif
 
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__mips64__)
 // These give a lot of ambient authority and bypass the setuid sandbox.
 bool SyscallSets::IsSystemVSharedMemory(int sysno) {
   switch (sysno) {
@@ -828,7 +832,8 @@ bool SyscallSets::IsSystemVSharedMemory(int sysno) {
 }
 #endif
 
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__mips64__)
 bool SyscallSets::IsSystemVMessageQueue(int sysno) {
   switch (sysno) {
     case __NR_msgctl:
@@ -842,12 +847,14 @@ bool SyscallSets::IsSystemVMessageQueue(int sysno) {
 }
 #endif
 
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
 // Big system V multiplexing system call.
 bool SyscallSets::IsSystemVIpc(int sysno) {
   switch (sysno) {
+#if !defined(__mips64__)
     case __NR_ipc:
       return true;
+#endif
     default:
       return false;
   }
@@ -855,10 +862,11 @@ bool SyscallSets::IsSystemVIpc(int sysno) {
 #endif
 
 bool SyscallSets::IsAnySystemV(int sysno) {
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) \
+    || defined(__mips64__)
   return IsSystemVMessageQueue(sysno) || IsSystemVSemaphores(sysno) ||
          IsSystemVSharedMemory(sysno);
-#elif defined(__i386__) || defined(__mips__)
+#elif defined(__i386__) || defined(__mips32__)
   return IsSystemVIpc(sysno);
 #endif
 }
@@ -973,13 +981,13 @@ bool SyscallSets::IsMisc(int sysno) {
 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
     case __NR_afs_syscall:
 #endif
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_break:
 #endif
 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
     case __NR_getpmsg:
 #endif
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_gtty:
     case __NR_idle:
     case __NR_lock:
@@ -993,7 +1001,7 @@ bool SyscallSets::IsMisc(int sysno) {
 #if defined(__x86_64__)
     case __NR_security:
 #endif
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
     case __NR_stty:
 #endif
 #if defined(__x86_64__)
@@ -1048,7 +1056,9 @@ bool SyscallSets::IsMipsPrivate(int sysno) {
 bool SyscallSets::IsMipsMisc(int sysno) {
   switch (sysno) {
     case __NR_sysmips:
+#if !defined(__mips64__)
     case __NR_unused150:
+#endif
       return true;
     default:
       return false;
diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
index 5ba6335..c31d5e9 100644
--- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
+++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
@@ -42,7 +42,7 @@ class SANDBOX_EXPORT SyscallSets {
   static bool IsAllowedGetOrModifySocket(int sysno);
   static bool IsDeniedGetOrModifySocket(int sysno);
 
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
   // Big multiplexing system call for sockets.
   static bool IsSocketCall(int sysno);
 #endif
@@ -70,19 +70,22 @@ class SANDBOX_EXPORT SyscallSets {
   // Asynchronous I/O API.
   static bool IsAsyncIo(int sysno);
   static bool IsKeyManagement(int sysno);
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__mips64__)
   static bool IsSystemVSemaphores(int sysno);
 #endif
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__mips64__)
   // These give a lot of ambient authority and bypass the setuid sandbox.
   static bool IsSystemVSharedMemory(int sysno);
 #endif
 
-#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || \
+    defined(__mips64__)
   static bool IsSystemVMessageQueue(int sysno);
 #endif
 
-#if defined(__i386__) || defined(__mips__)
+#if defined(__i386__) || defined(__mips32__)
   // Big system V multiplexing system call.
   static bool IsSystemVIpc(int sysno);
 #endif
diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc
index 4d55936..d6db70f 100644
--- a/sandbox/linux/seccomp-bpf/syscall.cc
+++ b/sandbox/linux/seccomp-bpf/syscall.cc
@@ -188,7 +188,7 @@ asm(// We need to be able to tell the kernel exactly where we made a
     ".fnend\n"
 #endif
     "9:.size SyscallAsm, 9b-SyscallAsm\n"
-#elif defined(__mips__)
+#elif defined(__mips32__)
     ".text\n"
     ".option pic2\n"
     ".align 4\n"
@@ -240,6 +240,53 @@ asm(// We need to be able to tell the kernel exactly where we made a
     ".set    pop\n"
     ".end    SyscallAsm\n"
     ".size   SyscallAsm,.-SyscallAsm\n"
+#elif defined(__mips64__)
+    ".text\n"
+    ".option pic2\n"
+    ".global SyscallAsm\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.ent SyscallAsm\n"
+    ".frame  $sp, 16, $ra\n"
+    ".set   push\n"
+    ".set   noreorder\n"
+    "daddiu  $sp, $sp, -16\n"
+    ".cpsetup $25, 0, SyscallAsm\n"
+    "sd     $ra, 8($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"
+    // This is equivalent to "la $v0, 2f".
+    // LA macro has to be avoided since LLVM-AS has issue with LA in PIC mode
+    // https://llvm.org/bugs/show_bug.cgi?id=27644
+    "ld     $v0, %got(2f)($gp)\n"
+    "daddiu  $v0, $v0, %lo(2f)\n"
+    "b      2f\n"
+    " nop\n"
+    // On MIPS N64 all eight arguments go to registers a0 - a7
+    // We can go ahead and directly copy the entries from the arguments array
+    // into the appropriate CPU registers.
+    "1:ld     $a7, 56($a0)\n"
+    "ld     $a6, 48($a0)\n"
+    "ld     $a5, 40($a0)\n"
+    "ld     $a4, 32($a0)\n"
+    "ld     $a3, 24($a0)\n"
+    "ld     $a2, 16($a0)\n"
+    "ld     $a1, 8($a0)\n"
+    "ld     $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:ld     $ra, 8($sp)\n"
+    ".cpreturn\n"
+    "jr     $ra\n"
+    "daddiu  $sp, $sp, 16\n"
+    ".set    pop\n"
+    ".end    SyscallAsm\n"
+    ".size   SyscallAsm,.-SyscallAsm\n"
 #elif defined(__aarch64__)
     ".text\n"
     ".align 2\n"
@@ -358,7 +405,7 @@ intptr_t Syscall::Call(int nr,
     ret = inout;
   }
 #elif defined(__mips__)
-  int err_status;
+  intptr_t err_status;
   intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status);
 
   if (err_status) {
diff --git a/sandbox/linux/system_headers/linux_seccomp.h b/sandbox/linux/system_headers/linux_seccomp.h
index 3deb3d2..a60fe2a 100644
--- a/sandbox/linux/system_headers/linux_seccomp.h
+++ b/sandbox/linux/system_headers/linux_seccomp.h
@@ -48,6 +48,9 @@
 #ifndef AUDIT_ARCH_MIPSEL
 #define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE)
 #endif
+#ifndef AUDIT_ARCH_MIPSEL64
+#define AUDIT_ARCH_MIPSEL64 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#endif
 #ifndef AUDIT_ARCH_AARCH64
 #define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
 #endif
diff --git a/sandbox/linux/system_headers/linux_signal.h b/sandbox/linux/system_headers/linux_signal.h
index fb9a47b..5ac4fdb 100644
--- a/sandbox/linux/system_headers/linux_signal.h
+++ b/sandbox/linux/system_headers/linux_signal.h
@@ -116,13 +116,20 @@ typedef siginfo_t LinuxSigInfo;
 #endif  // !defined(__native_client_nonsfi__)
 
 // struct sigset_t is different size in PNaCl from the Linux's.
-#if defined(__mips__)
+#if defined(__mips32__)
 #if !defined(_NSIG_WORDS)
 #define _NSIG_WORDS 4
 #endif
 struct LinuxSigSet {
   unsigned long sig[_NSIG_WORDS];
 };
+#elif defined(__mips64__)
+#if !defined(_NSIG_WORDS)
+#define _NSIG_WORDS 2
+#endif
+struct LinuxSigSet {
+  unsigned long sig[_NSIG_WORDS];
+};
 #else
 typedef uint64_t LinuxSigSet;
 #endif
diff --git a/sandbox/linux/system_headers/linux_syscalls.h b/sandbox/linux/system_headers/linux_syscalls.h
index 2b441e4..761c08a 100644
--- a/sandbox/linux/system_headers/linux_syscalls.h
+++ b/sandbox/linux/system_headers/linux_syscalls.h
@@ -21,11 +21,11 @@
 #include "sandbox/linux/system_headers/arm_linux_syscalls.h"
 #endif
 
-#if defined(__mips__) && (_MIPS_SIM == _ABIO32)
+#if defined(__mips32__)
 #include "sandbox/linux/system_headers/mips_linux_syscalls.h"
 #endif
 
-#if defined(__mips__) && (_MIPS_SIM == _ABI64)
+#if defined(__mips64__)
 #include "sandbox/linux/system_headers/mips64_linux_syscalls.h"
 #endif
 
diff --git a/sandbox/linux/system_headers/linux_ucontext.h b/sandbox/linux/system_headers/linux_ucontext.h
index ea4d8a6..e97d727 100644
--- a/sandbox/linux/system_headers/linux_ucontext.h
+++ b/sandbox/linux/system_headers/linux_ucontext.h
@@ -13,8 +13,10 @@
 #include "sandbox/linux/system_headers/i386_linux_ucontext.h"
 #elif defined(__x86_64__)
 #include "sandbox/linux/system_headers/x86_64_linux_ucontext.h"
-#elif defined(__mips__)
+#elif defined(__mips32__)
 #include "sandbox/linux/system_headers/mips_linux_ucontext.h"
+#elif defined(__mips64__)
+#include "sandbox/linux/system_headers/mips64_linux_ucontext.h"
 #elif defined(__aarch64__)
 #include "sandbox/linux/system_headers/arm64_linux_ucontext.h"
 #else
diff --git a/sandbox/linux/system_headers/mips64_linux_syscalls.h b/sandbox/linux/system_headers/mips64_linux_syscalls.h
index 90f3d1be..ec75815 100644
--- a/sandbox/linux/system_headers/mips64_linux_syscalls.h
+++ b/sandbox/linux/system_headers/mips64_linux_syscalls.h
@@ -6,7 +6,7 @@
 #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
 #define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
 
-#if !defined(__mips__) || (_MIPS_SIM != _ABI64)
+#if !defined(__mips__)
 #error "Including header on wrong architecture"
 #endif
 
diff --git a/sandbox/linux/system_headers/mips64_linux_ucontext.h b/sandbox/linux/system_headers/mips64_linux_ucontext.h
new file mode 100644
index 0000000..3d10479
--- /dev/null
+++ b/sandbox/linux/system_headers/mips64_linux_ucontext.h
@@ -0,0 +1,50 @@
+// 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_SYSTEM_HEADERS_MIPS64_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_UCONTEXT_H_
+
+#include <stdint.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 {
+  uint64_t gregs[32];
+  uint64_t fpregs[32];
+  uint64_t mdhi;
+  uint64_t hi1;
+  uint64_t hi2;
+  uint64_t hi3;
+  uint64_t mdlo;
+  uint64_t lo1;
+  uint64_t lo2;
+  uint64_t lo3;
+  uint64_t pc;
+  uint32_t fpc_csr;
+  uint32_t used_math;
+  uint32_t dsp;
+  uint32_t reserved;
+} 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_SYSTEM_HEADERS_MIPS64_LINUX_UCONTEXT_H_
diff --git a/sandbox/linux/system_headers/mips_linux_syscalls.h b/sandbox/linux/system_headers/mips_linux_syscalls.h
index 784d6b8..ddbf97f 100644
--- a/sandbox/linux/system_headers/mips_linux_syscalls.h
+++ b/sandbox/linux/system_headers/mips_linux_syscalls.h
@@ -6,7 +6,7 @@
 #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
 #define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
 
-#if !defined(__mips__) || (_MIPS_SIM != _ABIO32)
+#if !defined(__mips__)
 #error "Including header on wrong architecture"
 #endif
 
