Bug 1456203 - Take patch from upstream lss to fix use of disallowed syscalls on Android r=ted draft
authorJames Willcox <snorp@snorp.net>
Mon, 23 Apr 2018 11:58:31 -0500
changeset 786627 167d3e51d71ee35fa08830f1d660c511c50a57c4
parent 786626 b4ee44faff5c6351ab2d1e4c8ef0ec84f446954e
push id107544
push userbmo:snorp@snorp.net
push dateMon, 23 Apr 2018 17:34:11 +0000
reviewersted
bugs1456203, 699213
milestone61.0a1
Bug 1456203 - Take patch from upstream lss to fix use of disallowed syscalls on Android r=ted https://chromium-review.googlesource.com/c/linux-syscall-support/+/699213 MozReview-Commit-ID: 7hjCWfwcuHR
toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
--- a/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
+++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
@@ -138,16 +138,39 @@ extern "C" {
 # pragma push_macro("stat64")
 # pragma push_macro("fstat64")
 # pragma push_macro("lstat64")
 # undef stat64
 # undef fstat64
 # undef lstat64
 #endif
 
+#if defined(__ANDROID__) && defined(__x86_64__)
+// A number of x86_64 syscalls are blocked by seccomp on recent Android;
+// undefine them so that modern alternatives will be used instead where
+// possible.
+// The alternative syscalls have been sanity checked against linux-3.4+;
+// older versions might not work.
+# undef __NR_getdents
+# undef __NR_dup2
+# undef __NR_fork
+# undef __NR_getpgrp
+# undef __NR_open
+# undef __NR_poll
+# undef __NR_readlink
+# undef __NR_stat
+# undef __NR_unlink
+# undef __NR_pipe
+#endif
+
+#if defined(__ANDROID__)
+// waitpid is blocked by seccomp on all architectures on recent Android.
+# undef __NR_waitpid
+#endif
+
 /* As glibc often provides subtly incompatible data structures (and implicit
  * wrapper functions that convert them), we provide our own kernel data
  * structures for use by the system calls.
  * These structures have been developed by using Linux 2.6.23 headers for
  * reference. Note though, we do not care about exact API compatibility
  * with the kernel, and in fact the kernel often does not have a single
  * API that works across architectures. Instead, we try to mimic the glibc
  * API where reasonable, and only guarantee ABI compatibility with the
@@ -177,18 +200,18 @@ struct kernel_dirent64 {
   unsigned long long d_ino;
   long long          d_off;
   unsigned short     d_reclen;
   unsigned char      d_type;
   char               d_name[256];
 };
 
 /* include/linux/dirent.h                                                    */
-#if defined(__aarch64__)
-// aarch64 only defines dirent64, just uses that for dirent too.
+#if !defined(__NR_getdents)
+// when getdents is not available, getdents64 is used for both.
 #define kernel_dirent kernel_dirent64
 #else
 struct kernel_dirent {
   long               d_ino;
   long               d_off;
   unsigned short     d_reclen;
   char               d_name[256];
 };
@@ -1064,16 +1087,17 @@ struct kernel_statfs {
 #endif
 #ifndef __NR_quotactl
 #define __NR_quotactl            60
 #endif
 #ifndef __NR_getdents64
 #define __NR_getdents64          61
 #endif
 #ifndef __NR_getdents
+// when getdents is not available, getdents64 is used for both.
 #define __NR_getdents            __NR_getdents64
 #endif
 #ifndef __NR_pread64
 #define __NR_pread64             67
 #endif
 #ifndef __NR_pwrite64
 #define __NR_pwrite64            68
 #endif
@@ -1172,16 +1196,20 @@ struct kernel_statfs {
 #endif
 #ifndef __NR_sched_setaffinity
 #define __NR_sched_setaffinity  203
 #define __NR_sched_getaffinity  204
 #endif
 #ifndef __NR_getdents64
 #define __NR_getdents64         217
 #endif
+#ifndef __NR_getdents
+// when getdents is not available, getdents64 is used for both.
+#define __NR_getdents           __NR_getdents64
+#endif
 #ifndef __NR_set_tid_address
 #define __NR_set_tid_address    218
 #endif
 #ifndef __NR_fadvise64
 #define __NR_fadvise64          221
 #endif
 #ifndef __NR_clock_gettime
 #define __NR_clock_gettime      228
@@ -3331,29 +3359,32 @@ struct kernel_statfs {
   LSS_INLINE _syscall1(void *,  brk,             void *,      e)
   LSS_INLINE _syscall1(int,     chdir,           const char *,p)
   LSS_INLINE _syscall1(int,     close,           int,         f)
   LSS_INLINE _syscall2(int,     clock_getres,    int,         c,
                        struct kernel_timespec*, t)
   LSS_INLINE _syscall2(int,     clock_gettime,   int,         c,
                        struct kernel_timespec*, t)
   LSS_INLINE _syscall1(int,     dup,             int,         f)
-  #if !defined(__aarch64__)
-    // The dup2 syscall has been deprecated on aarch64. We polyfill it below.
+  #if defined(__NR_dup2)
+    // dup2 is polyfilled below when not available.
     LSS_INLINE _syscall2(int,     dup2,            int,         s,
                          int,            d)
   #endif
+  #if defined(__NR_dup3)
+    LSS_INLINE _syscall3(int, dup3,  int, s, int, d, int, f)
+  #endif
   LSS_INLINE _syscall3(int,     execve,          const char*, f,
                        const char*const*,a,const char*const*, e)
   LSS_INLINE _syscall1(int,     _exit,           int,         e)
   LSS_INLINE _syscall1(int,     exit_group,      int,         e)
   LSS_INLINE _syscall3(int,     fcntl,           int,         f,
                        int,            c, long,   a)
-  #if !defined(__aarch64__)
-    // The fork syscall has been deprecated on aarch64. We polyfill it below.
+  #if defined(__NR_fork)
+    // fork is polyfilled below when not available.
     LSS_INLINE _syscall0(pid_t,   fork)
   #endif
   LSS_INLINE _syscall2(int,     fstat,           int,         f,
                       struct kernel_stat*,   b)
   LSS_INLINE _syscall2(int,     fstatfs,         int,         f,
                       struct kernel_statfs*, b)
   #if defined(__x86_64__)
     /* Need to make sure off_t isn't truncated to 32-bits under x32.  */
@@ -3368,18 +3399,17 @@ struct kernel_statfs {
                        int,            o, int,    v,
                       struct kernel_timespec*, t)
   LSS_INLINE _syscall3(int,     getdents,        int,         f,
                        struct kernel_dirent*, d, int,    c)
   LSS_INLINE _syscall3(int,     getdents64,      int,         f,
                       struct kernel_dirent64*, d, int,    c)
   LSS_INLINE _syscall0(gid_t,   getegid)
   LSS_INLINE _syscall0(uid_t,   geteuid)
-  #if !defined(__aarch64__)
-    // The getgprp syscall has been deprecated on aarch64.
+  #if defined(__NR_getpgrp)
     LSS_INLINE _syscall0(pid_t,   getpgrp)
   #endif
   LSS_INLINE _syscall0(pid_t,   getpid)
   LSS_INLINE _syscall0(pid_t,   getppid)
   LSS_INLINE _syscall2(int,     getpriority,     int,         a,
                        int,            b)
   LSS_INLINE _syscall3(int,     getresgid,       gid_t *,     r,
                        gid_t *,         e,       gid_t *,     s)
@@ -3430,43 +3460,54 @@ struct kernel_statfs {
   LSS_INLINE _syscall6(long,    move_pages,      pid_t,       p,
                        unsigned long,  n, void **,g, int *,   d,
                        int *,          s, int,    f)
   LSS_INLINE _syscall3(int,     mprotect,        const void *,a,
                        size_t,         l,        int,         p)
   LSS_INLINE _syscall5(void*,   _mremap,         void*,       o,
                        size_t,         os,       size_t,      ns,
                        unsigned long,  f, void *, a)
-  #if !defined(__aarch64__)
-    // The open and poll syscalls have been deprecated on aarch64. We polyfill
-    // them below.
+  #if defined(__NR_open)
+    // open is polyfilled below when not available.
     LSS_INLINE _syscall3(int,     open,            const char*, p,
                          int,            f, int,    m)
+  #endif
+  #if defined(__NR_poll)
+    // poll is polyfilled below when not available.
     LSS_INLINE _syscall3(int,     poll,           struct kernel_pollfd*, u,
                          unsigned int,   n, int,    t)
   #endif
+  #if defined(__NR_ppoll)
+    LSS_INLINE _syscall5(int, ppoll, struct kernel_pollfd *, u,
+                         unsigned int, n, const struct kernel_timespec *, t,
+                         const struct kernel_sigset_t *, sigmask, size_t, s)
+  #endif
   LSS_INLINE _syscall5(int,     prctl,           int,         option,
                        unsigned long,  arg2,
                        unsigned long,  arg3,
                        unsigned long,  arg4,
                        unsigned long,  arg5)
   LSS_INLINE _syscall4(long,    ptrace,          int,         r,
                        pid_t,          p, void *, a, void *, d)
   #if defined(__NR_quotactl)
     // Defined on x86_64 / i386 only
     LSS_INLINE _syscall4(int,  quotactl,  int,  cmd,  const char *, special,
                          int, id, caddr_t, addr)
   #endif
   LSS_INLINE _syscall3(ssize_t, read,            int,         f,
                        void *,         b, size_t, c)
-  #if !defined(__aarch64__)
-    // The readlink syscall has been deprecated on aarch64. We polyfill below.
+  #if defined(__NR_readlink)
+    // readlink is polyfilled below when not available.
     LSS_INLINE _syscall3(int,     readlink,        const char*, p,
                          char*,          b, size_t, s)
   #endif
+  #if defined(__NR_readlinkat)
+    LSS_INLINE _syscall4(int, readlinkat, int, d, const char *, p, char *, b,
+                         size_t, s)
+  #endif
   LSS_INLINE _syscall4(int,     rt_sigaction,    int,         s,
                        const struct kernel_sigaction*, a,
                        struct kernel_sigaction*, o, size_t,   c)
   LSS_INLINE _syscall2(int, rt_sigpending, struct kernel_sigset_t *, s,
                        size_t,         c)
   LSS_INLINE _syscall4(int, rt_sigprocmask,      int,         h,
                        const struct kernel_sigset_t*,  s,
                        struct kernel_sigset_t*,        o, size_t, c)
@@ -3493,29 +3534,29 @@ struct kernel_statfs {
   LSS_INLINE _syscall2(int,     setrlimit,       int,         r,
                        const struct kernel_rlimit*, l)
   LSS_INLINE _syscall0(pid_t,    setsid)
   LSS_INLINE _syscall2(int,     sigaltstack,     const stack_t*, s,
                        const stack_t*, o)
   #if defined(__NR_sigreturn)
     LSS_INLINE _syscall1(int,     sigreturn,       unsigned long, u)
   #endif
-  #if !defined(__aarch64__)
-    // The stat syscall has been deprecated on aarch64. We polyfill it below.
+  #if defined(__NR_stat)
+    // stat is polyfilled below when not available.
     LSS_INLINE _syscall2(int,     stat,            const char*, f,
                         struct kernel_stat*,   b)
   #endif
   LSS_INLINE _syscall2(int,     statfs,          const char*, f,
                       struct kernel_statfs*, b)
   LSS_INLINE _syscall3(int,     tgkill,          pid_t,       p,
                        pid_t,          t, int,            s)
   LSS_INLINE _syscall2(int,     tkill,           pid_t,       p,
                        int,            s)
-  #if !defined(__aarch64__)
-    // The unlink syscall has been deprecated on aarch64. We polyfill it below.
+  #if defined(__NR_unlink)
+    // unlink is polyfilled below when not available.
     LSS_INLINE _syscall1(int,     unlink,           const char*, f)
   #endif
   LSS_INLINE _syscall3(ssize_t, write,            int,        f,
                        const void *,   b, size_t, c)
   LSS_INLINE _syscall3(ssize_t, writev,           int,        f,
                        const struct kernel_iovec*, v, size_t, c)
   #if defined(__NR_getcpu)
     LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu,
@@ -3603,31 +3644,33 @@ struct kernel_statfs {
       union { loff_t off; unsigned w[2]; } o = { offset }, l = { len };
       return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]);
     }
     #else
     LSS_INLINE _syscall4(int, fallocate,
                          int, f, int, mode, loff_t, offset, loff_t, len)
     #endif
   #endif
+  #if defined(__NR_newfstatat)
+    LSS_INLINE _syscall4(int, newfstatat,         int,   d,
+                         const char *,            p,
+                         struct kernel_stat*,     b, int, f)
+  #endif
   #if defined(__x86_64__) || defined(__s390x__)
     LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid,
                                          gid_t *egid,
                                          gid_t *sgid) {
       return LSS_NAME(getresgid)(rgid, egid, sgid);
     }
 
     LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid,
                                          uid_t *euid,
                                          uid_t *suid) {
       return LSS_NAME(getresuid)(ruid, euid, suid);
     }
-    LSS_INLINE _syscall4(int, newfstatat,         int,   d,
-                         const char *,            p,
-                        struct kernel_stat*,       b, int, f)
 
     LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) {
       return LSS_NAME(setfsgid)(gid);
     }
 
     LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) {
       return LSS_NAME(setfsuid)(uid);
     }
