Create global seccomp policy.

Enabling seccomp across all processes, rather than just zygote, is
useful for auditing the syscall usage of AOSP. Create a global seccomp
policy that can optionally be enabled by init.

Bug: 37960259
Test: confirm global seccomp by removing finit_module from policy and
      observing modprobe fail, confirm regular seccomp unchanged by
      comparing length of installed bpf
Change-Id: Iac53a42fa26a80b05126f262dd9525f4f66df558
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index 79968ae..f3a232e 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -26,7 +26,7 @@
     self.names.append(name)
 
 
-def get_names(syscall_files, architecture):
+def get_names(syscall_files, architecture, global_policy):
   syscall_lists = []
   for syscall_file in syscall_files:
     parser = SysCallsTxtParser()
@@ -34,6 +34,11 @@
     syscall_lists.append(parser.syscalls)
 
   bionic, whitelist, blacklist = syscall_lists[0], syscall_lists[1], syscall_lists[2]
+  if global_policy:
+    global_whitelist = syscall_lists[-1]
+  else:
+    global_whitelist = []
+
   for x in blacklist:
     if not x in bionic:
       raise RuntimeError("Blacklist item not in bionic - aborting " + str(x))
@@ -42,7 +47,7 @@
       raise RuntimeError("Blacklist item in whitelist - aborting " + str(x))
 
   bionic_minus_blacklist = [x for x in bionic if x not in blacklist]
-  syscalls = bionic_minus_blacklist + whitelist
+  syscalls = bionic_minus_blacklist + whitelist + global_whitelist
 
   # Select only elements matching required architecture
   syscalls = [x for x in syscalls if architecture in x and x[architecture]]
@@ -170,7 +175,8 @@
   return bpf
 
 
-def convert_bpf_to_output(bpf, architecture):
+def convert_bpf_to_output(bpf, architecture, global_policy):
+  suffix = "global_" if global_policy else ""
   header = textwrap.dedent("""\
     // Autogenerated file - edit at your peril!!
 
@@ -178,24 +184,25 @@
     #include <errno.h>
 
     #include "seccomp_bpfs.h"
-    const sock_filter {architecture}_filter[] = {{
-    """).format(architecture=architecture)
+    const sock_filter {architecture}_{suffix}filter[] = {{
+    """).format(architecture=architecture,suffix=suffix)
 
   footer = textwrap.dedent("""\
 
     }};
 
-    const size_t {architecture}_filter_size = sizeof({architecture}_filter) / sizeof(struct sock_filter);
-    """).format(architecture=architecture)
+    const size_t {architecture}_{suffix}filter_size = sizeof({architecture}_{suffix}filter) / sizeof(struct sock_filter);
+    """).format(architecture=architecture,suffix=suffix)
   return header + "\n".join(bpf) + footer
 
 
-def construct_bpf(syscall_files, architecture, header_dir, extra_switches):
-  names = get_names(syscall_files, architecture)
+def construct_bpf(syscall_files, architecture, header_dir, extra_switches,
+                  global_policy):
+  names = get_names(syscall_files, architecture, global_policy)
   syscalls = convert_names_to_NRs(names, header_dir, extra_switches)
   ranges = convert_NRs_to_ranges(syscalls)
   bpf = convert_ranges_to_bpf(ranges)
-  return convert_bpf_to_output(bpf, architecture)
+  return convert_bpf_to_output(bpf, architecture, global_policy)
 
 
 ANDROID_SYSCALL_FILES = ["SYSCALLS.TXT",
@@ -216,15 +223,18 @@
   os.chdir(os.path.join(os.environ["ANDROID_BUILD_TOP"], "bionic/libc"))
 
 
-def main():
-  set_dir()
+def gen_policy(global_policy):
+  if global_policy:
+    ANDROID_SYSCALL_FILES.append("SECCOMP_WHITELIST_GLOBAL.TXT")
+
   for arch, header_path, switches in POLICY_CONFIGS:
     files = [open(filename) for filename in ANDROID_SYSCALL_FILES]
-    output = construct_bpf(files, arch, header_path, switches)
+    output = construct_bpf(files, arch, header_path, switches, global_policy)
 
     # And output policy
     existing = ""
-    output_path = "seccomp/{}_policy.cpp".format(arch)
+    global_string = "_global" if global_policy else ""
+    output_path = "seccomp/{}{}_policy.cpp".format(arch, global_string)
     if os.path.isfile(output_path):
       existing = open(output_path).read()
     if output == existing:
@@ -234,5 +244,11 @@
         output_file.write(output)
       print "Generated file " + output_path
 
+
+def main():
+  set_dir()
+  gen_policy(False)
+  gen_policy(True)
+
 if __name__ == "__main__":
   main()