Merge "Bionic malloc debug: add a new option "abort_on_error""
diff --git a/libc/Android.bp b/libc/Android.bp
index 36a0507..6f2e347 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -2212,6 +2212,91 @@
     },
 }
 
+python_binary_host {
+    name: "genfunctosyscallnrs",
+    main: "tools/genfunctosyscallnrs.py",
+
+    srcs: [
+        "tools/genseccomp.py",
+        "tools/genfunctosyscallnrs.py",
+        "tools/gensyscalls.py",
+    ],
+
+    data: [
+        "kernel/uapi/**/*.h",
+    ],
+
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+cc_genrule {
+    name: "func_to_syscall_nrs",
+    recovery_available: true,
+    cmd: "$(location genfunctosyscallnrs) --out-dir=$(genDir) $(in)",
+
+    tools: [ "genfunctosyscallnrs" ],
+
+    srcs: [
+        "SYSCALLS.TXT",
+        ":libseccomp_gen_syscall_nrs_arm",
+        ":libseccomp_gen_syscall_nrs_arm64",
+        ":libseccomp_gen_syscall_nrs_mips",
+        ":libseccomp_gen_syscall_nrs_mips64",
+        ":libseccomp_gen_syscall_nrs_x86",
+        ":libseccomp_gen_syscall_nrs_x86_64",
+    ],
+
+    out: [
+        "func_to_syscall_nrs.h",
+    ],
+}
+
+// SECCOMP_BLACKLIST_APP_ZYGOTE.TXT = SECCOMP_BLACKLIST_APP.txt - setresgid*
+genrule {
+    name: "generate_app_zygote_blacklist",
+    out: ["SECCOMP_BLACKLIST_APP_ZYGOTE.TXT"],
+    srcs: ["SECCOMP_BLACKLIST_APP.TXT"],
+    cmd: "grep -v '^int[ \t]*setresgid' $(in) > $(out)",
+}
+
+cc_genrule {
+    name: "libseccomp_policy_app_zygote_sources",
+    recovery_available: true,
+    cmd: "$(location genseccomp) --out-dir=$(genDir) --name-modifier=app_zygote $(in)",
+
+    tools: [ "genseccomp" ],
+
+    srcs: [
+        "SYSCALLS.TXT",
+        "SECCOMP_WHITELIST_COMMON.TXT",
+        "SECCOMP_WHITELIST_APP.TXT",
+        "SECCOMP_BLACKLIST_COMMON.TXT",
+        ":generate_app_zygote_blacklist",
+        ":libseccomp_gen_syscall_nrs_arm",
+        ":libseccomp_gen_syscall_nrs_arm64",
+        ":libseccomp_gen_syscall_nrs_mips",
+        ":libseccomp_gen_syscall_nrs_mips64",
+        ":libseccomp_gen_syscall_nrs_x86",
+        ":libseccomp_gen_syscall_nrs_x86_64",
+    ],
+
+    out: [
+        "arm64_app_zygote_policy.cpp",
+        "arm_app_zygote_policy.cpp",
+        "mips64_app_zygote_policy.cpp",
+        "mips_app_zygote_policy.cpp",
+        "x86_64_app_zygote_policy.cpp",
+        "x86_app_zygote_policy.cpp",
+    ],
+}
+
 cc_genrule {
     name: "libseccomp_policy_app_sources",
     recovery_available: true,
@@ -2308,8 +2393,10 @@
 cc_library {
     name: "libseccomp_policy",
     recovery_available: true,
+    generated_headers: ["func_to_syscall_nrs"],
     generated_sources: [
         "libseccomp_policy_app_sources",
+        "libseccomp_policy_app_zygote_sources",
         "libseccomp_policy_global_sources",
         "libseccomp_policy_system_sources",
     ],
diff --git a/libc/seccomp/include/seccomp_policy.h b/libc/seccomp/include/seccomp_policy.h
index 49280f4..fd0fb60 100644
--- a/libc/seccomp/include/seccomp_policy.h
+++ b/libc/seccomp/include/seccomp_policy.h
@@ -17,8 +17,14 @@
 #pragma once
 
 #include <stddef.h>
+#include <stdint.h>
 #include <linux/filter.h>
 
 bool set_app_seccomp_filter();
+bool set_app_zygote_seccomp_filter();
 bool set_system_seccomp_filter();
 bool set_global_seccomp_filter();
+
+// Installs a filter that limits setresuid/setresgid to a range of
+// [uid_gid_min..uid_gid_max] (for the real-, effective- and super-ids).
+bool install_setuidgid_seccomp_filter(uint32_t uid_gid_min, uint32_t uid_gid_max);
diff --git a/libc/seccomp/seccomp_bpfs.h b/libc/seccomp/seccomp_bpfs.h
index 797dfc5..d9e8047 100644
--- a/libc/seccomp/seccomp_bpfs.h
+++ b/libc/seccomp/seccomp_bpfs.h
@@ -21,6 +21,8 @@
 
 extern const struct sock_filter arm_app_filter[];
 extern const size_t arm_app_filter_size;
+extern const struct sock_filter arm_app_zygote_filter[];
+extern const size_t arm_app_zygote_filter_size;
 extern const struct sock_filter arm_system_filter[];
 extern const size_t arm_system_filter_size;
 extern const struct sock_filter arm_global_filter[];
@@ -28,6 +30,8 @@
 
 extern const struct sock_filter arm64_app_filter[];
 extern const size_t arm64_app_filter_size;
+extern const struct sock_filter arm64_app_zygote_filter[];
+extern const size_t arm64_app_zygote_filter_size;
 extern const struct sock_filter arm64_system_filter[];
 extern const size_t arm64_system_filter_size;
 extern const struct sock_filter arm64_global_filter[];
@@ -35,6 +39,8 @@
 
 extern const struct sock_filter x86_app_filter[];
 extern const size_t x86_app_filter_size;
+extern const struct sock_filter x86_app_zygote_filter[];
+extern const size_t x86_app_zygote_filter_size;
 extern const struct sock_filter x86_system_filter[];
 extern const size_t x86_system_filter_size;
 extern const struct sock_filter x86_global_filter[];
@@ -42,6 +48,8 @@
 
 extern const struct sock_filter x86_64_app_filter[];
 extern const size_t x86_64_app_filter_size;
+extern const struct sock_filter x86_64_app_zygote_filter[];
+extern const size_t x86_64_app_zygote_filter_size;
 extern const struct sock_filter x86_64_system_filter[];
 extern const size_t x86_64_system_filter_size;
 extern const struct sock_filter x86_64_global_filter[];
@@ -49,6 +57,8 @@
 
 extern const struct sock_filter mips_app_filter[];
 extern const size_t mips_app_filter_size;
+extern const struct sock_filter mips_app_zygote_filter[];
+extern const size_t mips_app_zygote_filter_size;
 extern const struct sock_filter mips_system_filter[];
 extern const size_t mips_system_filter_size;
 extern const struct sock_filter mips_global_filter[];
@@ -56,6 +66,8 @@
 
 extern const struct sock_filter mips64_app_filter[];
 extern const size_t mips64_app_filter_size;
+extern const struct sock_filter mips64_app_zygote_filter[];
+extern const size_t mips64_app_zygote_filter_size;
 extern const struct sock_filter mips64_system_filter[];
 extern const size_t mips64_system_filter_size;
 extern const struct sock_filter mips64_global_filter[];
diff --git a/libc/seccomp/seccomp_policy.cpp b/libc/seccomp/seccomp_policy.cpp
index 3d617be..222a2c8 100644
--- a/libc/seccomp/seccomp_policy.cpp
+++ b/libc/seccomp/seccomp_policy.cpp
@@ -20,78 +20,111 @@
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 #include <sys/prctl.h>
+#include <sys/syscall.h>
 
 #include <vector>
 
 #include <android-base/logging.h>
 
+#include "func_to_syscall_nrs.h"
 #include "seccomp_bpfs.h"
 
-
 #if defined __arm__ || defined __aarch64__
 
 #define DUAL_ARCH
 #define PRIMARY_ARCH AUDIT_ARCH_AARCH64
 static const struct sock_filter* primary_app_filter = arm64_app_filter;
 static const size_t primary_app_filter_size = arm64_app_filter_size;
+static const struct sock_filter* primary_app_zygote_filter = arm64_app_zygote_filter;
+static const size_t primary_app_zygote_filter_size = arm64_app_zygote_filter_size;
 static const struct sock_filter* primary_system_filter = arm64_system_filter;
 static const size_t primary_system_filter_size = arm64_system_filter_size;
 static const struct sock_filter* primary_global_filter = arm64_global_filter;
 static const size_t primary_global_filter_size = arm64_global_filter_size;
+
+static const long primary_setresgid = __arm64_setresgid;
+static const long primary_setresuid = __arm64_setresuid;
 #define SECONDARY_ARCH AUDIT_ARCH_ARM
 static const struct sock_filter* secondary_app_filter = arm_app_filter;
 static const size_t secondary_app_filter_size = arm_app_filter_size;
+static const struct sock_filter* secondary_app_zygote_filter = arm_app_zygote_filter;
+static const size_t secondary_app_zygote_filter_size = arm_app_zygote_filter_size;
 static const struct sock_filter* secondary_system_filter = arm_system_filter;
 static const size_t secondary_system_filter_size = arm_system_filter_size;
 static const struct sock_filter* secondary_global_filter = arm_global_filter;
 static const size_t secondary_global_filter_size = arm_global_filter_size;
 
+static const long secondary_setresgid = __arm_setresgid;
+static const long secondary_setresuid = __arm_setresuid;
 #elif defined __i386__ || defined __x86_64__
 
 #define DUAL_ARCH
 #define PRIMARY_ARCH AUDIT_ARCH_X86_64
 static const struct sock_filter* primary_app_filter = x86_64_app_filter;
 static const size_t primary_app_filter_size = x86_64_app_filter_size;
+static const struct sock_filter* primary_app_zygote_filter = x86_64_app_zygote_filter;
+static const size_t primary_app_zygote_filter_size = x86_64_app_zygote_filter_size;
 static const struct sock_filter* primary_system_filter = x86_64_system_filter;
 static const size_t primary_system_filter_size = x86_64_system_filter_size;
 static const struct sock_filter* primary_global_filter = x86_64_global_filter;
 static const size_t primary_global_filter_size = x86_64_global_filter_size;
+
+static const long primary_setresgid = __x86_64_setresgid;
+static const long primary_setresuid = __x86_64_setresuid;
 #define SECONDARY_ARCH AUDIT_ARCH_I386
 static const struct sock_filter* secondary_app_filter = x86_app_filter;
 static const size_t secondary_app_filter_size = x86_app_filter_size;
+static const struct sock_filter* secondary_app_zygote_filter = x86_app_zygote_filter;
+static const size_t secondary_app_zygote_filter_size = x86_app_zygote_filter_size;
 static const struct sock_filter* secondary_system_filter = x86_system_filter;
 static const size_t secondary_system_filter_size = x86_system_filter_size;
 static const struct sock_filter* secondary_global_filter = x86_global_filter;
 static const size_t secondary_global_filter_size = x86_global_filter_size;
 
+static const long secondary_setresgid = __x86_setresgid;
+static const long secondary_setresuid = __x86_setresuid;
 #elif defined __mips__ || defined __mips64__
 
 #define DUAL_ARCH
 #define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
 static const struct sock_filter* primary_app_filter = mips64_app_filter;
 static const size_t primary_app_filter_size = mips64_app_filter_size;
+static const struct sock_filter* primary_app_zygote_filter = mips64_app_zygote_filter;
+static const size_t primary_app_zygote_filter_size = mips64_app_zygote_filter_size;
 static const struct sock_filter* primary_system_filter = mips64_system_filter;
 static const size_t primary_system_filter_size = mips64_system_filter_size;
 static const struct sock_filter* primary_global_filter = mips64_global_filter;
 static const size_t primary_global_filter_size = mips64_global_filter_size;
+
+static const long primary_setresgid = __mips64_setresgid;
+static const long primary_setresuid = __mips64_setresuid;
 #define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
 static const struct sock_filter* secondary_app_filter = mips_app_filter;
 static const size_t secondary_app_filter_size = mips_app_filter_size;
+static const struct sock_filter* secondary_app_zygote_filter = mips_app_zygote_filter;
+static const size_t secondary_app_zygote_filter_size = mips_app_zygote_filter_size;
 static const struct sock_filter* secondary_system_filter = mips_system_filter;
 static const size_t secondary_system_filter_size = mips_system_filter_size;
 static const struct sock_filter* secondary_global_filter = mips_global_filter;
 static const size_t secondary_global_filter_size = mips_global_filter_size;
 
+static const long secondary_setresgid = __mips_setresgid;
+static const long secondary_setresuid = __mips_setresuid;
 #else
 #error No architecture was defined!
 #endif
 
 
 #define syscall_nr (offsetof(struct seccomp_data, nr))
+#define syscall_arg(_n) (offsetof(struct seccomp_data, args[_n]))
 #define arch_nr (offsetof(struct seccomp_data, arch))
 
 typedef std::vector<sock_filter> filter;
 
+inline void Allow(filter& f) {
+    f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
+}
+
 inline void Disallow(filter& f) {
     f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
 }
@@ -128,6 +161,49 @@
 }
 #endif
 
+static void ValidateSyscallArgInRange(filter& f, __u32 arg_num, __u32 range_min, __u32 range_max) {
+    const __u32 syscall_arg = syscall_arg(arg_num);
+
+    if (range_max == UINT32_MAX) {
+        LOG(FATAL) << "range_max exceeds maximum argument range.";
+        return;
+    }
+
+    f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg));
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, range_min, 0, 1));
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, range_max + 1, 0, 1));
+    Disallow(f);
+}
+
+// This filter is meant to be installed in addition to a regular whitelist filter.
+// Therefore, it's default action has to be Allow, except when the evaluated
+// system call matches setresuid/setresgid and the arguments don't fall within the
+// passed in range.
+//
+// The regular whitelist only allows setresuid/setresgid for UID/GID changes, so
+// that's the only system call we need to check here. A CTS test ensures the other
+// calls will remain blocked.
+static void ValidateSetUidGid(filter& f, uint32_t uid_gid_min, uint32_t uid_gid_max, bool primary) {
+    // Check setresuid(ruid, euid, sguid) fall within range
+    ExamineSyscall(f);
+    __u32 setresuid_nr = primary ? primary_setresuid : secondary_setresuid;
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, setresuid_nr, 0, 12));
+    for (int arg = 0; arg < 3; arg++) {
+        ValidateSyscallArgInRange(f, arg, uid_gid_min, uid_gid_max);
+    }
+
+    // Check setresgid(rgid, egid, sgid) fall within range
+    ExamineSyscall(f);
+    __u32 setresgid_nr = primary ? primary_setresgid : secondary_setresgid;
+    f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, setresgid_nr, 0, 12));
+    for (int arg = 0; arg < 3; arg++) {
+        ValidateSyscallArgInRange(f, arg, uid_gid_min, uid_gid_max);
+    }
+
+    // Default is to allow; other filters may still reject this call.
+    Allow(f);
+}
+
 static bool install_filter(filter const& f) {
     struct sock_fprog prog = {
         static_cast<unsigned short>(f.size()),
@@ -141,8 +217,33 @@
     return true;
 }
 
+bool _install_setuidgid_filter(uint32_t uid_gid_min, uint32_t uid_gid_max) {
+    filter f;
+#ifdef DUAL_ARCH
+    // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
+    // jump that must be changed to point to the start of the 32-bit policy
+    // 32 bit syscalls will not hit the policy between here and the call to SetJump
+    auto offset_to_secondary_filter = ValidateArchitectureAndJumpIfNeeded(f);
+#else
+    ValidateArchitecture(f);
+#endif
+
+    ValidateSetUidGid(f, uid_gid_min, uid_gid_max, true /* primary */);
+
+#ifdef DUAL_ARCH
+    if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
+        return false;
+    }
+
+    ValidateSetUidGid(f, uid_gid_min, uid_gid_max, false /* primary */);
+#endif
+
+    return install_filter(f);
+}
+
 enum FilterType {
   APP,
+  APP_ZYGOTE,
   SYSTEM,
   GLOBAL
 };