@@ -3670,27 +3713,20 @@ struct kernel_statfs {
                                          struct kernel_sigset_t *oldset) {
       return LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8);
     }
 
     LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) {
       return LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8);
     }
   #endif
-  #if defined(__x86_64__) || defined(__ARM_ARCH_3__) ||                       \
-      defined(__ARM_EABI__) || defined(__aarch64__) ||                        \
-     (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) ||                   \
-      defined(__s390__)
+  #if defined(__NR_wait4)
     LSS_INLINE _syscall4(pid_t, wait4,            pid_t, p,
                          int*,                    s, int,       o,
                         struct kernel_rusage*,     r)
-
-    LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options){
-      return LSS_NAME(wait4)(pid, status, options, 0);
-    }
   #endif
   #if defined(__NR_openat)
     LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m)
   #endif
   #if defined(__NR_unlinkat)
     LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f)
   #endif
   #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
@@ -4186,18 +4222,18 @@ struct kernel_statfs {
       return LSS_NAME(socketcall)(8, d, type, protocol, sv);
     }
   #endif
   #if defined(__NR_fstatat64)
     LSS_INLINE _syscall4(int,   fstatat64,        int,   d,
                          const char *,      p,
                          struct kernel_stat64 *,   b,    int,   f)
   #endif
-  #if defined(__i386__) || defined(__PPC__) ||                                \
-     (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32)
+  #if defined(__NR_waitpid)
+    // waitpid is polyfilled below when not available.
     LSS_INLINE _syscall3(pid_t, waitpid,          pid_t, p,
                          int*,              s,    int,   o)
   #endif
   #if defined(__mips__)
     /* sys_pipe() on MIPS has non-standard calling conventions, as it returns
      * both file handles through CPU registers.
      */
     LSS_INLINE int LSS_NAME(pipe)(int *p) {
@@ -4214,20 +4250,23 @@ struct kernel_statfs {
         LSS_ERRNO = __errnovalue;
         return -1;
       } else {
         p[0] = __v0;
         p[1] = __v1;
         return 0;
       }
     }
-  #elif !defined(__aarch64__)
-    // The unlink syscall has been deprecated on aarch64. We polyfill it below.
+  #elif defined(__NR_pipe)
+    // pipe is polyfilled below when not available.
     LSS_INLINE _syscall1(int,     pipe,           int *, p)
   #endif
+  #if defined(__NR_pipe2)
+    LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags)
+  #endif
   /* TODO(csilvers): see if ppc can/should support this as well              */
   #if defined(__i386__) || defined(__ARM_ARCH_3__) ||                         \
       defined(__ARM_EABI__) ||                                                \
      (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) ||                   \
      (defined(__s390__) && !defined(__s390x__))
     #define __NR__statfs64  __NR_statfs64
     #define __NR__fstatfs64 __NR_fstatfs64
     LSS_INLINE _syscall3(int, _statfs64,     const char*, p,
@@ -4394,72 +4433,84 @@ struct kernel_statfs {
     }
     LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) {
       union { loff_t off; unsigned arg[2]; } o = { off };
       return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], len);
     }
   #endif
 #endif
 
-#if defined(__aarch64__)
-  LSS_INLINE _syscall3(int, dup3,  int, s, int, d, int, f)
-  LSS_INLINE _syscall4(int, newfstatat, int, dirfd, const char *, pathname,
-                       struct kernel_stat *, buf, int, flags)
-  LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags)
-  LSS_INLINE _syscall5(int, ppoll, struct kernel_pollfd *, u,
-                       unsigned int, n, const struct kernel_timespec *, t,
-                       const struct kernel_sigset_t *, sigmask, size_t, s)
-  LSS_INLINE _syscall4(int, readlinkat, int, d, const char *, p, char *, b,
-                       size_t, s)
-#endif
-
 /*
  * Polyfills for deprecated syscalls.
  */
 