@@ -159,6 +260,12 @@
         s = secondary_app_filter;
         s_size = secondary_app_filter_size;
         break;
+      case APP_ZYGOTE:
+        p = primary_app_zygote_filter;
+        p_size = primary_app_zygote_filter_size;
+        s = secondary_app_zygote_filter;
+        s_size = secondary_app_zygote_filter_size;
+        break;
       case SYSTEM:
         p = primary_system_filter;
         p_size = primary_system_filter_size;
@@ -210,6 +317,10 @@
     return _set_seccomp_filter(FilterType::APP);
 }
 
+bool set_app_zygote_seccomp_filter() {
+    return _set_seccomp_filter(FilterType::APP_ZYGOTE);
+}
+
 bool set_system_seccomp_filter() {
     return _set_seccomp_filter(FilterType::SYSTEM);
 }
@@ -217,3 +328,7 @@
 bool set_global_seccomp_filter() {
     return _set_seccomp_filter(FilterType::GLOBAL);
 }
+
+bool install_setuidgid_seccomp_filter(uint32_t uid_gid_min, uint32_t uid_gid_max) {
+    return _install_setuidgid_filter(uid_gid_min, uid_gid_max);
+}
diff --git a/libc/tools/genfunctosyscallnrs.py b/libc/tools/genfunctosyscallnrs.py
new file mode 100755
index 0000000..6a456f2
--- /dev/null
+++ b/libc/tools/genfunctosyscallnrs.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+import argparse
+import collections
+import logging
+import os
+import re
+import subprocess
+import textwrap
+
+from gensyscalls import SysCallsTxtParser
+from genseccomp import parse_syscall_NRs
+
+def load_syscall_names_from_file(file_path, architecture):
+  parser = SysCallsTxtParser()
+  parser.parse_open_file(open(file_path))
+  arch_map = {}
+  for syscall in parser.syscalls:
+    if syscall.get(architecture):
+      arch_map[syscall["func"]] = syscall["name"];
+
+  return arch_map
+
+def gen_syscall_nrs(out_file, base_syscall_file, syscall_NRs):
+  for arch in ('arm', 'arm64', 'mips', 'mips64', 'x86', 'x86_64'):
+    base_names = load_syscall_names_from_file(base_syscall_file, arch)
+
+    for func,syscall in base_names.iteritems():
+      out_file.write("#define __" + arch + "_" + func + " " + str(syscall_NRs[arch][syscall]) + ";\n")
+
+def main():
+  parser = argparse.ArgumentParser(
+      description="Generates a mapping of bionic functions to system call numbers per architecture.")
+  parser.add_argument("--verbose", "-v", help="Enables verbose logging.")
+  parser.add_argument("--out-dir",
+                      help="The output directory for the output files")
+  parser.add_argument("base_file", metavar="base-file", type=str,
+                      help="The path of the base syscall list (SYSCALLS.TXT).")
+  parser.add_argument("files", metavar="FILE", type=str, nargs="+",
+                      help=("A syscall name-number mapping file for an architecture.\n"))
+  args = parser.parse_args()
+
+  if args.verbose:
+    logging.basicConfig(level=logging.DEBUG)
+  else:
+    logging.basicConfig(level=logging.INFO)
+
+  syscall_files = []
+  syscall_NRs = {}
+  for filename in args.files:
+    m = re.search(r"libseccomp_gen_syscall_nrs_([^/]+)", filename)
+    syscall_NRs[m.group(1)] = parse_syscall_NRs(filename)
+
+  output_path = os.path.join(args.out_dir, "func_to_syscall_nrs.h")
+  with open(output_path, "w") as output_file:
+    gen_syscall_nrs(out_file=output_file,
+             syscall_NRs=syscall_NRs, base_syscall_file=args.base_file)
+
+if __name__ == "__main__":
+  main()