-#if defined(__aarch64__)
+#if !defined(__NR_dup2)
   LSS_INLINE int LSS_NAME(dup2)(int s, int d) {
     return LSS_NAME(dup3)(s, d, 0);
   }
+#endif
 
+#if !defined(__NR_open)
   LSS_INLINE int LSS_NAME(open)(const char *pathname, int flags, int mode) {
     return LSS_NAME(openat)(AT_FDCWD, pathname, flags, mode);
   }
+#endif
 
+#if !defined(__NR_unlink)
   LSS_INLINE int LSS_NAME(unlink)(const char *pathname) {
     return LSS_NAME(unlinkat)(AT_FDCWD, pathname, 0);
   }
+#endif
 
+#if !defined(__NR_readlink)
   LSS_INLINE int LSS_NAME(readlink)(const char *pathname, char *buffer,
                                     size_t size) {
     return LSS_NAME(readlinkat)(AT_FDCWD, pathname, buffer, size);
   }
+#endif
 
+#if !defined(__NR_pipe)
   LSS_INLINE pid_t LSS_NAME(pipe)(int *pipefd) {
     return LSS_NAME(pipe2)(pipefd, 0);
   }
+#endif
 
+#if !defined(__NR_poll)
   LSS_INLINE int LSS_NAME(poll)(struct kernel_pollfd *fds, unsigned int nfds,
                                 int timeout) {
    struct kernel_timespec timeout_ts;
    struct kernel_timespec *timeout_ts_p = NULL;
 
     if (timeout >= 0) {
       timeout_ts.tv_sec = timeout / 1000;
       timeout_ts.tv_nsec = (timeout % 1000) * 1000000;
       timeout_ts_p = &timeout_ts;
     }
     return LSS_NAME(ppoll)(fds, nfds, timeout_ts_p, NULL, 0);
   }
+#endif
 
+#if !defined(__NR_stat)
   LSS_INLINE int LSS_NAME(stat)(const char *pathname,
                                 struct kernel_stat *buf) {
     return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0);
   }
+#endif
 
+#if !defined(__NR_waitpid)
+  LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options) {
+    return LSS_NAME(wait4)(pid, status, options, 0);
+  }
+#endif
+
+#if !defined(__NR_fork)
+// TODO: define this in an arch-independant way instead of inlining the clone
+//       syscall body.
+
+# if defined(__aarch64__)
   LSS_INLINE pid_t LSS_NAME(fork)(void) {
     // No fork syscall on aarch64 - implement by means of the clone syscall.
     // Note that this does not reset glibc's cached view of the PID/TID, so
     // some glibc interfaces might go wrong in the forked subprocess.
     int flags = SIGCHLD;
     void *child_stack = NULL;
     void *parent_tidptr = NULL;
     void *newtls = NULL;
@@ -4468,16 +4519,33 @@ struct kernel_statfs {
     LSS_REG(0, flags);
     LSS_REG(1, child_stack);
     LSS_REG(2, parent_tidptr);
     LSS_REG(3, newtls);
     LSS_REG(4, child_tidptr);
     LSS_BODY(pid_t, clone, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3),
              "r"(__r4));
   }
+# elif defined(__x86_64__)
+  LSS_INLINE pid_t LSS_NAME(fork)(void) {
+    // Android disallows the fork syscall on x86_64 - implement by means of the
+    // clone syscall as above for aarch64.
+    int flags = SIGCHLD;
+    void *child_stack = NULL;
+    void *parent_tidptr = NULL;
+    void *newtls = NULL;
+    void *child_tidptr = NULL;
+
+    LSS_BODY(5, pid_t, clone, LSS_SYSCALL_ARG(flags),
+             LSS_SYSCALL_ARG(child_stack), LSS_SYSCALL_ARG(parent_tidptr),
+             LSS_SYSCALL_ARG(newtls), LSS_SYSCALL_ARG(child_tidptr));
+  }
+# else
+#  error missing fork polyfill for this architecture
+# endif
 #endif
 
 #ifdef __ANDROID__
   /* These restore the original values of these macros saved by the
    * corresponding #pragma push_macro near the top of this file. */
 # pragma pop_macro("stat64")
 # pragma pop_macro("fstat64")
 # pragma pop_macro("lstat64")