Merge "Blacklist setregid(32) for apps."
diff --git a/libc/Android.bp b/libc/Android.bp
index e0d0fee..6f2e347 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1612,6 +1612,8 @@
         symbol_file: "libc.map.txt",
         versions: ["10000"],
     },
+
+    symbol_ordering_file: "symbol_ordering",
 }
 
 genrule {
@@ -1646,6 +1648,59 @@
     cmd: "$(location :bionic-generate-version-script) x86_64 $(in) $(out)",
 }
 
+// libc_headers for libasync_safe and libpropertyinfoparser
+cc_library_headers {
+    name: "libc_headers",
+
+    host_supported: true,
+    vendor_available: true,
+    recovery_available: true,
+
+    no_libcrt: true,
+    no_libgcc: true,
+    stl: "none",
+    system_shared_libs: [],
+
+    export_include_dirs: [
+        "include",
+        "kernel/uapi",
+        "kernel/android/uapi",
+    ],
+
+    arch: {
+        arm: {
+            export_include_dirs: [
+                "kernel/uapi/asm-arm",
+            ],
+        },
+        arm64: {
+            export_include_dirs: [
+                "kernel/uapi/asm-arm64",
+            ],
+        },
+        mips: {
+            export_include_dirs: [
+                "kernel/uapi/asm-mips",
+            ],
+        },
+        mips64: {
+            export_include_dirs: [
+                "kernel/uapi/asm-mips",
+            ],
+        },
+        x86: {
+            export_include_dirs: [
+                "kernel/uapi/asm-x86",
+            ],
+        },
+        x86_64: {
+            export_include_dirs: [
+                "kernel/uapi/asm-x86",
+            ],
+        },
+    },
+}
+
 // ========================================================
 // libstdc++.so and libstdc++.a.
 // ========================================================
@@ -1999,47 +2054,39 @@
     symbol_file: "libc.map.txt",
     export_headers_as_system: true,
     export_preprocessed_headers: ["include"],
+    export_include_dirs: [
+        "kernel/android/uapi",
+        "kernel/uapi",
+    ],
     arch: {
         arm: {
             export_include_dirs: [
-                "kernel/uapi",
                 "kernel/uapi/asm-arm",
-                "kernel/android/uapi",
             ],
         },
         arm64: {
             export_include_dirs: [
-                "kernel/uapi",
                 "kernel/uapi/asm-arm64",
-                "kernel/android/uapi",
             ],
         },
         mips: {
             export_include_dirs: [
-                "kernel/uapi",
                 "kernel/uapi/asm-mips",
-                "kernel/android/uapi",
             ],
         },
         mips64: {
             export_include_dirs: [
-                "kernel/uapi",
                 "kernel/uapi/asm-mips",
-                "kernel/android/uapi",
             ],
         },
         x86: {
             export_include_dirs: [
-                "kernel/uapi",
                 "kernel/uapi/asm-x86",
-                "kernel/android/uapi",
             ],
         },
         x86_64: {
             export_include_dirs: [
-                "kernel/uapi",
                 "kernel/uapi/asm-x86",
-                "kernel/android/uapi",
             ],
         },
     },
@@ -2165,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,
@@ -2261,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/arch-arm/bionic/vfork.S b/libc/arch-arm/bionic/vfork.S
index 8329111..0b17d64 100644
--- a/libc/arch-arm/bionic/vfork.S
+++ b/libc/arch-arm/bionic/vfork.S
@@ -27,12 +27,13 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 
 ENTRY(vfork)
 __BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork)
     // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
     mrc     p15, 0, r3, c13, c0, 3
-    ldr     r3, [r3, #4]
+    ldr     r3, [r3, #(TLS_SLOT_THREAD_ID * 4)]
     mov     r0, #0
     str     r0, [r3, #12]
 
diff --git a/libc/arch-arm64/bionic/vfork.S b/libc/arch-arm64/bionic/vfork.S
index 0a83cc7..6acd64b 100644
--- a/libc/arch-arm64/bionic/vfork.S
+++ b/libc/arch-arm64/bionic/vfork.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 #include <asm/signal.h>
 #include <linux/sched.h>
 
@@ -34,7 +35,7 @@
 __BIONIC_WEAK_ASM_FOR_NATIVE_BRIDGE(vfork)
     // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
     mrs     x0, tpidr_el0
-    ldr     x0, [x0, #8]
+    ldr     x0, [x0, #(TLS_SLOT_THREAD_ID * 8)]
     str     wzr, [x0, #20]
 
     mov     x0, #(CLONE_VM | CLONE_VFORK | SIGCHLD)
diff --git a/libc/arch-x86/bionic/vfork.S b/libc/arch-x86/bionic/vfork.S
index 79d7899..24ede3d 100644
--- a/libc/arch-x86/bionic/vfork.S
+++ b/libc/arch-x86/bionic/vfork.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 
 // This custom code preserves the return address across the system call.
 
@@ -38,7 +39,7 @@
 
   // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
   movl    %gs:0, %eax
-  movl    4(%eax), %eax
+  movl    (TLS_SLOT_THREAD_ID * 4)(%eax), %eax
   movl    $0, 12(%eax)
 
   movl    $__NR_vfork, %eax
diff --git a/libc/arch-x86_64/bionic/vfork.S b/libc/arch-x86_64/bionic/vfork.S
index ce96a8c..e32b517 100644
--- a/libc/arch-x86_64/bionic/vfork.S
+++ b/libc/arch-x86_64/bionic/vfork.S
@@ -27,6 +27,7 @@
  */
 
 #include <private/bionic_asm.h>
+#include <private/bionic_asm_tls.h>
 
 // This custom code preserves the return address across the system call.
 
@@ -36,7 +37,7 @@
 
   // __get_tls()[TLS_SLOT_THREAD_ID]->cached_pid_ = 0
   mov    %fs:0, %rax
-  mov    8(%rax), %rax
+  mov    (TLS_SLOT_THREAD_ID * 8)(%rax), %rax
   movl   $0, 20(%rax)
 
   movl    $__NR_vfork, %eax
diff --git a/libc/async_safe/Android.bp b/libc/async_safe/Android.bp
index 29f90d1..a54d3b0 100644
--- a/libc/async_safe/Android.bp
+++ b/libc/async_safe/Android.bp
@@ -12,6 +12,7 @@
     recovery_available: true,
 
     include_dirs: ["bionic/libc"],
+    header_libs: ["libc_headers"],
 
     export_include_dirs: ["include"],
 }
diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp
index 2b90c90..6279e65 100644
--- a/libc/bionic/__libc_init_main_thread.cpp
+++ b/libc/bionic/__libc_init_main_thread.cpp
@@ -126,6 +126,7 @@
   auto new_tcb = reinterpret_cast<bionic_tcb*>(mapping.static_tls + layout.offset_bionic_tcb());
   auto new_tls = reinterpret_cast<bionic_tls*>(mapping.static_tls + layout.offset_bionic_tls());
 
+  __init_static_tls(mapping.static_tls);
   new_tcb->copy_from_bootstrap(temp_tcb);
   new_tls->copy_from_bootstrap(temp_tls);
   __init_tcb(new_tcb, &main_thread);
diff --git a/libc/bionic/bionic_elf_tls.cpp b/libc/bionic/bionic_elf_tls.cpp
index 55c2c31..4253b97 100644
--- a/libc/bionic/bionic_elf_tls.cpp
+++ b/libc/bionic/bionic_elf_tls.cpp
@@ -28,13 +28,104 @@
 
 #include "private/bionic_elf_tls.h"
 
+#include <async_safe/log.h>
+#include <string.h>
 #include <sys/param.h>
+#include <unistd.h>
 
+#include "private/ScopedRWLock.h"
+#include "private/bionic_globals.h"
 #include "private/bionic_macros.h"
 #include "private/bionic_tls.h"
 
-void StaticTlsLayout::reserve_tcb() {
-  offset_bionic_tcb_ = reserve_type<bionic_tcb>();
+// Search for a TLS segment in the given phdr table. Returns true if it has a
+// TLS segment and false otherwise.
+bool __bionic_get_tls_segment(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                              ElfW(Addr) load_bias, TlsSegment* out) {
+  for (size_t i = 0; i < phdr_count; ++i) {
+    const ElfW(Phdr)& phdr = phdr_table[i];
+    if (phdr.p_type == PT_TLS) {
+      *out = TlsSegment {
+        phdr.p_memsz,
+        phdr.p_align,
+        reinterpret_cast<void*>(load_bias + phdr.p_vaddr),
+        phdr.p_filesz,
+      };
+      return true;
+    }
+  }
+  return false;
+}
+
+// Return true if the alignment of a TLS segment is a valid power-of-two. Also
+// cap the alignment if it's too high.
+bool __bionic_check_tls_alignment(size_t* alignment) {
+  // N.B. The size does not need to be a multiple of the alignment. With
+  // ld.bfd (or after using binutils' strip), the TLS segment's size isn't
+  // rounded up.
+  if (*alignment == 0 || !powerof2(*alignment)) {
+    return false;
+  }
+  // Bionic only respects TLS alignment up to one page.
+  *alignment = MIN(*alignment, PAGE_SIZE);
+  return true;
+}
+
+size_t StaticTlsLayout::offset_thread_pointer() const {
+  return offset_bionic_tcb_ + (-MIN_TLS_SLOT * sizeof(void*));
+}
+
+// Reserves space for the Bionic TCB and the executable's TLS segment. Returns
+// the offset of the executable's TLS segment.
+size_t StaticTlsLayout::reserve_exe_segment_and_tcb(const TlsSegment* exe_segment,
+                                                    const char* progname __attribute__((unused))) {
+  // Special case: if the executable has no TLS segment, then just allocate a
+  // TCB and skip the minimum alignment check on ARM.
+  if (exe_segment == nullptr) {
+    offset_bionic_tcb_ = reserve_type<bionic_tcb>();
+    return 0;
+  }
+
+#if defined(__arm__) || defined(__aarch64__)
+
+  // First reserve enough space for the TCB before the executable segment.
+  reserve(sizeof(bionic_tcb), 1);
+
+  // Then reserve the segment itself.
+  const size_t result = reserve(exe_segment->size, exe_segment->alignment);
+
+  // The variant 1 ABI that ARM linkers follow specifies a 2-word TCB between
+  // the thread pointer and the start of the executable's TLS segment, but both
+  // the thread pointer and the TLS segment are aligned appropriately for the
+  // TLS segment. Calculate the distance between the thread pointer and the
+  // EXE's segment.
+  const size_t exe_tpoff = __BIONIC_ALIGN(sizeof(void*) * 2, exe_segment->alignment);
+
+  const size_t min_bionic_alignment = BIONIC_ROUND_UP_POWER_OF_2(MAX_TLS_SLOT) * sizeof(void*);
+  if (exe_tpoff < min_bionic_alignment) {
+    async_safe_fatal("error: \"%s\": executable's TLS segment is underaligned: "
+                     "alignment is %zu, needs to be at least %zu for %s Bionic",
+                     progname, exe_segment->alignment, min_bionic_alignment,
+                     (sizeof(void*) == 4 ? "ARM" : "ARM64"));
+  }
+
+  offset_bionic_tcb_ = result - exe_tpoff - (-MIN_TLS_SLOT * sizeof(void*));
+  return result;
+
+#elif defined(__i386__) || defined(__x86_64__)
+
+  // x86 uses variant 2 TLS layout. The executable's segment is located just
+  // before the TCB.
+  static_assert(MIN_TLS_SLOT == 0, "First slot of bionic_tcb must be slot #0 on x86");
+  const size_t exe_size = round_up_with_overflow_check(exe_segment->size, exe_segment->alignment);
+  reserve(exe_size, 1);
+  const size_t max_align = MAX(alignof(bionic_tcb), exe_segment->alignment);
+  offset_bionic_tcb_ = reserve(sizeof(bionic_tcb), max_align);
+  return offset_bionic_tcb_ - exe_size;
+
+#else
+#error "Unrecognized architecture"
+#endif
 }
 
 void StaticTlsLayout::reserve_bionic_tls() {
@@ -44,6 +135,10 @@
 void StaticTlsLayout::finish_layout() {
   // Round the offset up to the alignment.
   offset_ = round_up_with_overflow_check(offset_, alignment_);
+
+  if (overflowed_) {
+    async_safe_fatal("error: TLS segments in static TLS overflowed");
+  }
 }
 
 // The size is not required to be a multiple of the alignment. The alignment
@@ -62,3 +157,33 @@
   if (value < old_value) overflowed_ = true;
   return value;
 }
+
+// Copy each TLS module's initialization image into a newly-allocated block of
+// static TLS memory. To reduce dirty pages, this function only writes to pages
+// within the static TLS that need initialization. The memory should already be
+// zero-initialized on entry.
+void __init_static_tls(void* static_tls) {
+  // The part of the table we care about (i.e. static TLS modules) never changes
+  // after startup, but we still need the mutex because the table could grow,
+  // moving the initial part. If this locking is too slow, we can duplicate the
+  // static part of the table.
+  TlsModules& modules = __libc_shared_globals()->tls_modules;
+  ScopedReadLock locker(&modules.rwlock);
+
+  for (size_t i = 0; i < modules.module_count; ++i) {
+    TlsModule& module = modules.module_table[i];
+    if (module.static_offset == SIZE_MAX) {
+      // All of the static modules come before all of the dynamic modules, so
+      // once we see the first dynamic module, we're done.
+      break;
+    }
+    if (module.segment.init_size == 0) {
+      // Skip the memcpy call for TLS segments with no initializer, which is
+      // common.
+      continue;
+    }
+    memcpy(static_cast<char*>(static_tls) + module.static_offset,
+           module.segment.init_ptr,
+           module.segment.init_size);
+  }
+}
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 68650ed..8fbc20e 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -83,10 +83,29 @@
   }
 }
 
-static void layout_static_tls() {
+static void layout_static_tls(KernelArgumentBlock& args) {
   StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
   layout.reserve_bionic_tls();
-  layout.reserve_tcb();
+
+  const char* progname = args.argv[0];
+  ElfW(Phdr)* phdr_start = reinterpret_cast<ElfW(Phdr)*>(getauxval(AT_PHDR));
+  size_t phdr_ct = getauxval(AT_PHNUM);
+
+  static TlsModule mod;
+  if (__bionic_get_tls_segment(phdr_start, phdr_ct, 0, &mod.segment)) {
+    if (!__bionic_check_tls_alignment(&mod.segment.alignment)) {
+      async_safe_fatal("error: TLS segment alignment in \"%s\" is not a power of 2: %zu\n",
+                       progname, mod.segment.alignment);
+    }
+    mod.static_offset = layout.reserve_exe_segment_and_tcb(&mod.segment, progname);
+    mod.first_generation = 1;
+    __libc_shared_globals()->tls_modules.generation = 1;
+    __libc_shared_globals()->tls_modules.module_count = 1;
+    __libc_shared_globals()->tls_modules.module_table = &mod;
+  } else {
+    layout.reserve_exe_segment_and_tcb(nullptr, progname);
+  }
+
   layout.finish_layout();
 }
 
@@ -111,7 +130,7 @@
   __libc_init_globals();
   __libc_shared_globals()->init_progname = args.argv[0];
   __libc_init_AT_SECURE(args.envp);
-  layout_static_tls();
+  layout_static_tls(args);
   __libc_init_main_thread_final();
   __libc_init_common();
 
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index d530fa4..4cc5df9 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -641,42 +641,6 @@
   }
 }
 
-extern "C" void InstallInitHeapprofdHook(int);
-
-// Initializes memory allocation framework once per process.
-static void malloc_init_impl(libc_globals* globals) {
-  struct sigaction action = {};
-  action.sa_handler = InstallInitHeapprofdHook;
-  sigaction(HEAPPROFD_SIGNAL, &action, nullptr);
-
-  const char* prefix;
-  const char* shared_lib;
-  char prop[PROP_VALUE_MAX];
-  char* options = prop;
-  // Prefer malloc debug since it existed first and is a more complete
-  // malloc interceptor than the hooks.
-  if (CheckLoadMallocDebug(&options)) {
-    prefix = "debug";
-    shared_lib = DEBUG_SHARED_LIB;
-  } else if (CheckLoadMallocHooks(&options)) {
-    prefix = "hooks";
-    shared_lib = HOOKS_SHARED_LIB;
-  } else if (CheckLoadHeapprofd()) {
-    prefix = "heapprofd";
-    shared_lib = HEAPPROFD_SHARED_LIB;
-  } else {
-    return;
-  }
-  install_hooks(globals, options, prefix, shared_lib);
-}
-
-// Initializes memory allocation framework.
-// This routine is called from __libc_init routines in libc_init_dynamic.cpp.
-__BIONIC_WEAK_FOR_NATIVE_BRIDGE
-__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
-  malloc_init_impl(globals);
-}
-
 // The logic for triggering heapprofd below is as following.
 // 1. HEAPPROFD_SIGNAL is received by the process.
 // 2. If neither InitHeapprofd nor InitHeapprofdHook are currently installed
@@ -704,6 +668,45 @@
 static _Atomic bool g_heapprofd_init_in_progress = false;
 static _Atomic bool g_heapprofd_init_hook_installed = false;
 
+extern "C" void InstallInitHeapprofdHook(int);
+
+// Initializes memory allocation framework once per process.
+static void malloc_init_impl(libc_globals* globals) {
+  struct sigaction action = {};
+  action.sa_handler = InstallInitHeapprofdHook;
+  sigaction(HEAPPROFD_SIGNAL, &action, nullptr);
+
+  const char* prefix;
+  const char* shared_lib;
+  char prop[PROP_VALUE_MAX];
+  char* options = prop;
+  // Prefer malloc debug since it existed first and is a more complete
+  // malloc interceptor than the hooks.
+  if (CheckLoadMallocDebug(&options)) {
+    prefix = "debug";
+    shared_lib = DEBUG_SHARED_LIB;
+  } else if (CheckLoadMallocHooks(&options)) {
+    prefix = "hooks";
+    shared_lib = HOOKS_SHARED_LIB;
+  } else if (CheckLoadHeapprofd()) {
+    prefix = "heapprofd";
+    shared_lib = HEAPPROFD_SHARED_LIB;
+  } else {
+    return;
+  }
+  if (!atomic_exchange(&g_heapprofd_init_in_progress, true)) {
+    install_hooks(globals, options, prefix, shared_lib);
+    atomic_store(&g_heapprofd_init_in_progress, false);
+  }
+}
+
+// Initializes memory allocation framework.
+// This routine is called from __libc_init routines in libc_init_dynamic.cpp.
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
+  malloc_init_impl(globals);
+}
+
 static void* InitHeapprofd(void*) {
   __libc_globals.mutate([](libc_globals* globals) {
     install_hooks(globals, nullptr, HEAPPROFD_PREFIX, HEAPPROFD_SHARED_LIB);
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index 8676a45..31e0378 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -288,7 +288,8 @@
   auto tcb = reinterpret_cast<bionic_tcb*>(mapping.static_tls + layout.offset_bionic_tcb());
   auto tls = reinterpret_cast<bionic_tls*>(mapping.static_tls + layout.offset_bionic_tls());
 
-  // (Re)initialize TLS pointers.
+  // Initialize TLS memory.
+  __init_static_tls(mapping.static_tls);
   __init_tcb(tcb, thread);
   __init_tcb_stack_guard(tcb);
   __init_bionic_tls_ptrs(tcb, tls);
diff --git a/libc/bionic/pthread_internal.cpp b/libc/bionic/pthread_internal.cpp
index 870a526..46fa630 100644
--- a/libc/bionic/pthread_internal.cpp
+++ b/libc/bionic/pthread_internal.cpp
@@ -35,30 +35,13 @@
 
 #include <async_safe/log.h>
 
+#include "private/ScopedRWLock.h"
 #include "private/bionic_futex.h"
 #include "private/bionic_tls.h"
 
 static pthread_internal_t* g_thread_list = nullptr;
 static pthread_rwlock_t g_thread_list_lock = PTHREAD_RWLOCK_INITIALIZER;
 
-template <bool write> class ScopedRWLock {
- public:
-  explicit ScopedRWLock(pthread_rwlock_t* rwlock) : rwlock_(rwlock) {
-    (write ? pthread_rwlock_wrlock : pthread_rwlock_rdlock)(rwlock_);
-  }
-
-  ~ScopedRWLock() {
-    pthread_rwlock_unlock(rwlock_);
-  }
-
- private:
-  pthread_rwlock_t* rwlock_;
-  BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedRWLock);
-};
-
-typedef ScopedRWLock<true> ScopedWriteLock;
-typedef ScopedRWLock<false> ScopedReadLock;
-
 pthread_t __pthread_internal_add(pthread_internal_t* thread) {
   ScopedWriteLock locker(&g_thread_list_lock);
 
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index e9d0e4b..a919a79 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -280,7 +280,7 @@
  */
 #  define __BIONIC_FORTIFY_VARIADIC static __inline__
 /* Error functions don't have bodies, so they can just be static. */
-#  define __BIONIC_ERROR_FUNCTION_VISIBILITY static
+#  define __BIONIC_ERROR_FUNCTION_VISIBILITY static __attribute__((unused))
 #else
 /* Further increase sharing for some inline functions */
 #  define __pass_object_size_n(n)
diff --git a/libc/kernel/uapi/asm-arm64/asm/hwcap.h b/libc/kernel/uapi/asm-arm64/asm/hwcap.h
index a7cd560..8f50b1d 100644
--- a/libc/kernel/uapi/asm-arm64/asm/hwcap.h
+++ b/libc/kernel/uapi/asm-arm64/asm/hwcap.h
@@ -46,4 +46,5 @@
 #define HWCAP_USCAT (1 << 25)
 #define HWCAP_ILRCPC (1 << 26)
 #define HWCAP_FLAGM (1 << 27)
+#define HWCAP_SSBS (1 << 28)
 #endif
diff --git a/libc/kernel/uapi/asm-arm64/asm/ptrace.h b/libc/kernel/uapi/asm-arm64/asm/ptrace.h
index 4e6c755..e1cfb48 100644
--- a/libc/kernel/uapi/asm-arm64/asm/ptrace.h
+++ b/libc/kernel/uapi/asm-arm64/asm/ptrace.h
@@ -34,6 +34,7 @@
 #define PSR_I_BIT 0x00000080
 #define PSR_A_BIT 0x00000100
 #define PSR_D_BIT 0x00000200
+#define PSR_SSBS_BIT 0x00001000
 #define PSR_PAN_BIT 0x00400000
 #define PSR_UAO_BIT 0x00800000
 #define PSR_V_BIT 0x10000000
diff --git a/libc/kernel/uapi/asm-arm64/asm/siginfo.h b/libc/kernel/uapi/asm-arm64/asm/siginfo.h
index 111a215..a31ebb2 100644
--- a/libc/kernel/uapi/asm-arm64/asm/siginfo.h
+++ b/libc/kernel/uapi/asm-arm64/asm/siginfo.h
@@ -16,8 +16,4 @@
  ***
  ****************************************************************************
  ****************************************************************************/
-#ifndef __ASM_SIGINFO_H
-#define __ASM_SIGINFO_H
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #include <asm-generic/siginfo.h>
-#endif
diff --git a/libc/kernel/uapi/asm-arm64/asm/unistd.h b/libc/kernel/uapi/asm-arm64/asm/unistd.h
index cc151fd..0648b02 100644
--- a/libc/kernel/uapi/asm-arm64/asm/unistd.h
+++ b/libc/kernel/uapi/asm-arm64/asm/unistd.h
@@ -17,4 +17,5 @@
  ****************************************************************************
  ****************************************************************************/
 #define __ARCH_WANT_RENAMEAT
+#define __ARCH_WANT_NEW_STAT
 #include <asm-generic/unistd.h>
diff --git a/libc/kernel/uapi/asm-generic/ioctls.h b/libc/kernel/uapi/asm-generic/ioctls.h
index 41dbce2..f8a4357 100644
--- a/libc/kernel/uapi/asm-generic/ioctls.h
+++ b/libc/kernel/uapi/asm-generic/ioctls.h
@@ -81,6 +81,8 @@
 #define TIOCGPTLCK _IOR('T', 0x39, int)
 #define TIOCGEXCL _IOR('T', 0x40, int)
 #define TIOCGPTPEER _IO('T', 0x41)
+#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
 #define FIONCLEX 0x5450
 #define FIOCLEX 0x5451
 #define FIOASYNC 0x5452
diff --git a/libc/kernel/uapi/asm-generic/siginfo.h b/libc/kernel/uapi/asm-generic/siginfo.h
index 166193b..829ffad 100644
--- a/libc/kernel/uapi/asm-generic/siginfo.h
+++ b/libc/kernel/uapi/asm-generic/siginfo.h
@@ -24,13 +24,7 @@
   int sival_int;
   void __user * sival_ptr;
 } sigval_t;
-#ifndef __ARCH_SI_PREAMBLE_SIZE
-#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#endif
 #define SI_MAX_SIZE 128
-#ifndef SI_PAD_SIZE
-#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int))
-#endif
 #ifndef __ARCH_SI_BAND_T
 #define __ARCH_SI_BAND_T long
 #endif
@@ -40,73 +34,75 @@
 #ifndef __ARCH_SI_ATTRIBUTES
 #define __ARCH_SI_ATTRIBUTES
 #endif
-typedef struct siginfo {
-  int si_signo;
-#ifndef __ARCH_HAS_SWAPPED_SIGINFO
-  int si_errno;
-  int si_code;
-#else
-  int si_code;
-  int si_errno;
-#endif
-  union {
-    int _pad[SI_PAD_SIZE];
-    struct {
-      __kernel_pid_t _pid;
-      __kernel_uid32_t _uid;
-    } _kill;
-    struct {
-      __kernel_timer_t _tid;
-      int _overrun;
-      sigval_t _sigval;
-      int _sys_private;
-    } _timer;
-    struct {
-      __kernel_pid_t _pid;
-      __kernel_uid32_t _uid;
-      sigval_t _sigval;
-    } _rt;
-    struct {
-      __kernel_pid_t _pid;
-      __kernel_uid32_t _uid;
-      int _status;
-      __ARCH_SI_CLOCK_T _utime;
-      __ARCH_SI_CLOCK_T _stime;
-    } _sigchld;
-    struct {
-      void __user * _addr;
+union __sifields {
+  struct {
+    __kernel_pid_t _pid;
+    __kernel_uid32_t _uid;
+  } _kill;
+  struct {
+    __kernel_timer_t _tid;
+    int _overrun;
+    sigval_t _sigval;
+    int _sys_private;
+  } _timer;
+  struct {
+    __kernel_pid_t _pid;
+    __kernel_uid32_t _uid;
+    sigval_t _sigval;
+  } _rt;
+  struct {
+    __kernel_pid_t _pid;
+    __kernel_uid32_t _uid;
+    int _status;
+    __ARCH_SI_CLOCK_T _utime;
+    __ARCH_SI_CLOCK_T _stime;
+  } _sigchld;
+  struct {
+    void __user * _addr;
 #ifdef __ARCH_SI_TRAPNO
-      int _trapno;
+    int _trapno;
 #endif
 #ifdef __ia64__
-      int _imm;
-      unsigned int _flags;
-      unsigned long _isr;
+    int _imm;
+    unsigned int _flags;
+    unsigned long _isr;
 #endif
 #define __ADDR_BND_PKEY_PAD (__alignof__(void *) < sizeof(short) ? sizeof(short) : __alignof__(void *))
-      union {
-        short _addr_lsb;
-        struct {
-          char _dummy_bnd[__ADDR_BND_PKEY_PAD];
-          void __user * _lower;
-          void __user * _upper;
-        } _addr_bnd;
-        struct {
-          char _dummy_pkey[__ADDR_BND_PKEY_PAD];
-          __u32 _pkey;
-        } _addr_pkey;
-      };
-    } _sigfault;
-    struct {
-      __ARCH_SI_BAND_T _band;
-      int _fd;
-    } _sigpoll;
-    struct {
-      void __user * _call_addr;
-      int _syscall;
-      unsigned int _arch;
-    } _sigsys;
-  } _sifields;
+    union {
+      short _addr_lsb;
+      struct {
+        char _dummy_bnd[__ADDR_BND_PKEY_PAD];
+        void __user * _lower;
+        void __user * _upper;
+      } _addr_bnd;
+      struct {
+        char _dummy_pkey[__ADDR_BND_PKEY_PAD];
+        __u32 _pkey;
+      } _addr_pkey;
+    };
+  } _sigfault;
+  struct {
+    __ARCH_SI_BAND_T _band;
+    int _fd;
+  } _sigpoll;
+  struct {
+    void __user * _call_addr;
+    int _syscall;
+    unsigned int _arch;
+  } _sigsys;
+};
+#ifndef __ARCH_HAS_SWAPPED_SIGINFO
+#define __SIGINFO struct { int si_signo; int si_errno; int si_code; union __sifields _sifields; \
+}
+#else
+#define __SIGINFO struct { int si_signo; int si_code; int si_errno; union __sifields _sifields; \
+}
+#endif
+typedef struct siginfo {
+  union {
+    __SIGINFO;
+    int _si_pad[SI_MAX_SIZE / sizeof(int)];
+  };
 } __ARCH_SI_ATTRIBUTES siginfo_t;
 #define si_pid _sifields._kill._pid
 #define si_uid _sifields._kill._uid
@@ -212,6 +208,8 @@
 #define NSIGPOLL 6
 #define SYS_SECCOMP 1
 #define NSIGSYS 1
+#define EMT_TAGOVF 1
+#define NSIGEMT 1
 #define SIGEV_SIGNAL 0
 #define SIGEV_NONE 1
 #define SIGEV_THREAD 2
diff --git a/libc/kernel/uapi/asm-generic/unistd.h b/libc/kernel/uapi/asm-generic/unistd.h
index 52f0b57..fddf1d0 100644
--- a/libc/kernel/uapi/asm-generic/unistd.h
+++ b/libc/kernel/uapi/asm-generic/unistd.h
@@ -113,8 +113,10 @@
 #define __NR_splice 76
 #define __NR_tee 77
 #define __NR_readlinkat 78
+#if defined(__ARCH_WANT_NEW_STAT) || defined(__ARCH_WANT_STAT64)
 #define __NR3264_fstatat 79
 #define __NR3264_fstat 80
+#endif
 #define __NR_sync 81
 #define __NR_fsync 82
 #define __NR_fdatasync 83
@@ -329,8 +331,10 @@
 #define __NR_ftruncate __NR3264_ftruncate
 #define __NR_lseek __NR3264_lseek
 #define __NR_sendfile __NR3264_sendfile
+#if defined(__ARCH_WANT_NEW_STAT) || defined(__ARCH_WANT_STAT64)
 #define __NR_newfstatat __NR3264_fstatat
 #define __NR_fstat __NR3264_fstat
+#endif
 #define __NR_mmap __NR3264_mmap
 #define __NR_fadvise64 __NR3264_fadvise64
 #ifdef __NR3264_stat
@@ -345,8 +349,10 @@
 #define __NR_ftruncate64 __NR3264_ftruncate
 #define __NR_llseek __NR3264_lseek
 #define __NR_sendfile64 __NR3264_sendfile
+#if defined(__ARCH_WANT_NEW_STAT) || defined(__ARCH_WANT_STAT64)
 #define __NR_fstatat64 __NR3264_fstatat
 #define __NR_fstat64 __NR3264_fstat
+#endif
 #define __NR_mmap2 __NR3264_mmap
 #define __NR_fadvise64_64 __NR3264_fadvise64
 #ifdef __NR3264_stat
diff --git a/libc/kernel/uapi/asm-mips/asm/ioctls.h b/libc/kernel/uapi/asm-mips/asm/ioctls.h
index a4a40b0..694546f 100644
--- a/libc/kernel/uapi/asm-mips/asm/ioctls.h
+++ b/libc/kernel/uapi/asm-mips/asm/ioctls.h
@@ -85,6 +85,8 @@
 #define TIOCGPTLCK _IOR('T', 0x39, int)
 #define TIOCGEXCL _IOR('T', 0x40, int)
 #define TIOCGPTPEER _IO('T', 0x41)
+#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
 #define TIOCSCTTY 0x5480
 #define TIOCGSOFTCAR 0x5481
 #define TIOCSSOFTCAR 0x5482
diff --git a/libc/kernel/uapi/asm-mips/asm/siginfo.h b/libc/kernel/uapi/asm-mips/asm/siginfo.h
index c37107b..c9efb21 100644
--- a/libc/kernel/uapi/asm-mips/asm/siginfo.h
+++ b/libc/kernel/uapi/asm-mips/asm/siginfo.h
@@ -20,13 +20,6 @@
 #define _UAPI_ASM_SIGINFO_H
 #define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(long) + 2 * sizeof(int))
 #undef __ARCH_SI_TRAPNO
-#if _MIPS_SZLONG == 32
-#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#elif _MIPS_SZLONG==64
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
-#else
-#error _MIPS_SZLONG neither 32 nor 64
-#endif
 #define __ARCH_HAS_SWAPPED_SIGINFO
 #include <asm-generic/siginfo.h>
 #undef SI_ASYNCIO
diff --git a/libc/kernel/uapi/asm-x86/asm/bootparam.h b/libc/kernel/uapi/asm-x86/asm/bootparam.h
index b010277..dc90f57 100644
--- a/libc/kernel/uapi/asm-x86/asm/bootparam.h
+++ b/libc/kernel/uapi/asm-x86/asm/bootparam.h
@@ -135,7 +135,8 @@
   __u8 _pad2[4];
   __u64 tboot_addr;
   struct ist_info ist_info;
-  __u8 _pad3[16];
+  __u64 acpi_rsdp_addr;
+  __u8 _pad3[8];
   __u8 hd0_info[16];
   __u8 hd1_info[16];
   struct sys_desc_table sys_desc_table;
diff --git a/libc/kernel/uapi/asm-x86/asm/kvm.h b/libc/kernel/uapi/asm-x86/asm/kvm.h
index 1d7f767..4386f76 100644
--- a/libc/kernel/uapi/asm-x86/asm/kvm.h
+++ b/libc/kernel/uapi/asm-x86/asm/kvm.h
@@ -248,6 +248,7 @@
 #define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
 #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
 #define KVM_VCPUEVENT_VALID_SMM 0x00000008
+#define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010
 #define KVM_X86_SHADOW_INT_MOV_SS 0x01
 #define KVM_X86_SHADOW_INT_STI 0x02
 struct kvm_vcpu_events {
@@ -255,7 +256,7 @@
     __u8 injected;
     __u8 nr;
     __u8 has_error_code;
-    __u8 pad;
+    __u8 pending;
     __u32 error_code;
   } exception;
   struct {
@@ -278,7 +279,9 @@
     __u8 smm_inside_nmi;
     __u8 latched_init;
   } smi;
-  __u32 reserved[9];
+  __u8 reserved[27];
+  __u8 exception_has_payload;
+  __u64 exception_payload;
 };
 struct kvm_debugregs {
   __u64 db[4];
@@ -316,6 +319,7 @@
 #define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2)
 #define KVM_STATE_NESTED_GUEST_MODE 0x00000001
 #define KVM_STATE_NESTED_RUN_PENDING 0x00000002
+#define KVM_STATE_NESTED_EVMCS 0x00000004
 #define KVM_STATE_NESTED_SMM_GUEST_MODE 0x00000001
 #define KVM_STATE_NESTED_SMM_VMXON 0x00000002
 struct kvm_vmx_nested_state {
diff --git a/libc/kernel/uapi/asm-x86/asm/siginfo.h b/libc/kernel/uapi/asm-x86/asm/siginfo.h
index 1da8066..0de5283 100644
--- a/libc/kernel/uapi/asm-x86/asm/siginfo.h
+++ b/libc/kernel/uapi/asm-x86/asm/siginfo.h
@@ -23,8 +23,6 @@
 typedef long long __kernel_si_clock_t __attribute__((aligned(4)));
 #define __ARCH_SI_CLOCK_T __kernel_si_clock_t
 #define __ARCH_SI_ATTRIBUTES __attribute__((aligned(8)))
-#else
-#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 #endif
 #include <asm-generic/siginfo.h>
diff --git a/libc/kernel/uapi/drm/amdgpu_drm.h b/libc/kernel/uapi/drm/amdgpu_drm.h
index 2013fa7..8d65fd4 100644
--- a/libc/kernel/uapi/drm/amdgpu_drm.h
+++ b/libc/kernel/uapi/drm/amdgpu_drm.h
@@ -406,6 +406,7 @@
 #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_CNTL 0x0f
 #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_GPM_MEM 0x10
 #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_SRM_MEM 0x11
+#define AMDGPU_INFO_FW_DMCU 0x12
 #define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f
 #define AMDGPU_INFO_VRAM_USAGE 0x10
 #define AMDGPU_INFO_GTT_USAGE 0x11
diff --git a/libc/kernel/uapi/drm/drm_fourcc.h b/libc/kernel/uapi/drm/drm_fourcc.h
index 4589cfe..df89cd1 100644
--- a/libc/kernel/uapi/drm/drm_fourcc.h
+++ b/libc/kernel/uapi/drm/drm_fourcc.h
@@ -24,6 +24,7 @@
 #endif
 #define fourcc_code(a,b,c,d) ((__u32) (a) | ((__u32) (b) << 8) | ((__u32) (c) << 16) | ((__u32) (d) << 24))
 #define DRM_FORMAT_BIG_ENDIAN (1 << 31)
+#define DRM_FORMAT_INVALID 0
 #define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ')
 #define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ')
 #define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ')
@@ -118,6 +119,7 @@
 #define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4)
 #define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5)
 #define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1)
+#define DRM_FORMAT_MOD_SAMSUNG_16_16_TILE fourcc_mod_code(SAMSUNG, 2)
 #define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1)
 #define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1)
 #define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2)
diff --git a/libc/kernel/uapi/drm/i915_drm.h b/libc/kernel/uapi/drm/i915_drm.h
index 53d1548..89fa529 100644
--- a/libc/kernel/uapi/drm/i915_drm.h
+++ b/libc/kernel/uapi/drm/i915_drm.h
@@ -335,6 +335,7 @@
 #define I915_PARAM_HAS_EXEC_FENCE_ARRAY 49
 #define I915_PARAM_HAS_CONTEXT_ISOLATION 50
 #define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51
+#define I915_PARAM_MMAP_GTT_COHERENT 52
 typedef struct drm_i915_getparam {
   __s32 param;
   int __user * value;
diff --git a/libc/kernel/uapi/linux/android/binder.h b/libc/kernel/uapi/linux/android/binder.h
index 538a441..2d00a79 100644
--- a/libc/kernel/uapi/linux/android/binder.h
+++ b/libc/kernel/uapi/linux/android/binder.h
@@ -103,6 +103,14 @@
   __u32 has_strong_ref;
   __u32 has_weak_ref;
 };
+struct binder_node_info_for_ref {
+  __u32 handle;
+  __u32 strong_count;
+  __u32 weak_count;
+  __u32 reserved1;
+  __u32 reserved2;
+  __u32 reserved3;
+};
 #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
 #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
 #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
@@ -111,6 +119,7 @@
 #define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
 #define BINDER_VERSION _IOWR('b', 9, struct binder_version)
 #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
+#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref)
 enum transaction_flags {
   TF_ONE_WAY = 0x01,
   TF_ROOT_OBJECT = 0x04,
diff --git a/libc/kernel/uapi/linux/blkzoned.h b/libc/kernel/uapi/linux/blkzoned.h
index eaff1d8..62f826f 100644
--- a/libc/kernel/uapi/linux/blkzoned.h
+++ b/libc/kernel/uapi/linux/blkzoned.h
@@ -57,4 +57,6 @@
 };
 #define BLKREPORTZONE _IOWR(0x12, 130, struct blk_zone_report)
 #define BLKRESETZONE _IOW(0x12, 131, struct blk_zone_range)
+#define BLKGETZONESZ _IOR(0x12, 132, __u32)
+#define BLKGETNRZONES _IOR(0x12, 133, __u32)
 #endif
diff --git a/libc/kernel/uapi/linux/bpf.h b/libc/kernel/uapi/linux/bpf.h
index a187913..d70a409 100644
--- a/libc/kernel/uapi/linux/bpf.h
+++ b/libc/kernel/uapi/linux/bpf.h
@@ -91,6 +91,7 @@
   BPF_BTF_LOAD,
   BPF_BTF_GET_FD_BY_ID,
   BPF_TASK_FD_QUERY,
+  BPF_MAP_LOOKUP_AND_DELETE_ELEM,
 };
 enum bpf_map_type {
   BPF_MAP_TYPE_UNSPEC,
@@ -114,6 +115,9 @@
   BPF_MAP_TYPE_SOCKHASH,
   BPF_MAP_TYPE_CGROUP_STORAGE,
   BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
+  BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
+  BPF_MAP_TYPE_QUEUE,
+  BPF_MAP_TYPE_STACK,
 };
 enum bpf_prog_type {
   BPF_PROG_TYPE_UNSPEC,
@@ -138,6 +142,7 @@
   BPF_PROG_TYPE_LWT_SEG6LOCAL,
   BPF_PROG_TYPE_LIRC_MODE2,
   BPF_PROG_TYPE_SK_REUSEPORT,
+  BPF_PROG_TYPE_FLOW_DISSECTOR,
 };
 enum bpf_attach_type {
   BPF_CGROUP_INET_INGRESS,
@@ -157,6 +162,7 @@
   BPF_CGROUP_UDP4_SENDMSG,
   BPF_CGROUP_UDP6_SENDMSG,
   BPF_LIRC_MODE2,
+  BPF_FLOW_DISSECTOR,
   __MAX_BPF_ATTACH_TYPE
 };
 #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
@@ -295,7 +301,7 @@
     __u64 probe_addr;
   } task_fd_query;
 } __attribute__((aligned(8)));
-#define __BPF_FUNC_MAPPER(FN) FN(unspec), FN(map_lookup_elem), FN(map_update_elem), FN(map_delete_elem), FN(probe_read), FN(ktime_get_ns), FN(trace_printk), FN(get_prandom_u32), FN(get_smp_processor_id), FN(skb_store_bytes), FN(l3_csum_replace), FN(l4_csum_replace), FN(tail_call), FN(clone_redirect), FN(get_current_pid_tgid), FN(get_current_uid_gid), FN(get_current_comm), FN(get_cgroup_classid), FN(skb_vlan_push), FN(skb_vlan_pop), FN(skb_get_tunnel_key), FN(skb_set_tunnel_key), FN(perf_event_read), FN(redirect), FN(get_route_realm), FN(perf_event_output), FN(skb_load_bytes), FN(get_stackid), FN(csum_diff), FN(skb_get_tunnel_opt), FN(skb_set_tunnel_opt), FN(skb_change_proto), FN(skb_change_type), FN(skb_under_cgroup), FN(get_hash_recalc), FN(get_current_task), FN(probe_write_user), FN(current_task_under_cgroup), FN(skb_change_tail), FN(skb_pull_data), FN(csum_update), FN(set_hash_invalid), FN(get_numa_node_id), FN(skb_change_head), FN(xdp_adjust_head), FN(probe_read_str), FN(get_socket_cookie), FN(get_socket_uid), FN(set_hash), FN(setsockopt), FN(skb_adjust_room), FN(redirect_map), FN(sk_redirect_map), FN(sock_map_update), FN(xdp_adjust_meta), FN(perf_event_read_value), FN(perf_prog_read_value), FN(getsockopt), FN(override_return), FN(sock_ops_cb_flags_set), FN(msg_redirect_map), FN(msg_apply_bytes), FN(msg_cork_bytes), FN(msg_pull_data), FN(bind), FN(xdp_adjust_tail), FN(skb_get_xfrm_state), FN(get_stack), FN(skb_load_bytes_relative), FN(fib_lookup), FN(sock_hash_update), FN(msg_redirect_hash), FN(sk_redirect_hash), FN(lwt_push_encap), FN(lwt_seg6_store_bytes), FN(lwt_seg6_adjust_srh), FN(lwt_seg6_action), FN(rc_repeat), FN(rc_keydown), FN(skb_cgroup_id), FN(get_current_cgroup_id), FN(get_local_storage), FN(sk_select_reuseport), FN(skb_ancestor_cgroup_id),
+#define __BPF_FUNC_MAPPER(FN) FN(unspec), FN(map_lookup_elem), FN(map_update_elem), FN(map_delete_elem), FN(probe_read), FN(ktime_get_ns), FN(trace_printk), FN(get_prandom_u32), FN(get_smp_processor_id), FN(skb_store_bytes), FN(l3_csum_replace), FN(l4_csum_replace), FN(tail_call), FN(clone_redirect), FN(get_current_pid_tgid), FN(get_current_uid_gid), FN(get_current_comm), FN(get_cgroup_classid), FN(skb_vlan_push), FN(skb_vlan_pop), FN(skb_get_tunnel_key), FN(skb_set_tunnel_key), FN(perf_event_read), FN(redirect), FN(get_route_realm), FN(perf_event_output), FN(skb_load_bytes), FN(get_stackid), FN(csum_diff), FN(skb_get_tunnel_opt), FN(skb_set_tunnel_opt), FN(skb_change_proto), FN(skb_change_type), FN(skb_under_cgroup), FN(get_hash_recalc), FN(get_current_task), FN(probe_write_user), FN(current_task_under_cgroup), FN(skb_change_tail), FN(skb_pull_data), FN(csum_update), FN(set_hash_invalid), FN(get_numa_node_id), FN(skb_change_head), FN(xdp_adjust_head), FN(probe_read_str), FN(get_socket_cookie), FN(get_socket_uid), FN(set_hash), FN(setsockopt), FN(skb_adjust_room), FN(redirect_map), FN(sk_redirect_map), FN(sock_map_update), FN(xdp_adjust_meta), FN(perf_event_read_value), FN(perf_prog_read_value), FN(getsockopt), FN(override_return), FN(sock_ops_cb_flags_set), FN(msg_redirect_map), FN(msg_apply_bytes), FN(msg_cork_bytes), FN(msg_pull_data), FN(bind), FN(xdp_adjust_tail), FN(skb_get_xfrm_state), FN(get_stack), FN(skb_load_bytes_relative), FN(fib_lookup), FN(sock_hash_update), FN(msg_redirect_hash), FN(sk_redirect_hash), FN(lwt_push_encap), FN(lwt_seg6_store_bytes), FN(lwt_seg6_adjust_srh), FN(lwt_seg6_action), FN(rc_repeat), FN(rc_keydown), FN(skb_cgroup_id), FN(get_current_cgroup_id), FN(get_local_storage), FN(sk_select_reuseport), FN(skb_ancestor_cgroup_id), FN(sk_lookup_tcp), FN(sk_lookup_udp), FN(sk_release), FN(map_push_elem), FN(map_pop_elem), FN(map_peek_elem), FN(msg_push_data),
 #define __BPF_ENUM_FN(x) BPF_FUNC_ ##x
 enum bpf_func_id {
   __BPF_FUNC_MAPPER(__BPF_ENUM_FN) __BPF_FUNC_MAX_ID,
@@ -320,6 +326,7 @@
 #define BPF_F_INDEX_MASK 0xffffffffULL
 #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK
 #define BPF_F_CTXLEN_MASK (0xfffffULL << 32)
+#define BPF_F_CURRENT_NETNS (- 1L)
 enum bpf_adj_room_mode {
   BPF_ADJ_ROOM_NET,
 };
@@ -331,6 +338,8 @@
   BPF_LWT_ENCAP_SEG6,
   BPF_LWT_ENCAP_SEG6_INLINE
 };
+#define __bpf_md_ptr(type,name) union { type name; __u64 : 64; \
+} __attribute__((aligned(8)))
 struct __sk_buff {
   __u32 len;
   __u32 pkt_type;
@@ -358,6 +367,7 @@
   __u32 remote_port;
   __u32 local_port;
   __u32 data_meta;
+  __bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
 };
 struct bpf_tunnel_key {
   __u32 tunnel_id;
@@ -396,6 +406,22 @@
   __u32 src_ip6[4];
   __u32 src_port;
 };
+struct bpf_sock_tuple {
+  union {
+    struct {
+      __be32 saddr;
+      __be32 daddr;
+      __be16 sport;
+      __be16 dport;
+    } ipv4;
+    struct {
+      __be32 saddr[4];
+      __be32 daddr[4];
+      __be16 sport;
+      __be16 dport;
+    } ipv6;
+  };
+};
 #define XDP_PACKET_HEADROOM 256
 enum xdp_action {
   XDP_ABORTED = 0,
@@ -416,8 +442,8 @@
   SK_PASS,
 };
 struct sk_msg_md {
-  void * data;
-  void * data_end;
+  __bpf_md_ptr(void *, data);
+  __bpf_md_ptr(void *, data_end);
   __u32 family;
   __u32 remote_ip4;
   __u32 local_ip4;
@@ -427,8 +453,8 @@
   __u32 local_port;
 };
 struct sk_reuseport_md {
-  void * data;
-  void * data_end;
+  __bpf_md_ptr(void *, data);
+  __bpf_md_ptr(void *, data_end);
   __u32 len;
   __u32 eth_protocol;
   __u32 ip_protocol;
@@ -630,4 +656,26 @@
   BPF_FD_TYPE_UPROBE,
   BPF_FD_TYPE_URETPROBE,
 };
+struct bpf_flow_keys {
+  __u16 nhoff;
+  __u16 thoff;
+  __u16 addr_proto;
+  __u8 is_frag;
+  __u8 is_first_frag;
+  __u8 is_encap;
+  __u8 ip_proto;
+  __be16 n_proto;
+  __be16 sport;
+  __be16 dport;
+  union {
+    struct {
+      __be32 ipv4_src;
+      __be32 ipv4_dst;
+    };
+    struct {
+      __u32 ipv6_src[4];
+      __u32 ipv6_dst[4];
+    };
+  };
+};
 #endif
diff --git a/libc/kernel/uapi/linux/cec.h b/libc/kernel/uapi/linux/cec.h
index fd0f824..05af529 100644
--- a/libc/kernel/uapi/linux/cec.h
+++ b/libc/kernel/uapi/linux/cec.h
@@ -44,9 +44,12 @@
 #define CEC_TX_STATUS_LOW_DRIVE (1 << 3)
 #define CEC_TX_STATUS_ERROR (1 << 4)
 #define CEC_TX_STATUS_MAX_RETRIES (1 << 5)
+#define CEC_TX_STATUS_ABORTED (1 << 6)
+#define CEC_TX_STATUS_TIMEOUT (1 << 7)
 #define CEC_RX_STATUS_OK (1 << 0)
 #define CEC_RX_STATUS_TIMEOUT (1 << 1)
 #define CEC_RX_STATUS_FEATURE_ABORT (1 << 2)
+#define CEC_RX_STATUS_ABORTED (1 << 3)
 #define CEC_LOG_ADDR_INVALID 0xff
 #define CEC_PHYS_ADDR_INVALID 0xffff
 #define CEC_MAX_LOG_ADDRS 4
diff --git a/libc/kernel/uapi/linux/cryptouser.h b/libc/kernel/uapi/linux/cryptouser.h
index 15c46d8..816fb05 100644
--- a/libc/kernel/uapi/linux/cryptouser.h
+++ b/libc/kernel/uapi/linux/cryptouser.h
@@ -24,6 +24,7 @@
   CRYPTO_MSG_UPDATEALG,
   CRYPTO_MSG_GETALG,
   CRYPTO_MSG_DELRNG,
+  CRYPTO_MSG_GETSTAT,
   __CRYPTO_MSG_MAX
 };
 #define CRYPTO_MSG_MAX (__CRYPTO_MSG_MAX - 1)
@@ -42,6 +43,16 @@
   CRYPTOCFGA_REPORT_AKCIPHER,
   CRYPTOCFGA_REPORT_KPP,
   CRYPTOCFGA_REPORT_ACOMP,
+  CRYPTOCFGA_STAT_LARVAL,
+  CRYPTOCFGA_STAT_HASH,
+  CRYPTOCFGA_STAT_BLKCIPHER,
+  CRYPTOCFGA_STAT_AEAD,
+  CRYPTOCFGA_STAT_COMPRESS,
+  CRYPTOCFGA_STAT_RNG,
+  CRYPTOCFGA_STAT_CIPHER,
+  CRYPTOCFGA_STAT_AKCIPHER,
+  CRYPTOCFGA_STAT_KPP,
+  CRYPTOCFGA_STAT_ACOMP,
   __CRYPTOCFGA_MAX
 #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1)
 };
@@ -54,6 +65,46 @@
   __u32 cru_refcnt;
   __u32 cru_flags;
 };
+struct crypto_stat {
+  char type[CRYPTO_MAX_NAME];
+  union {
+    __u32 stat_encrypt_cnt;
+    __u32 stat_compress_cnt;
+    __u32 stat_generate_cnt;
+    __u32 stat_hash_cnt;
+    __u32 stat_setsecret_cnt;
+  };
+  union {
+    __u64 stat_encrypt_tlen;
+    __u64 stat_compress_tlen;
+    __u64 stat_generate_tlen;
+    __u64 stat_hash_tlen;
+  };
+  union {
+    __u32 stat_akcipher_err_cnt;
+    __u32 stat_cipher_err_cnt;
+    __u32 stat_compress_err_cnt;
+    __u32 stat_aead_err_cnt;
+    __u32 stat_hash_err_cnt;
+    __u32 stat_rng_err_cnt;
+    __u32 stat_kpp_err_cnt;
+  };
+  union {
+    __u32 stat_decrypt_cnt;
+    __u32 stat_decompress_cnt;
+    __u32 stat_seed_cnt;
+    __u32 stat_generate_public_key_cnt;
+  };
+  union {
+    __u64 stat_decrypt_tlen;
+    __u64 stat_decompress_tlen;
+  };
+  union {
+    __u32 stat_verify_cnt;
+    __u32 stat_compute_shared_secret_cnt;
+  };
+  __u32 stat_sign_cnt;
+};
 struct crypto_report_larval {
   char type[CRYPTO_MAX_NAME];
 };
diff --git a/libc/kernel/uapi/linux/dns_resolver.h b/libc/kernel/uapi/linux/dns_resolver.h
new file mode 100644
index 0000000..21cb5c0
--- /dev/null
+++ b/libc/kernel/uapi/linux/dns_resolver.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_DNS_RESOLVER_H
+#define _UAPI_LINUX_DNS_RESOLVER_H
+#include <linux/types.h>
+enum dns_payload_content_type {
+  DNS_PAYLOAD_IS_SERVER_LIST = 0,
+};
+enum dns_payload_address_type {
+  DNS_ADDRESS_IS_IPV4 = 0,
+  DNS_ADDRESS_IS_IPV6 = 1,
+};
+enum dns_payload_protocol_type {
+  DNS_SERVER_PROTOCOL_UNSPECIFIED = 0,
+  DNS_SERVER_PROTOCOL_UDP = 1,
+  DNS_SERVER_PROTOCOL_TCP = 2,
+};
+enum dns_record_source {
+  DNS_RECORD_UNAVAILABLE = 0,
+  DNS_RECORD_FROM_CONFIG = 1,
+  DNS_RECORD_FROM_DNS_A = 2,
+  DNS_RECORD_FROM_DNS_AFSDB = 3,
+  DNS_RECORD_FROM_DNS_SRV = 4,
+  DNS_RECORD_FROM_NSS = 5,
+  NR__dns_record_source
+};
+enum dns_lookup_status {
+  DNS_LOOKUP_NOT_DONE = 0,
+  DNS_LOOKUP_GOOD = 1,
+  DNS_LOOKUP_GOOD_WITH_BAD = 2,
+  DNS_LOOKUP_BAD = 3,
+  DNS_LOOKUP_GOT_NOT_FOUND = 4,
+  DNS_LOOKUP_GOT_LOCAL_FAILURE = 5,
+  DNS_LOOKUP_GOT_TEMP_FAILURE = 6,
+  DNS_LOOKUP_GOT_NS_FAILURE = 7,
+  NR__dns_lookup_status
+};
+struct dns_payload_header {
+  __u8 zero;
+  __u8 content;
+  __u8 version;
+} __packed;
+struct dns_server_list_v1_header {
+  struct dns_payload_header hdr;
+  __u8 source;
+  __u8 status;
+  __u8 nr_servers;
+} __packed;
+struct dns_server_list_v1_server {
+  __u16 name_len;
+  __u16 priority;
+  __u16 weight;
+  __u16 port;
+  __u8 source;
+  __u8 status;
+  __u8 protocol;
+  __u8 nr_addrs;
+} __packed;
+struct dns_server_list_v1_address {
+  __u8 address_type;
+} __packed;
+#endif
diff --git a/libc/kernel/uapi/linux/elf-em.h b/libc/kernel/uapi/linux/elf-em.h
index b7c89da..5b54e18 100644
--- a/libc/kernel/uapi/linux/elf-em.h
+++ b/libc/kernel/uapi/linux/elf-em.h
@@ -52,6 +52,7 @@
 #define EM_TILEPRO 188
 #define EM_MICROBLAZE 189
 #define EM_TILEGX 191
+#define EM_RISCV 243
 #define EM_BPF 247
 #define EM_FRV 0x5441
 #define EM_ALPHA 0x9026
diff --git a/libc/kernel/uapi/linux/fanotify.h b/libc/kernel/uapi/linux/fanotify.h
index 73d92ca..00a1871 100644
--- a/libc/kernel/uapi/linux/fanotify.h
+++ b/libc/kernel/uapi/linux/fanotify.h
@@ -39,15 +39,18 @@
 #define FAN_UNLIMITED_QUEUE 0x00000010
 #define FAN_UNLIMITED_MARKS 0x00000020
 #define FAN_ENABLE_AUDIT 0x00000040
+#define FAN_REPORT_TID 0x00000100
 #define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS)
 #define FAN_MARK_ADD 0x00000001
 #define FAN_MARK_REMOVE 0x00000002
 #define FAN_MARK_DONT_FOLLOW 0x00000004
 #define FAN_MARK_ONLYDIR 0x00000008
-#define FAN_MARK_MOUNT 0x00000010
 #define FAN_MARK_IGNORED_MASK 0x00000020
 #define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
 #define FAN_MARK_FLUSH 0x00000080
+#define FAN_MARK_INODE 0x00000000
+#define FAN_MARK_MOUNT 0x00000010
+#define FAN_MARK_FILESYSTEM 0x00000100
 #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_DONT_FOLLOW | FAN_MARK_ONLYDIR | FAN_MARK_MOUNT | FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY | FAN_MARK_FLUSH)
 #define FAN_ALL_EVENTS (FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN)
 #define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_ACCESS_PERM)
diff --git a/libc/kernel/uapi/linux/fuse.h b/libc/kernel/uapi/linux/fuse.h
index a727580..3c3a124 100644
--- a/libc/kernel/uapi/linux/fuse.h
+++ b/libc/kernel/uapi/linux/fuse.h
@@ -20,7 +20,7 @@
 #define _LINUX_FUSE_H
 #include <stdint.h>
 #define FUSE_KERNEL_VERSION 7
-#define FUSE_KERNEL_MINOR_VERSION 27
+#define FUSE_KERNEL_MINOR_VERSION 28
 #define FUSE_ROOT_ID 1
 struct fuse_attr {
   uint64_t ino;
@@ -72,6 +72,7 @@
 #define FOPEN_DIRECT_IO (1 << 0)
 #define FOPEN_KEEP_CACHE (1 << 1)
 #define FOPEN_NONSEEKABLE (1 << 2)
+#define FOPEN_CACHE_DIR (1 << 3)
 #define FUSE_ASYNC_READ (1 << 0)
 #define FUSE_POSIX_LOCKS (1 << 1)
 #define FUSE_FILE_OPS (1 << 2)
@@ -94,6 +95,8 @@
 #define FUSE_HANDLE_KILLPRIV (1 << 19)
 #define FUSE_POSIX_ACL (1 << 20)
 #define FUSE_ABORT_ERROR (1 << 21)
+#define FUSE_MAX_PAGES (1 << 22)
+#define FUSE_CACHE_SYMLINKS (1 << 23)
 #define CUSE_UNRESTRICTED_IOCTL (1 << 0)
 #define FUSE_RELEASE_FLUSH (1 << 0)
 #define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
@@ -154,6 +157,7 @@
   FUSE_READDIRPLUS = 44,
   FUSE_RENAME2 = 45,
   FUSE_LSEEK = 46,
+  FUSE_COPY_FILE_RANGE = 47,
   CUSE_INIT = 4096,
 };
 enum fuse_notify_code {
@@ -341,7 +345,9 @@
   uint16_t congestion_threshold;
   uint32_t max_write;
   uint32_t time_gran;
-  uint32_t unused[9];
+  uint16_t max_pages;
+  uint16_t padding;
+  uint32_t unused[8];
 };
 #define CUSE_INIT_INFO_MAX 4096
 struct cuse_init_in {
@@ -488,4 +494,13 @@
 struct fuse_lseek_out {
   uint64_t offset;
 };
+struct fuse_copy_file_range_in {
+  uint64_t fh_in;
+  uint64_t off_in;
+  uint64_t nodeid_out;
+  uint64_t fh_out;
+  uint64_t off_out;
+  uint64_t len;
+  uint64_t flags;
+};
 #endif
diff --git a/libc/kernel/uapi/linux/gen_stats.h b/libc/kernel/uapi/linux/gen_stats.h
index 127ae88..0b6c228 100644
--- a/libc/kernel/uapi/linux/gen_stats.h
+++ b/libc/kernel/uapi/linux/gen_stats.h
@@ -27,6 +27,7 @@
   TCA_STATS_APP,
   TCA_STATS_RATE_EST64,
   TCA_STATS_PAD,
+  TCA_STATS_BASIC_HW,
   __TCA_STATS_MAX,
 };
 #define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
diff --git a/libc/kernel/uapi/linux/if_addr.h b/libc/kernel/uapi/linux/if_addr.h
index 0a4b0ae..6a6b640 100644
--- a/libc/kernel/uapi/linux/if_addr.h
+++ b/libc/kernel/uapi/linux/if_addr.h
@@ -38,6 +38,7 @@
   IFA_MULTICAST,
   IFA_FLAGS,
   IFA_RT_PRIORITY,
+  IFA_TARGET_NETNSID,
   __IFA_MAX,
 };
 #define IFA_MAX (__IFA_MAX - 1)
diff --git a/libc/kernel/uapi/linux/if_arp.h b/libc/kernel/uapi/linux/if_arp.h
index 0b1959d..eda888f 100644
--- a/libc/kernel/uapi/linux/if_arp.h
+++ b/libc/kernel/uapi/linux/if_arp.h
@@ -98,7 +98,7 @@
   struct sockaddr arp_ha;
   int arp_flags;
   struct sockaddr arp_netmask;
-  char arp_dev[16];
+  char arp_dev[IFNAMSIZ];
 };
 struct arpreq_old {
   struct sockaddr arp_pa;
diff --git a/libc/kernel/uapi/linux/if_fddi.h b/libc/kernel/uapi/linux/if_fddi.h
index 4efd7f8..4b5074b 100644
--- a/libc/kernel/uapi/linux/if_fddi.h
+++ b/libc/kernel/uapi/linux/if_fddi.h
@@ -29,6 +29,18 @@
 #define FDDI_K_LLC_ZLEN 13
 #define FDDI_K_LLC_LEN 4491
 #define FDDI_K_OUI_LEN 3
+#define FDDI_FC_K_CLASS_MASK 0x80
+#define FDDI_FC_K_CLASS_SYNC 0x80
+#define FDDI_FC_K_CLASS_ASYNC 0x00
+#define FDDI_FC_K_ALEN_MASK 0x40
+#define FDDI_FC_K_ALEN_48 0x40
+#define FDDI_FC_K_ALEN_16 0x00
+#define FDDI_FC_K_FORMAT_MASK 0x30
+#define FDDI_FC_K_FORMAT_FUTURE 0x30
+#define FDDI_FC_K_FORMAT_IMPLEMENTOR 0x20
+#define FDDI_FC_K_FORMAT_LLC 0x10
+#define FDDI_FC_K_FORMAT_MANAGEMENT 0x00
+#define FDDI_FC_K_CONTROL_MASK 0x0f
 #define FDDI_FC_K_VOID 0x00
 #define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80
 #define FDDI_FC_K_RESTRICTED_TOKEN 0xC0
diff --git a/libc/kernel/uapi/linux/if_link.h b/libc/kernel/uapi/linux/if_link.h
index 4bbf21d..2c80d3d 100644
--- a/libc/kernel/uapi/linux/if_link.h
+++ b/libc/kernel/uapi/linux/if_link.h
@@ -138,6 +138,7 @@
   IFLA_EVENT,
   IFLA_NEW_NETNSID,
   IFLA_IF_NETNSID,
+  IFLA_TARGET_NETNSID = IFLA_IF_NETNSID,
   IFLA_CARRIER_UP_COUNT,
   IFLA_CARRIER_DOWN_COUNT,
   IFLA_NEW_IFINDEX,
@@ -219,6 +220,7 @@
   IFLA_BR_MCAST_STATS_ENABLED,
   IFLA_BR_MCAST_IGMP_VERSION,
   IFLA_BR_MCAST_MLD_VERSION,
+  IFLA_BR_VLAN_STATS_PER_PORT,
   __IFLA_BR_MAX,
 };
 #define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
@@ -444,6 +446,7 @@
   IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
   IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
   IFLA_GENEVE_LABEL,
+  IFLA_GENEVE_TTL_INHERIT,
   __IFLA_GENEVE_MAX
 };
 #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
diff --git a/libc/kernel/uapi/linux/if_packet.h b/libc/kernel/uapi/linux/if_packet.h
index 61d0a3a..300aa7b 100644
--- a/libc/kernel/uapi/linux/if_packet.h
+++ b/libc/kernel/uapi/linux/if_packet.h
@@ -63,6 +63,7 @@
 #define PACKET_QDISC_BYPASS 20
 #define PACKET_ROLLOVER_STATS 21
 #define PACKET_FANOUT_DATA 22
+#define PACKET_IGNORE_OUTGOING 23
 #define PACKET_FANOUT_HASH 0
 #define PACKET_FANOUT_LB 1
 #define PACKET_FANOUT_CPU 2
diff --git a/libc/kernel/uapi/linux/if_tunnel.h b/libc/kernel/uapi/linux/if_tunnel.h
index d41dc49..8e1847f 100644
--- a/libc/kernel/uapi/linux/if_tunnel.h
+++ b/libc/kernel/uapi/linux/if_tunnel.h
@@ -154,4 +154,20 @@
   __IFLA_VTI_MAX,
 };
 #define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
+#define TUNNEL_CSUM __cpu_to_be16(0x01)
+#define TUNNEL_ROUTING __cpu_to_be16(0x02)
+#define TUNNEL_KEY __cpu_to_be16(0x04)
+#define TUNNEL_SEQ __cpu_to_be16(0x08)
+#define TUNNEL_STRICT __cpu_to_be16(0x10)
+#define TUNNEL_REC __cpu_to_be16(0x20)
+#define TUNNEL_VERSION __cpu_to_be16(0x40)
+#define TUNNEL_NO_KEY __cpu_to_be16(0x80)
+#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100)
+#define TUNNEL_OAM __cpu_to_be16(0x0200)
+#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400)
+#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800)
+#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000)
+#define TUNNEL_NOCACHE __cpu_to_be16(0x2000)
+#define TUNNEL_ERSPAN_OPT __cpu_to_be16(0x4000)
+#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT)
 #endif
diff --git a/libc/kernel/uapi/linux/in.h b/libc/kernel/uapi/linux/in.h
index 788a6d9..78bd72a 100644
--- a/libc/kernel/uapi/linux/in.h
+++ b/libc/kernel/uapi/linux/in.h
@@ -200,9 +200,12 @@
 #define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
 #define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
 #define IN_MULTICAST(a) IN_CLASSD(a)
-#define IN_MULTICAST_NET 0xF0000000
-#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
-#define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
+#define IN_MULTICAST_NET 0xe0000000
+#define IN_BADCLASS(a) (((long int) (a)) == (long int)0xffffffff)
+#define IN_EXPERIMENTAL(a) IN_BADCLASS((a))
+#define IN_CLASSE(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#define IN_CLASSE_NET 0xffffffff
+#define IN_CLASSE_NSHIFT 0
 #define INADDR_ANY ((unsigned long int) 0x00000000)
 #define INADDR_BROADCAST ((unsigned long int) 0xffffffff)
 #define INADDR_NONE ((unsigned long int) 0xffffffff)
diff --git a/libc/kernel/uapi/linux/in6.h b/libc/kernel/uapi/linux/in6.h
index 9da111c..3627f52 100644
--- a/libc/kernel/uapi/linux/in6.h
+++ b/libc/kernel/uapi/linux/in6.h
@@ -132,6 +132,7 @@
 #define IPV6_V6ONLY 26
 #define IPV6_JOIN_ANYCAST 27
 #define IPV6_LEAVE_ANYCAST 28
+#define IPV6_MULTICAST_ALL 29
 #define IPV6_PMTUDISC_DONT 0
 #define IPV6_PMTUDISC_WANT 1
 #define IPV6_PMTUDISC_DO 2
diff --git a/libc/kernel/uapi/linux/input-event-codes.h b/libc/kernel/uapi/linux/input-event-codes.h
index d8ae4c8..11e6d5b 100644
--- a/libc/kernel/uapi/linux/input-event-codes.h
+++ b/libc/kernel/uapi/linux/input-event-codes.h
@@ -622,6 +622,7 @@
 #define REL_DIAL 0x07
 #define REL_WHEEL 0x08
 #define REL_MISC 0x09
+#define REL_RESERVED 0x0a
 #define REL_MAX 0x0f
 #define REL_CNT (REL_MAX + 1)
 #define ABS_X 0x00
@@ -650,6 +651,7 @@
 #define ABS_TOOL_WIDTH 0x1c
 #define ABS_VOLUME 0x20
 #define ABS_MISC 0x28
+#define ABS_RESERVED 0x2e
 #define ABS_MT_SLOT 0x2f
 #define ABS_MT_TOUCH_MAJOR 0x30
 #define ABS_MT_TOUCH_MINOR 0x31
diff --git a/libc/kernel/uapi/linux/keyctl.h b/libc/kernel/uapi/linux/keyctl.h
index 0cc7f55..53f0468 100644
--- a/libc/kernel/uapi/linux/keyctl.h
+++ b/libc/kernel/uapi/linux/keyctl.h
@@ -60,9 +60,19 @@
 #define KEYCTL_INVALIDATE 21
 #define KEYCTL_GET_PERSISTENT 22
 #define KEYCTL_DH_COMPUTE 23
+#define KEYCTL_PKEY_QUERY 24
+#define KEYCTL_PKEY_ENCRYPT 25
+#define KEYCTL_PKEY_DECRYPT 26
+#define KEYCTL_PKEY_SIGN 27
+#define KEYCTL_PKEY_VERIFY 28
 #define KEYCTL_RESTRICT_KEYRING 29
 struct keyctl_dh_params {
-  __s32 __linux_private;
+  union {
+#ifndef __cplusplus
+    __s32 __linux_private;
+#endif
+    __s32 priv;
+  };
   __s32 prime;
   __s32 base;
 };
@@ -72,4 +82,26 @@
   __u32 otherinfolen;
   __u32 __spare[8];
 };
+#define KEYCTL_SUPPORTS_ENCRYPT 0x01
+#define KEYCTL_SUPPORTS_DECRYPT 0x02
+#define KEYCTL_SUPPORTS_SIGN 0x04
+#define KEYCTL_SUPPORTS_VERIFY 0x08
+struct keyctl_pkey_query {
+  __u32 supported_ops;
+  __u32 key_size;
+  __u16 max_data_size;
+  __u16 max_sig_size;
+  __u16 max_enc_size;
+  __u16 max_dec_size;
+  __u32 __spare[10];
+};
+struct keyctl_pkey_params {
+  __s32 key_id;
+  __u32 in_len;
+  union {
+    __u32 out_len;
+    __u32 in2_len;
+  };
+  __u32 __spare[7];
+};
 #endif
diff --git a/libc/kernel/uapi/linux/kfd_ioctl.h b/libc/kernel/uapi/linux/kfd_ioctl.h
index 55aff04..525f672 100644
--- a/libc/kernel/uapi/linux/kfd_ioctl.h
+++ b/libc/kernel/uapi/linux/kfd_ioctl.h
@@ -64,6 +64,13 @@
   __u32 num_cu_mask;
   __u64 cu_mask_ptr;
 };
+struct kfd_ioctl_get_queue_wave_state_args {
+  __u64 ctl_stack_address;
+  __u32 ctl_stack_used_size;
+  __u32 save_area_used_size;
+  __u32 queue_id;
+  __u32 pad;
+};
 #define KFD_IOC_CACHE_POLICY_COHERENT 0
 #define KFD_IOC_CACHE_POLICY_NONCOHERENT 1
 struct kfd_ioctl_set_memory_policy_args {
@@ -175,10 +182,10 @@
   __u32 pad;
 };
 struct kfd_hsa_hw_exception_data {
-  uint32_t reset_type;
-  uint32_t reset_cause;
-  uint32_t memory_lost;
-  uint32_t gpu_id;
+  __u32 reset_type;
+  __u32 reset_cause;
+  __u32 memory_lost;
+  __u32 gpu_id;
 };
 struct kfd_event_data {
   union {
@@ -285,6 +292,7 @@
 #define AMDKFD_IOC_MAP_MEMORY_TO_GPU AMDKFD_IOWR(0x18, struct kfd_ioctl_map_memory_to_gpu_args)
 #define AMDKFD_IOC_UNMAP_MEMORY_FROM_GPU AMDKFD_IOWR(0x19, struct kfd_ioctl_unmap_memory_from_gpu_args)
 #define AMDKFD_IOC_SET_CU_MASK AMDKFD_IOW(0x1A, struct kfd_ioctl_set_cu_mask_args)
+#define AMDKFD_IOC_GET_QUEUE_WAVE_STATE AMDKFD_IOWR(0x1B, struct kfd_ioctl_get_queue_wave_state_args)
 #define AMDKFD_COMMAND_START 0x01
-#define AMDKFD_COMMAND_END 0x1B
+#define AMDKFD_COMMAND_END 0x1C
 #endif
diff --git a/libc/kernel/uapi/linux/kvm.h b/libc/kernel/uapi/linux/kvm.h
index 14e882b..b70bcd9 100644
--- a/libc/kernel/uapi/linux/kvm.h
+++ b/libc/kernel/uapi/linux/kvm.h
@@ -316,12 +316,18 @@
 struct kvm_coalesced_mmio_zone {
   __u64 addr;
   __u32 size;
-  __u32 pad;
+  union {
+    __u32 pad;
+    __u32 pio;
+  };
 };
 struct kvm_coalesced_mmio {
   __u64 phys_addr;
   __u32 len;
-  __u32 pad;
+  union {
+    __u32 pad;
+    __u32 pio;
+  };
   __u8 data[8];
 };
 struct kvm_coalesced_mmio_ring {
@@ -539,6 +545,7 @@
 };
 #define KVM_PPC_PAGE_SIZES_REAL 0x00000001
 #define KVM_PPC_1T_SEGMENTS 0x00000002
+#define KVM_PPC_NO_HASH 0x00000004
 struct kvm_ppc_smmu_info {
   __u64 flags;
   __u32 slb_size;
@@ -558,6 +565,8 @@
 #define KVM_VM_MIPS_TE 0
 #define KVM_VM_MIPS_VZ 1
 #define KVM_S390_SIE_PAGE_OFFSET 1
+#define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL
+#define KVM_VM_TYPE_ARM_IPA_SIZE(x) ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
 #define KVM_GET_API_VERSION _IO(KVMIO, 0x00)
 #define KVM_CREATE_VM _IO(KVMIO, 0x01)
 #define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list)
@@ -744,6 +753,12 @@
 #define KVM_CAP_NESTED_STATE 157
 #define KVM_CAP_ARM_INJECT_SERROR_ESR 158
 #define KVM_CAP_MSR_PLATFORM_INFO 159
+#define KVM_CAP_PPC_NESTED_HV 160
+#define KVM_CAP_HYPERV_SEND_IPI 161
+#define KVM_CAP_COALESCED_PIO 162
+#define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163
+#define KVM_CAP_EXCEPTION_PAYLOAD 164
+#define KVM_CAP_ARM_VM_IPA_SIZE 165
 #ifdef KVM_CAP_IRQ_ROUTING
 struct kvm_irq_routing_irqchip {
   __u32 irqchip;
diff --git a/libc/kernel/uapi/linux/magic.h b/libc/kernel/uapi/linux/magic.h
index 68b4c65..bf57a58 100644
--- a/libc/kernel/uapi/linux/magic.h
+++ b/libc/kernel/uapi/linux/magic.h
@@ -45,6 +45,7 @@
 #define HPFS_SUPER_MAGIC 0xf995e849
 #define ISOFS_SUPER_MAGIC 0x9660
 #define JFFS2_SUPER_MAGIC 0x72b6
+#define XFS_SUPER_MAGIC 0x58465342
 #define PSTOREFS_MAGIC 0x6165676C
 #define EFIVARFS_MAGIC 0xde5e81e4
 #define HOSTFS_SUPER_MAGIC 0x00c0ffee
diff --git a/libc/kernel/uapi/linux/media.h b/libc/kernel/uapi/linux/media.h
index eefc07a..4ba0ef6 100644
--- a/libc/kernel/uapi/linux/media.h
+++ b/libc/kernel/uapi/linux/media.h
@@ -198,6 +198,9 @@
 #define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum)
 #define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc)
 #define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology)
+#define MEDIA_IOC_REQUEST_ALLOC _IOR('|', 0x05, int)
+#define MEDIA_REQUEST_IOC_QUEUE _IO('|', 0x80)
+#define MEDIA_REQUEST_IOC_REINIT _IO('|', 0x81)
 #define MEDIA_ENT_TYPE_SHIFT 16
 #define MEDIA_ENT_TYPE_MASK 0x00ff0000
 #define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
diff --git a/libc/kernel/uapi/linux/ncsi.h b/libc/kernel/uapi/linux/ncsi.h
index 6b128e4..23cdf1b 100644
--- a/libc/kernel/uapi/linux/ncsi.h
+++ b/libc/kernel/uapi/linux/ncsi.h
@@ -23,6 +23,7 @@
   NCSI_CMD_PKG_INFO,
   NCSI_CMD_SET_INTERFACE,
   NCSI_CMD_CLEAR_INTERFACE,
+  NCSI_CMD_SEND_CMD,
   __NCSI_CMD_AFTER_LAST,
   NCSI_CMD_MAX = __NCSI_CMD_AFTER_LAST - 1
 };
@@ -32,6 +33,7 @@
   NCSI_ATTR_PACKAGE_LIST,
   NCSI_ATTR_PACKAGE_ID,
   NCSI_ATTR_CHANNEL_ID,
+  NCSI_ATTR_DATA,
   __NCSI_ATTR_AFTER_LAST,
   NCSI_ATTR_MAX = __NCSI_ATTR_AFTER_LAST - 1
 };
diff --git a/libc/kernel/uapi/linux/ndctl.h b/libc/kernel/uapi/linux/ndctl.h
index bee0b1c..742fbad 100644
--- a/libc/kernel/uapi/linux/ndctl.h
+++ b/libc/kernel/uapi/linux/ndctl.h
@@ -140,9 +140,6 @@
   ND_DRIVER_NAMESPACE_BLK = 1 << ND_DEVICE_NAMESPACE_BLK,
   ND_DRIVER_DAX_PMEM = 1 << ND_DEVICE_DAX_PMEM,
 };
-enum {
-  ND_MIN_NAMESPACE_SIZE = PAGE_SIZE,
-};
 enum ars_masks {
   ARS_STATUS_MASK = 0x0000FFFF,
   ARS_EXT_STATUS_SHIFT = 16,
diff --git a/libc/kernel/uapi/linux/neighbour.h b/libc/kernel/uapi/linux/neighbour.h
index cf32a12..6329211 100644
--- a/libc/kernel/uapi/linux/neighbour.h
+++ b/libc/kernel/uapi/linux/neighbour.h
@@ -51,6 +51,7 @@
 #define NTF_PROXY 0x08
 #define NTF_EXT_LEARNED 0x10
 #define NTF_OFFLOADED 0x20
+#define NTF_STICKY 0x40
 #define NTF_ROUTER 0x80
 #define NUD_INCOMPLETE 0x01
 #define NUD_REACHABLE 0x02
diff --git a/libc/kernel/uapi/linux/net_tstamp.h b/libc/kernel/uapi/linux/net_tstamp.h
index 2f022ea..375906a 100644
--- a/libc/kernel/uapi/linux/net_tstamp.h
+++ b/libc/kernel/uapi/linux/net_tstamp.h
@@ -80,7 +80,7 @@
   SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) | SOF_TXTIME_FLAGS_LAST
 };
 struct sock_txtime {
-  clockid_t clockid;
+  __kernel_clockid_t clockid;
   __u32 flags;
 };
 #endif
diff --git a/libc/kernel/uapi/linux/netfilter/nf_tables.h b/libc/kernel/uapi/linux/netfilter/nf_tables.h
index 63394e0..2bb7c86 100644
--- a/libc/kernel/uapi/linux/netfilter/nf_tables.h
+++ b/libc/kernel/uapi/linux/netfilter/nf_tables.h
@@ -419,6 +419,7 @@
   NFT_RT_NEXTHOP4,
   NFT_RT_NEXTHOP6,
   NFT_RT_TCPMSS,
+  NFT_RT_XFRM,
   __NFT_RT_MAX
 };
 #define NFT_RT_MAX (__NFT_RT_MAX - 1)
@@ -596,6 +597,13 @@
   __NFTA_QUOTA_MAX
 };
 #define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1)
+enum nft_secmark_attributes {
+  NFTA_SECMARK_UNSPEC,
+  NFTA_SECMARK_CTX,
+  __NFTA_SECMARK_MAX,
+};
+#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1)
+#define NFT_SECMARK_CTX_MAXLEN 256
 enum nft_reject_types {
   NFT_REJECT_ICMP_UNREACH,
   NFT_REJECT_TCP_RST,
@@ -737,7 +745,8 @@
 #define NFT_OBJECT_CONNLIMIT 5
 #define NFT_OBJECT_TUNNEL 6
 #define NFT_OBJECT_CT_TIMEOUT 7
-#define __NFT_OBJECT_MAX 8
+#define NFT_OBJECT_SECMARK 8
+#define __NFT_OBJECT_MAX 9
 #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
 enum nft_object_attributes {
   NFTA_OBJ_UNSPEC,
@@ -773,6 +782,7 @@
 enum nft_osf_attributes {
   NFTA_OSF_UNSPEC,
   NFTA_OSF_DREG,
+  NFTA_OSF_TTL,
   __NFTA_OSF_MAX,
 };
 #define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
@@ -782,6 +792,26 @@
   __NFTA_DEVICE_MAX
 };
 #define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
+enum nft_xfrm_attributes {
+  NFTA_XFRM_UNSPEC,
+  NFTA_XFRM_DREG,
+  NFTA_XFRM_KEY,
+  NFTA_XFRM_DIR,
+  NFTA_XFRM_SPNUM,
+  __NFTA_XFRM_MAX
+};
+#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1)
+enum nft_xfrm_keys {
+  NFT_XFRM_KEY_UNSPEC,
+  NFT_XFRM_KEY_DADDR_IP4,
+  NFT_XFRM_KEY_DADDR_IP6,
+  NFT_XFRM_KEY_SADDR_IP4,
+  NFT_XFRM_KEY_SADDR_IP6,
+  NFT_XFRM_KEY_REQID,
+  NFT_XFRM_KEY_SPI,
+  __NFT_XFRM_KEY_MAX,
+};
+#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1)
 enum nft_trace_attributes {
   NFTA_TRACE_UNSPEC,
   NFTA_TRACE_TABLE,
diff --git a/libc/kernel/uapi/linux/netfilter/xt_cgroup.h b/libc/kernel/uapi/linux/netfilter/xt_cgroup.h
index ccc0349..6d939ea 100644
--- a/libc/kernel/uapi/linux/netfilter/xt_cgroup.h
+++ b/libc/kernel/uapi/linux/netfilter/xt_cgroup.h
@@ -33,4 +33,16 @@
   __u32 classid;
   void * priv __attribute__((aligned(8)));
 };
+#define XT_CGROUP_PATH_MAX 512
+struct xt_cgroup_info_v2 {
+  __u8 has_path;
+  __u8 has_classid;
+  __u8 invert_path;
+  __u8 invert_classid;
+  union {
+    char path[XT_CGROUP_PATH_MAX];
+    __u32 classid;
+  };
+  void * priv __attribute__((aligned(8)));
+};
 #endif
diff --git a/libc/kernel/uapi/linux/netfilter_bridge.h b/libc/kernel/uapi/linux/netfilter_bridge.h
index 6da98f5..e1434f4 100644
--- a/libc/kernel/uapi/linux/netfilter_bridge.h
+++ b/libc/kernel/uapi/linux/netfilter_bridge.h
@@ -23,6 +23,7 @@
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
 #include <linux/if_pppox.h>
+#include <limits.h>
 #define NF_BR_PRE_ROUTING 0
 #define NF_BR_LOCAL_IN 1
 #define NF_BR_FORWARD 2
diff --git a/libc/kernel/uapi/linux/netlink.h b/libc/kernel/uapi/linux/netlink.h
index 4f35c02..4c0fd1f 100644
--- a/libc/kernel/uapi/linux/netlink.h
+++ b/libc/kernel/uapi/linux/netlink.h
@@ -112,6 +112,7 @@
 #define NETLINK_LIST_MEMBERSHIPS 9
 #define NETLINK_CAP_ACK 10
 #define NETLINK_EXT_ACK 11
+#define NETLINK_GET_STRICT_CHK 12
 struct nl_pktinfo {
   __u32 group;
 };
diff --git a/libc/kernel/uapi/linux/nl80211.h b/libc/kernel/uapi/linux/nl80211.h
index 1f2f77d..471e65f 100644
--- a/libc/kernel/uapi/linux/nl80211.h
+++ b/libc/kernel/uapi/linux/nl80211.h
@@ -163,6 +163,7 @@
   NL80211_CMD_EXTERNAL_AUTH,
   NL80211_CMD_STA_OPMODE_CHANGED,
   NL80211_CMD_CONTROL_PORT_FRAME,
+  NL80211_CMD_GET_FTM_RESPONDER_STATS,
   __NL80211_CMD_AFTER_LAST,
   NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
 };
@@ -449,6 +450,8 @@
   NL80211_ATTR_TXQ_MEMORY_LIMIT,
   NL80211_ATTR_TXQ_QUANTUM,
   NL80211_ATTR_HE_CAPABILITY,
+  NL80211_ATTR_FTM_RESPONDER,
+  NL80211_ATTR_FTM_RESPONDER_STATS,
   __NL80211_ATTR_AFTER_LAST,
   NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
   NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
@@ -615,10 +618,13 @@
   NL80211_STA_INFO_RX_DURATION,
   NL80211_STA_INFO_PAD,
   NL80211_STA_INFO_ACK_SIGNAL,
-  NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG,
+  NL80211_STA_INFO_ACK_SIGNAL_AVG,
+  NL80211_STA_INFO_RX_MPDUS,
+  NL80211_STA_INFO_FCS_ERROR_COUNT,
   __NL80211_STA_INFO_AFTER_LAST,
   NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
 };
+#define NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG NL80211_STA_INFO_ACK_SIGNAL_AVG
 enum nl80211_tid_stats {
   __NL80211_TID_STATS_INVALID,
   NL80211_TID_STATS_RX_MSDU,
@@ -1283,10 +1289,13 @@
   NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
   NL80211_EXT_FEATURE_DFS_OFFLOAD,
   NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
-  NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT,
+  NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
+  NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT = NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
   NL80211_EXT_FEATURE_TXQS,
   NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
   NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
+  NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
+  NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
   NUM_NL80211_EXT_FEATURES,
   MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
 };
@@ -1448,4 +1457,27 @@
   NL80211_EXTERNAL_AUTH_START,
   NL80211_EXTERNAL_AUTH_ABORT,
 };
+enum nl80211_ftm_responder_attributes {
+  __NL80211_FTM_RESP_ATTR_INVALID,
+  NL80211_FTM_RESP_ATTR_ENABLED,
+  NL80211_FTM_RESP_ATTR_LCI,
+  NL80211_FTM_RESP_ATTR_CIVICLOC,
+  __NL80211_FTM_RESP_ATTR_LAST,
+  NL80211_FTM_RESP_ATTR_MAX = __NL80211_FTM_RESP_ATTR_LAST - 1,
+};
+enum nl80211_ftm_responder_stats {
+  __NL80211_FTM_STATS_INVALID,
+  NL80211_FTM_STATS_SUCCESS_NUM,
+  NL80211_FTM_STATS_PARTIAL_NUM,
+  NL80211_FTM_STATS_FAILED_NUM,
+  NL80211_FTM_STATS_ASAP_NUM,
+  NL80211_FTM_STATS_NON_ASAP_NUM,
+  NL80211_FTM_STATS_TOTAL_DURATION_MSEC,
+  NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM,
+  NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM,
+  NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM,
+  NL80211_FTM_STATS_PAD,
+  __NL80211_FTM_STATS_AFTER_LAST,
+  NL80211_FTM_STATS_MAX = __NL80211_FTM_STATS_AFTER_LAST - 1
+};
 #endif
diff --git a/libc/kernel/uapi/linux/pci_regs.h b/libc/kernel/uapi/linux/pci_regs.h
index 7b234f5..8122fbb 100644
--- a/libc/kernel/uapi/linux/pci_regs.h
+++ b/libc/kernel/uapi/linux/pci_regs.h
@@ -36,6 +36,7 @@
 #define PCI_COMMAND_FAST_BACK 0x200
 #define PCI_COMMAND_INTX_DISABLE 0x400
 #define PCI_STATUS 0x06
+#define PCI_STATUS_IMM_READY 0x01
 #define PCI_STATUS_INTERRUPT 0x08
 #define PCI_STATUS_CAP_LIST 0x10
 #define PCI_STATUS_66MHZ 0x20
diff --git a/libc/kernel/uapi/linux/perf_event.h b/libc/kernel/uapi/linux/perf_event.h
index c106b5b..bf51785 100644
--- a/libc/kernel/uapi/linux/perf_event.h
+++ b/libc/kernel/uapi/linux/perf_event.h
@@ -286,6 +286,7 @@
 #define PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT (1 << 12)
 #define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
 #define PERF_RECORD_MISC_COMM_EXEC (1 << 13)
+#define PERF_RECORD_MISC_FORK_EXEC (1 << 13)
 #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
 #define PERF_RECORD_MISC_EXACT_IP (1 << 14)
 #define PERF_RECORD_MISC_SWITCH_OUT_PREEMPT (1 << 14)
diff --git a/libc/kernel/uapi/linux/pkt_cls.h b/libc/kernel/uapi/linux/pkt_cls.h
index 1ede892..ac80a0a 100644
--- a/libc/kernel/uapi/linux/pkt_cls.h
+++ b/libc/kernel/uapi/linux/pkt_cls.h
@@ -388,6 +388,7 @@
   TCA_FLOWER_KEY_ENC_IP_TTL_MASK,
   TCA_FLOWER_KEY_ENC_OPTS,
   TCA_FLOWER_KEY_ENC_OPTS_MASK,
+  TCA_FLOWER_IN_HW_COUNT,
   __TCA_FLOWER_MAX,
 };
 #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
diff --git a/libc/kernel/uapi/linux/pkt_sched.h b/libc/kernel/uapi/linux/pkt_sched.h
index 4efbc1c..e7d4942 100644
--- a/libc/kernel/uapi/linux/pkt_sched.h
+++ b/libc/kernel/uapi/linux/pkt_sched.h
@@ -283,8 +283,8 @@
   __u32 lends;
   __u32 borrows;
   __u32 giants;
-  __u32 tokens;
-  __u32 ctokens;
+  __s32 tokens;
+  __s32 ctokens;
 };
 struct tc_hfsc_qopt {
   __u16 defcls;
@@ -828,4 +828,35 @@
   CAKE_ATM_PTM,
   CAKE_ATM_MAX
 };
+enum {
+  TC_TAPRIO_CMD_SET_GATES = 0x00,
+  TC_TAPRIO_CMD_SET_AND_HOLD = 0x01,
+  TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02,
+};
+enum {
+  TCA_TAPRIO_SCHED_ENTRY_UNSPEC,
+  TCA_TAPRIO_SCHED_ENTRY_INDEX,
+  TCA_TAPRIO_SCHED_ENTRY_CMD,
+  TCA_TAPRIO_SCHED_ENTRY_GATE_MASK,
+  TCA_TAPRIO_SCHED_ENTRY_INTERVAL,
+  __TCA_TAPRIO_SCHED_ENTRY_MAX,
+};
+#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1)
+enum {
+  TCA_TAPRIO_SCHED_UNSPEC,
+  TCA_TAPRIO_SCHED_ENTRY,
+  __TCA_TAPRIO_SCHED_MAX,
+};
+#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1)
+enum {
+  TCA_TAPRIO_ATTR_UNSPEC,
+  TCA_TAPRIO_ATTR_PRIOMAP,
+  TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST,
+  TCA_TAPRIO_ATTR_SCHED_BASE_TIME,
+  TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY,
+  TCA_TAPRIO_ATTR_SCHED_CLOCKID,
+  TCA_TAPRIO_PAD,
+  __TCA_TAPRIO_ATTR_MAX,
+};
+#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1)
 #endif
diff --git a/libc/kernel/uapi/linux/prctl.h b/libc/kernel/uapi/linux/prctl.h
index ba50b14..44a088d 100644
--- a/libc/kernel/uapi/linux/prctl.h
+++ b/libc/kernel/uapi/linux/prctl.h
@@ -137,6 +137,7 @@
 #define PR_GET_SPECULATION_CTRL 52
 #define PR_SET_SPECULATION_CTRL 53
 #define PR_SPEC_STORE_BYPASS 0
+#define PR_SPEC_INDIRECT_BRANCH 1
 #define PR_SPEC_NOT_AFFECTED 0
 #define PR_SPEC_PRCTL (1UL << 0)
 #define PR_SPEC_ENABLE (1UL << 1)
diff --git a/libc/kernel/uapi/linux/sctp.h b/libc/kernel/uapi/linux/sctp.h
index 6ba738e..dc07d78 100644
--- a/libc/kernel/uapi/linux/sctp.h
+++ b/libc/kernel/uapi/linux/sctp.h
@@ -314,6 +314,8 @@
 };
 #define SCTP_ASSOC_CHANGE_DENIED 0x0004
 #define SCTP_ASSOC_CHANGE_FAILED 0x0008
+#define SCTP_STREAM_CHANGE_DENIED SCTP_ASSOC_CHANGE_DENIED
+#define SCTP_STREAM_CHANGE_FAILED SCTP_ASSOC_CHANGE_FAILED
 struct sctp_stream_change_event {
   __u16 strchange_type;
   __u16 strchange_flags;
@@ -655,6 +657,7 @@
 };
 enum sctp_sched_type {
   SCTP_SS_FCFS,
+  SCTP_SS_DEFAULT = SCTP_SS_FCFS,
   SCTP_SS_PRIO,
   SCTP_SS_RR,
   SCTP_SS_MAX = SCTP_SS_RR
diff --git a/libc/kernel/uapi/linux/serial.h b/libc/kernel/uapi/linux/serial.h
index 79f11e3..e4e903d 100644
--- a/libc/kernel/uapi/linux/serial.h
+++ b/libc/kernel/uapi/linux/serial.h
@@ -100,4 +100,15 @@
   __u32 delay_rts_after_send;
   __u32 padding[5];
 };
+struct serial_iso7816 {
+  __u32 flags;
+#define SER_ISO7816_ENABLED (1 << 0)
+#define SER_ISO7816_T_PARAM (0x0f << 4)
+#define SER_ISO7816_T(t) (((t) & 0x0f) << 4)
+  __u32 tg;
+  __u32 sc_fi;
+  __u32 sc_di;
+  __u32 clk;
+  __u32 reserved[5];
+};
 #endif
diff --git a/libc/kernel/uapi/linux/taskstats.h b/libc/kernel/uapi/linux/taskstats.h
index b7bc744..dc7791d 100644
--- a/libc/kernel/uapi/linux/taskstats.h
+++ b/libc/kernel/uapi/linux/taskstats.h
@@ -19,7 +19,7 @@
 #ifndef _LINUX_TASKSTATS_H
 #define _LINUX_TASKSTATS_H
 #include <linux/types.h>
-#define TASKSTATS_VERSION 8
+#define TASKSTATS_VERSION 9
 #define TS_COMM_LEN 32
 struct taskstats {
   __u16 version;
@@ -66,6 +66,8 @@
   __u64 cpu_scaled_run_real_total;
   __u64 freepages_count;
   __u64 freepages_delay_total;
+  __u64 thrashing_count;
+  __u64 thrashing_delay_total;
 };
 enum {
   TASKSTATS_CMD_UNSPEC = 0,
diff --git a/libc/kernel/uapi/linux/udmabuf.h b/libc/kernel/uapi/linux/udmabuf.h
new file mode 100644
index 0000000..70cf49f
--- /dev/null
+++ b/libc/kernel/uapi/linux/udmabuf.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_UDMABUF_H
+#define _UAPI_LINUX_UDMABUF_H
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#define UDMABUF_FLAGS_CLOEXEC 0x01
+struct udmabuf_create {
+  __u32 memfd;
+  __u32 flags;
+  __u64 offset;
+  __u64 size;
+};
+struct udmabuf_create_item {
+  __u32 memfd;
+  __u32 __pad;
+  __u64 offset;
+  __u64 size;
+};
+struct udmabuf_create_list {
+  __u32 flags;
+  __u32 count;
+  struct udmabuf_create_item list[];
+};
+#define UDMABUF_CREATE _IOW('u', 0x42, struct udmabuf_create)
+#define UDMABUF_CREATE_LIST _IOW('u', 0x43, struct udmabuf_create_list)
+#endif
diff --git a/libc/kernel/uapi/linux/usb/tmc.h b/libc/kernel/uapi/linux/usb/tmc.h
index 6e276de..20c061b 100644
--- a/libc/kernel/uapi/linux/usb/tmc.h
+++ b/libc/kernel/uapi/linux/usb/tmc.h
@@ -37,10 +37,30 @@
 #define USBTMC488_REQUEST_REN_CONTROL 160
 #define USBTMC488_REQUEST_GOTO_LOCAL 161
 #define USBTMC488_REQUEST_LOCAL_LOCKOUT 162
+struct usbtmc_request {
+  __u8 bRequestType;
+  __u8 bRequest;
+  __u16 wValue;
+  __u16 wIndex;
+  __u16 wLength;
+} __attribute__((packed));
+struct usbtmc_ctrlrequest {
+  struct usbtmc_request req;
+  void __user * data;
+} __attribute__((packed));
 struct usbtmc_termchar {
   __u8 term_char;
   __u8 term_char_enabled;
 } __attribute__((packed));
+#define USBTMC_FLAG_ASYNC 0x0001
+#define USBTMC_FLAG_APPEND 0x0002
+#define USBTMC_FLAG_IGNORE_TRAILER 0x0004
+struct usbtmc_message {
+  __u32 transfer_size;
+  __u32 transferred;
+  __u32 flags;
+  void __user * message;
+} __attribute__((packed));
 #define USBTMC_IOC_NR 91
 #define USBTMC_IOCTL_INDICATOR_PULSE _IO(USBTMC_IOC_NR, 1)
 #define USBTMC_IOCTL_CLEAR _IO(USBTMC_IOC_NR, 2)
@@ -48,16 +68,26 @@
 #define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
 #define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
 #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
+#define USBTMC_IOCTL_CTRL_REQUEST _IOWR(USBTMC_IOC_NR, 8, struct usbtmc_ctrlrequest)
 #define USBTMC_IOCTL_GET_TIMEOUT _IOR(USBTMC_IOC_NR, 9, __u32)
 #define USBTMC_IOCTL_SET_TIMEOUT _IOW(USBTMC_IOC_NR, 10, __u32)
 #define USBTMC_IOCTL_EOM_ENABLE _IOW(USBTMC_IOC_NR, 11, __u8)
 #define USBTMC_IOCTL_CONFIG_TERMCHAR _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar)
+#define USBTMC_IOCTL_WRITE _IOWR(USBTMC_IOC_NR, 13, struct usbtmc_message)
+#define USBTMC_IOCTL_READ _IOWR(USBTMC_IOC_NR, 14, struct usbtmc_message)
+#define USBTMC_IOCTL_WRITE_RESULT _IOWR(USBTMC_IOC_NR, 15, __u32)
+#define USBTMC_IOCTL_API_VERSION _IOR(USBTMC_IOC_NR, 16, __u32)
 #define USBTMC488_IOCTL_GET_CAPS _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
 #define USBTMC488_IOCTL_REN_CONTROL _IOW(USBTMC_IOC_NR, 19, unsigned char)
 #define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21)
 #define USBTMC488_IOCTL_TRIGGER _IO(USBTMC_IOC_NR, 22)
+#define USBTMC488_IOCTL_WAIT_SRQ _IOW(USBTMC_IOC_NR, 23, __u32)
+#define USBTMC_IOCTL_MSG_IN_ATTR _IOR(USBTMC_IOC_NR, 24, __u8)
+#define USBTMC_IOCTL_AUTO_ABORT _IOW(USBTMC_IOC_NR, 25, __u8)
+#define USBTMC_IOCTL_CANCEL_IO _IO(USBTMC_IOC_NR, 35)
+#define USBTMC_IOCTL_CLEANUP_IO _IO(USBTMC_IOC_NR, 36)
 #define USBTMC488_CAPABILITY_TRIGGER 1
 #define USBTMC488_CAPABILITY_SIMPLE 2
 #define USBTMC488_CAPABILITY_REN_CONTROL 2
diff --git a/libc/kernel/uapi/linux/usb/video.h b/libc/kernel/uapi/linux/usb/video.h
index fb34483..cd2ede9 100644
--- a/libc/kernel/uapi/linux/usb/video.h
+++ b/libc/kernel/uapi/linux/usb/video.h
@@ -148,22 +148,22 @@
   __u8 bLength;
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
-  __u16 bcdUVC;
-  __u16 wTotalLength;
-  __u32 dwClockFrequency;
+  __le16 bcdUVC;
+  __le16 wTotalLength;
+  __le32 dwClockFrequency;
   __u8 bInCollection;
   __u8 baInterfaceNr[];
 } __attribute__((__packed__));
 #define UVC_DT_HEADER_SIZE(n) (12 + (n))
 #define UVC_HEADER_DESCRIPTOR(n) uvc_header_descriptor_ ##n
-#define DECLARE_UVC_HEADER_DESCRIPTOR(n) struct UVC_HEADER_DESCRIPTOR(n) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u16 bcdUVC; __u16 wTotalLength; __u32 dwClockFrequency; __u8 bInCollection; __u8 baInterfaceNr[n]; \
+#define DECLARE_UVC_HEADER_DESCRIPTOR(n) struct UVC_HEADER_DESCRIPTOR(n) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __le16 bcdUVC; __le16 wTotalLength; __le32 dwClockFrequency; __u8 bInCollection; __u8 baInterfaceNr[n]; \
 } __attribute__((packed))
 struct uvc_input_terminal_descriptor {
   __u8 bLength;
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
   __u8 bTerminalID;
-  __u16 wTerminalType;
+  __le16 wTerminalType;
   __u8 bAssocTerminal;
   __u8 iTerminal;
 } __attribute__((__packed__));
@@ -173,7 +173,7 @@
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
   __u8 bTerminalID;
-  __u16 wTerminalType;
+  __le16 wTerminalType;
   __u8 bAssocTerminal;
   __u8 bSourceID;
   __u8 iTerminal;
@@ -184,12 +184,12 @@
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
   __u8 bTerminalID;
-  __u16 wTerminalType;
+  __le16 wTerminalType;
   __u8 bAssocTerminal;
   __u8 iTerminal;
-  __u16 wObjectiveFocalLengthMin;
-  __u16 wObjectiveFocalLengthMax;
-  __u16 wOcularFocalLength;
+  __le16 wObjectiveFocalLengthMin;
+  __le16 wObjectiveFocalLengthMax;
+  __le16 wOcularFocalLength;
   __u8 bControlSize;
   __u8 bmControls[3];
 } __attribute__((__packed__));
@@ -213,7 +213,7 @@
   __u8 bDescriptorSubType;
   __u8 bUnitID;
   __u8 bSourceID;
-  __u16 wMaxMultiplier;
+  __le16 wMaxMultiplier;
   __u8 bControlSize;
   __u8 bmControls[2];
   __u8 iProcessing;
@@ -240,7 +240,7 @@
   __u8 bLength;
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
-  __u16 wMaxTransferSize;
+  __le16 wMaxTransferSize;
 } __attribute__((__packed__));
 #define UVC_DT_CONTROL_ENDPOINT_SIZE 5
 struct uvc_input_header_descriptor {
@@ -248,7 +248,7 @@
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
   __u8 bNumFormats;
-  __u16 wTotalLength;
+  __le16 wTotalLength;
   __u8 bEndpointAddress;
   __u8 bmInfo;
   __u8 bTerminalLink;
@@ -260,14 +260,14 @@
 } __attribute__((__packed__));
 #define UVC_DT_INPUT_HEADER_SIZE(n,p) (13 + (n * p))
 #define UVC_INPUT_HEADER_DESCRIPTOR(n,p) uvc_input_header_descriptor_ ##n_ ##p
-#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n,p) struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bNumFormats; __u16 wTotalLength; __u8 bEndpointAddress; __u8 bmInfo; __u8 bTerminalLink; __u8 bStillCaptureMethod; __u8 bTriggerSupport; __u8 bTriggerUsage; __u8 bControlSize; __u8 bmaControls[p][n]; \
+#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n,p) struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bNumFormats; __le16 wTotalLength; __u8 bEndpointAddress; __u8 bmInfo; __u8 bTerminalLink; __u8 bStillCaptureMethod; __u8 bTriggerSupport; __u8 bTriggerUsage; __u8 bControlSize; __u8 bmaControls[p][n]; \
 } __attribute__((packed))
 struct uvc_output_header_descriptor {
   __u8 bLength;
   __u8 bDescriptorType;
   __u8 bDescriptorSubType;
   __u8 bNumFormats;
-  __u16 wTotalLength;
+  __le16 wTotalLength;
   __u8 bEndpointAddress;
   __u8 bTerminalLink;
   __u8 bControlSize;
@@ -275,7 +275,7 @@
 } __attribute__((__packed__));
 #define UVC_DT_OUTPUT_HEADER_SIZE(n,p) (9 + (n * p))
 #define UVC_OUTPUT_HEADER_DESCRIPTOR(n,p) uvc_output_header_descriptor_ ##n_ ##p
-#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n,p) struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bNumFormats; __u16 wTotalLength; __u8 bEndpointAddress; __u8 bTerminalLink; __u8 bControlSize; __u8 bmaControls[p][n]; \
+#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n,p) struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bNumFormats; __le16 wTotalLength; __u8 bEndpointAddress; __u8 bTerminalLink; __u8 bControlSize; __u8 bmaControls[p][n]; \
 } __attribute__((packed))
 struct uvc_color_matching_descriptor {
   __u8 bLength;
@@ -325,18 +325,18 @@
   __u8 bDescriptorSubType;
   __u8 bFrameIndex;
   __u8 bmCapabilities;
-  __u16 wWidth;
-  __u16 wHeight;
-  __u32 dwMinBitRate;
-  __u32 dwMaxBitRate;
-  __u32 dwMaxVideoFrameBufferSize;
-  __u32 dwDefaultFrameInterval;
+  __le16 wWidth;
+  __le16 wHeight;
+  __le32 dwMinBitRate;
+  __le32 dwMaxBitRate;
+  __le32 dwMaxVideoFrameBufferSize;
+  __le32 dwDefaultFrameInterval;
   __u8 bFrameIntervalType;
-  __u32 dwFrameInterval[];
+  __le32 dwFrameInterval[];
 } __attribute__((__packed__));
 #define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26 + 4 * (n))
 #define UVC_FRAME_UNCOMPRESSED(n) uvc_frame_uncompressed_ ##n
-#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) struct UVC_FRAME_UNCOMPRESSED(n) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bFrameIndex; __u8 bmCapabilities; __u16 wWidth; __u16 wHeight; __u32 dwMinBitRate; __u32 dwMaxBitRate; __u32 dwMaxVideoFrameBufferSize; __u32 dwDefaultFrameInterval; __u8 bFrameIntervalType; __u32 dwFrameInterval[n]; \
+#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) struct UVC_FRAME_UNCOMPRESSED(n) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bFrameIndex; __u8 bmCapabilities; __le16 wWidth; __le16 wHeight; __le32 dwMinBitRate; __le32 dwMaxBitRate; __le32 dwMaxVideoFrameBufferSize; __le32 dwDefaultFrameInterval; __u8 bFrameIntervalType; __le32 dwFrameInterval[n]; \
 } __attribute__((packed))
 struct uvc_format_mjpeg {
   __u8 bLength;
@@ -358,17 +358,17 @@
   __u8 bDescriptorSubType;
   __u8 bFrameIndex;
   __u8 bmCapabilities;
-  __u16 wWidth;
-  __u16 wHeight;
-  __u32 dwMinBitRate;
-  __u32 dwMaxBitRate;
-  __u32 dwMaxVideoFrameBufferSize;
-  __u32 dwDefaultFrameInterval;
+  __le16 wWidth;
+  __le16 wHeight;
+  __le32 dwMinBitRate;
+  __le32 dwMaxBitRate;
+  __le32 dwMaxVideoFrameBufferSize;
+  __le32 dwDefaultFrameInterval;
   __u8 bFrameIntervalType;
-  __u32 dwFrameInterval[];
+  __le32 dwFrameInterval[];
 } __attribute__((__packed__));
 #define UVC_DT_FRAME_MJPEG_SIZE(n) (26 + 4 * (n))
 #define UVC_FRAME_MJPEG(n) uvc_frame_mjpeg_ ##n
-#define DECLARE_UVC_FRAME_MJPEG(n) struct UVC_FRAME_MJPEG(n) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bFrameIndex; __u8 bmCapabilities; __u16 wWidth; __u16 wHeight; __u32 dwMinBitRate; __u32 dwMaxBitRate; __u32 dwMaxVideoFrameBufferSize; __u32 dwDefaultFrameInterval; __u8 bFrameIntervalType; __u32 dwFrameInterval[n]; \
+#define DECLARE_UVC_FRAME_MJPEG(n) struct UVC_FRAME_MJPEG(n) { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubType; __u8 bFrameIndex; __u8 bmCapabilities; __le16 wWidth; __le16 wHeight; __le32 dwMinBitRate; __le32 dwMaxBitRate; __le32 dwMaxVideoFrameBufferSize; __le32 dwDefaultFrameInterval; __u8 bFrameIntervalType; __le32 dwFrameInterval[n]; \
 } __attribute__((packed))
 #endif
diff --git a/libc/kernel/uapi/linux/v4l2-controls.h b/libc/kernel/uapi/linux/v4l2-controls.h
index 45590a2..3c2d2b2 100644
--- a/libc/kernel/uapi/linux/v4l2-controls.h
+++ b/libc/kernel/uapi/linux/v4l2-controls.h
@@ -18,6 +18,7 @@
  ****************************************************************************/
 #ifndef __LINUX_V4L2_CONTROLS_H
 #define __LINUX_V4L2_CONTROLS_H
+#include <linux/types.h>
 #define V4L2_CTRL_CLASS_USER 0x00980000
 #define V4L2_CTRL_CLASS_MPEG 0x00990000
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000
diff --git a/libc/kernel/uapi/linux/version.h b/libc/kernel/uapi/linux/version.h
index a234744..6b1ef1b 100644
--- a/libc/kernel/uapi/linux/version.h
+++ b/libc/kernel/uapi/linux/version.h
@@ -16,5 +16,5 @@
  ***
  ****************************************************************************
  ****************************************************************************/
-#define LINUX_VERSION_CODE 267008
+#define LINUX_VERSION_CODE 267265
 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
diff --git a/libc/kernel/uapi/linux/vfio.h b/libc/kernel/uapi/linux/vfio.h
index 8b397f4..d282a52 100644
--- a/libc/kernel/uapi/linux/vfio.h
+++ b/libc/kernel/uapi/linux/vfio.h
@@ -57,6 +57,7 @@
 #define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2)
 #define VFIO_DEVICE_FLAGS_AMBA (1 << 3)
 #define VFIO_DEVICE_FLAGS_CCW (1 << 4)
+#define VFIO_DEVICE_FLAGS_AP (1 << 5)
   __u32 num_regions;
   __u32 num_irqs;
 };
@@ -65,6 +66,7 @@
 #define VFIO_DEVICE_API_PLATFORM_STRING "vfio-platform"
 #define VFIO_DEVICE_API_AMBA_STRING "vfio-amba"
 #define VFIO_DEVICE_API_CCW_STRING "vfio-ccw"
+#define VFIO_DEVICE_API_AP_STRING "vfio-ap"
 struct vfio_region_info {
   __u32 argsz;
   __u32 flags;
@@ -100,6 +102,18 @@
 #define VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION (1)
 #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2)
 #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3)
+#define VFIO_REGION_TYPE_GFX (1)
+#define VFIO_REGION_SUBTYPE_GFX_EDID (1)
+struct vfio_region_gfx_edid {
+  __u32 edid_offset;
+  __u32 edid_max_size;
+  __u32 edid_size;
+  __u32 max_xres;
+  __u32 max_yres;
+  __u32 link_state;
+#define VFIO_DEVICE_GFX_LINK_STATE_UP 1
+#define VFIO_DEVICE_GFX_LINK_STATE_DOWN 2
+};
 #define VFIO_REGION_INFO_CAP_MSIX_MAPPABLE 3
 struct vfio_irq_info {
   __u32 argsz;
diff --git a/libc/kernel/uapi/linux/videodev2.h b/libc/kernel/uapi/linux/videodev2.h
index 51faa1e..ef89b08 100644
--- a/libc/kernel/uapi/linux/videodev2.h
+++ b/libc/kernel/uapi/linux/videodev2.h
@@ -86,7 +86,7 @@
   V4L2_COLORSPACE_470_SYSTEM_BG = 6,
   V4L2_COLORSPACE_JPEG = 7,
   V4L2_COLORSPACE_SRGB = 8,
-  V4L2_COLORSPACE_ADOBERGB = 9,
+  V4L2_COLORSPACE_OPRGB = 9,
   V4L2_COLORSPACE_BT2020 = 10,
   V4L2_COLORSPACE_RAW = 11,
   V4L2_COLORSPACE_DCI_P3 = 12,
@@ -96,13 +96,13 @@
   V4L2_XFER_FUNC_DEFAULT = 0,
   V4L2_XFER_FUNC_709 = 1,
   V4L2_XFER_FUNC_SRGB = 2,
-  V4L2_XFER_FUNC_ADOBERGB = 3,
+  V4L2_XFER_FUNC_OPRGB = 3,
   V4L2_XFER_FUNC_SMPTE240M = 4,
   V4L2_XFER_FUNC_NONE = 5,
   V4L2_XFER_FUNC_DCI_P3 = 6,
   V4L2_XFER_FUNC_SMPTE2084 = 7,
 };
-#define V4L2_MAP_XFER_FUNC_DEFAULT(colsp) ((colsp) == V4L2_COLORSPACE_ADOBERGB ? V4L2_XFER_FUNC_ADOBERGB : ((colsp) == V4L2_COLORSPACE_SMPTE240M ? V4L2_XFER_FUNC_SMPTE240M : ((colsp) == V4L2_COLORSPACE_DCI_P3 ? V4L2_XFER_FUNC_DCI_P3 : ((colsp) == V4L2_COLORSPACE_RAW ? V4L2_XFER_FUNC_NONE : ((colsp) == V4L2_COLORSPACE_SRGB || (colsp) == V4L2_COLORSPACE_JPEG ? V4L2_XFER_FUNC_SRGB : V4L2_XFER_FUNC_709)))))
+#define V4L2_MAP_XFER_FUNC_DEFAULT(colsp) ((colsp) == V4L2_COLORSPACE_OPRGB ? V4L2_XFER_FUNC_OPRGB : ((colsp) == V4L2_COLORSPACE_SMPTE240M ? V4L2_XFER_FUNC_SMPTE240M : ((colsp) == V4L2_COLORSPACE_DCI_P3 ? V4L2_XFER_FUNC_DCI_P3 : ((colsp) == V4L2_COLORSPACE_RAW ? V4L2_XFER_FUNC_NONE : ((colsp) == V4L2_COLORSPACE_SRGB || (colsp) == V4L2_COLORSPACE_JPEG ? V4L2_XFER_FUNC_SRGB : V4L2_XFER_FUNC_709)))))
 enum v4l2_ycbcr_encoding {
   V4L2_YCBCR_ENC_DEFAULT = 0,
   V4L2_YCBCR_ENC_601 = 1,
@@ -125,6 +125,8 @@
   V4L2_QUANTIZATION_LIM_RANGE = 2,
 };
 #define V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb_or_hsv,colsp,ycbcr_enc) (((is_rgb_or_hsv) && (colsp) == V4L2_COLORSPACE_BT2020) ? V4L2_QUANTIZATION_LIM_RANGE : (((is_rgb_or_hsv) || (colsp) == V4L2_COLORSPACE_JPEG) ? V4L2_QUANTIZATION_FULL_RANGE : V4L2_QUANTIZATION_LIM_RANGE))
+#define V4L2_COLORSPACE_ADOBERGB V4L2_COLORSPACE_OPRGB
+#define V4L2_XFER_FUNC_ADOBERGB V4L2_XFER_FUNC_OPRGB
 enum v4l2_priority {
   V4L2_PRIORITY_UNSET = 0,
   V4L2_PRIORITY_BACKGROUND = 1,
@@ -313,6 +315,7 @@
 #define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3')
 #define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1')
 #define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2')
+#define V4L2_PIX_FMT_MPEG2_SLICE v4l2_fourcc('M', 'G', '2', 'S')
 #define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4')
 #define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D')
 #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G')
@@ -352,6 +355,7 @@
 #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ')
 #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1')
 #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I')
+#define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2')
 #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b')
 #define V4L2_PIX_FMT_IPU3_SGBRG10 v4l2_fourcc('i', 'p', '3', 'g')
 #define V4L2_PIX_FMT_IPU3_SGRBG10 v4l2_fourcc('i', 'p', '3', 'G')
@@ -371,6 +375,7 @@
 #define V4L2_META_FMT_VSP1_HGO v4l2_fourcc('V', 'S', 'P', 'H')
 #define V4L2_META_FMT_VSP1_HGT v4l2_fourcc('V', 'S', 'P', 'T')
 #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H')
+#define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X')
 #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe
 #define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA 0x00000001
 struct v4l2_fmtdesc {
@@ -469,8 +474,13 @@
   __u32 count;
   __u32 type;
   __u32 memory;
-  __u32 reserved[2];
+  __u32 capabilities;
+  __u32 reserved[1];
 };
+#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0)
+#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1)
+#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2)
+#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3)
 struct v4l2_plane {
   __u32 bytesused;
   __u32 length;
@@ -500,7 +510,10 @@
   } m;
   __u32 length;
   __u32 reserved2;
-  __u32 reserved;
+  union {
+    __s32 request_fd;
+    __u32 reserved;
+  };
 };
 #define V4L2_BUF_FLAG_MAPPED 0x00000001
 #define V4L2_BUF_FLAG_QUEUED 0x00000002
@@ -509,6 +522,7 @@
 #define V4L2_BUF_FLAG_PFRAME 0x00000010
 #define V4L2_BUF_FLAG_BFRAME 0x00000020
 #define V4L2_BUF_FLAG_ERROR 0x00000040
+#define V4L2_BUF_FLAG_IN_REQUEST 0x00000080
 #define V4L2_BUF_FLAG_TIMECODE 0x00000100
 #define V4L2_BUF_FLAG_PREPARED 0x00000400
 #define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x00000800
@@ -521,6 +535,7 @@
 #define V4L2_BUF_FLAG_TSTAMP_SRC_EOF 0x00000000
 #define V4L2_BUF_FLAG_TSTAMP_SRC_SOE 0x00010000
 #define V4L2_BUF_FLAG_LAST 0x00100000
+#define V4L2_BUF_FLAG_REQUEST_FD 0x00800000
 struct v4l2_exportbuffer {
   __u32 type;
   __u32 index;
@@ -702,6 +717,7 @@
 #define V4L2_DV_FL_HAS_PICTURE_ASPECT (1 << 6)
 #define V4L2_DV_FL_HAS_CEA861_VIC (1 << 7)
 #define V4L2_DV_FL_HAS_HDMI_VIC (1 << 8)
+#define V4L2_DV_FL_CAN_DETECT_REDUCED_FPS (1 << 9)
 #define V4L2_DV_BT_BLANKING_WIDTH(bt) ((bt)->hfrontporch + (bt)->hsync + (bt)->hbackporch)
 #define V4L2_DV_BT_FRAME_WIDTH(bt) ((bt)->width + V4L2_DV_BT_BLANKING_WIDTH(bt))
 #define V4L2_DV_BT_BLANKING_HEIGHT(bt) ((bt)->vfrontporch + (bt)->vsync + (bt)->vbackporch + (bt)->il_vfrontporch + (bt)->il_vsync + (bt)->il_vbackporch)
@@ -819,7 +835,8 @@
   };
   __u32 count;
   __u32 error_idx;
-  __u32 reserved[2];
+  __s32 request_fd;
+  __u32 reserved[1];
   struct v4l2_ext_control * controls;
 };
 #define V4L2_CTRL_ID_MASK (0x0fffffff)
@@ -829,6 +846,7 @@
 #define V4L2_CTRL_MAX_DIMS (4)
 #define V4L2_CTRL_WHICH_CUR_VAL 0
 #define V4L2_CTRL_WHICH_DEF_VAL 0x0f000000
+#define V4L2_CTRL_WHICH_REQUEST_VAL 0x0f010000
 enum v4l2_ctrl_type {
   V4L2_CTRL_TYPE_INTEGER = 1,
   V4L2_CTRL_TYPE_BOOLEAN = 2,
@@ -1274,7 +1292,8 @@
   __u32 count;
   __u32 memory;
   struct v4l2_format format;
-  __u32 reserved[8];
+  __u32 capabilities;
+  __u32 reserved[7];
 };
 #define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)
 #define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc)
diff --git a/libc/kernel/uapi/linux/virtio_balloon.h b/libc/kernel/uapi/linux/virtio_balloon.h
index 5969fa0..806e757 100644
--- a/libc/kernel/uapi/linux/virtio_balloon.h
+++ b/libc/kernel/uapi/linux/virtio_balloon.h
@@ -25,10 +25,16 @@
 #define VIRTIO_BALLOON_F_MUST_TELL_HOST 0
 #define VIRTIO_BALLOON_F_STATS_VQ 1
 #define VIRTIO_BALLOON_F_DEFLATE_ON_OOM 2
+#define VIRTIO_BALLOON_F_FREE_PAGE_HINT 3
+#define VIRTIO_BALLOON_F_PAGE_POISON 4
 #define VIRTIO_BALLOON_PFN_SHIFT 12
+#define VIRTIO_BALLOON_CMD_ID_STOP 0
+#define VIRTIO_BALLOON_CMD_ID_DONE 1
 struct virtio_balloon_config {
   __u32 num_pages;
   __u32 actual;
+  __u32 free_page_report_cmd_id;
+  __u32 poison_val;
 };
 #define VIRTIO_BALLOON_S_SWAP_IN 0
 #define VIRTIO_BALLOON_S_SWAP_OUT 1
diff --git a/libc/kernel/uapi/rdma/ib_user_verbs.h b/libc/kernel/uapi/rdma/ib_user_verbs.h
index 3baf4ed..6ca4413 100644
--- a/libc/kernel/uapi/rdma/ib_user_verbs.h
+++ b/libc/kernel/uapi/rdma/ib_user_verbs.h
@@ -619,6 +619,22 @@
   __u32 length;
   __u32 lkey;
 };
+enum ib_uverbs_wr_opcode {
+  IB_UVERBS_WR_RDMA_WRITE = 0,
+  IB_UVERBS_WR_RDMA_WRITE_WITH_IMM = 1,
+  IB_UVERBS_WR_SEND = 2,
+  IB_UVERBS_WR_SEND_WITH_IMM = 3,
+  IB_UVERBS_WR_RDMA_READ = 4,
+  IB_UVERBS_WR_ATOMIC_CMP_AND_SWP = 5,
+  IB_UVERBS_WR_ATOMIC_FETCH_AND_ADD = 6,
+  IB_UVERBS_WR_LOCAL_INV = 7,
+  IB_UVERBS_WR_BIND_MW = 8,
+  IB_UVERBS_WR_SEND_WITH_INV = 9,
+  IB_UVERBS_WR_TSO = 10,
+  IB_UVERBS_WR_RDMA_READ_WITH_INV = 11,
+  IB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP = 12,
+  IB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13,
+};
 struct ib_uverbs_send_wr {
   __aligned_u64 wr_id;
   __u32 num_sge;
diff --git a/libc/kernel/uapi/rdma/mlx5-abi.h b/libc/kernel/uapi/rdma/mlx5-abi.h
index 50ecd2f..77e14f6 100644
--- a/libc/kernel/uapi/rdma/mlx5-abi.h
+++ b/libc/kernel/uapi/rdma/mlx5-abi.h
@@ -28,6 +28,9 @@
   MLX5_QP_FLAG_BFREG_INDEX = 1 << 3,
   MLX5_QP_FLAG_TYPE_DCT = 1 << 4,
   MLX5_QP_FLAG_TYPE_DCI = 1 << 5,
+  MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_UC = 1 << 6,
+  MLX5_QP_FLAG_TIR_ALLOW_SELF_LB_MC = 1 << 7,
+  MLX5_QP_FLAG_ALLOW_SCATTER_CQE = 1 << 8,
 };
 enum {
   MLX5_SRQ_FLAG_SIGNATURE = 1 << 0,
@@ -252,9 +255,21 @@
   __u32 comp_mask;
   __u32 flags;
 };
+enum mlx5_ib_create_qp_resp_mask {
+  MLX5_IB_CREATE_QP_RESP_MASK_TIRN = 1UL << 0,
+  MLX5_IB_CREATE_QP_RESP_MASK_TISN = 1UL << 1,
+  MLX5_IB_CREATE_QP_RESP_MASK_RQN = 1UL << 2,
+  MLX5_IB_CREATE_QP_RESP_MASK_SQN = 1UL << 3,
+};
 struct mlx5_ib_create_qp_resp {
   __u32 bfreg_index;
   __u32 reserved;
+  __u32 comp_mask;
+  __u32 tirn;
+  __u32 tisn;
+  __u32 rqn;
+  __u32 sqn;
+  __u32 reserved1;
 };
 struct mlx5_ib_alloc_mw {
   __u32 comp_mask;
diff --git a/libc/kernel/uapi/rdma/mlx5_user_ioctl_cmds.h b/libc/kernel/uapi/rdma/mlx5_user_ioctl_cmds.h
index 11ff576..902816b 100644
--- a/libc/kernel/uapi/rdma/mlx5_user_ioctl_cmds.h
+++ b/libc/kernel/uapi/rdma/mlx5_user_ioctl_cmds.h
@@ -93,6 +93,7 @@
   MLX5_IB_ATTR_FLOW_MATCHER_MATCH_MASK,
   MLX5_IB_ATTR_FLOW_MATCHER_FLOW_TYPE,
   MLX5_IB_ATTR_FLOW_MATCHER_MATCH_CRITERIA,
+  MLX5_IB_ATTR_FLOW_MATCHER_FLOW_FLAGS,
 };
 enum mlx5_ib_flow_matcher_destroy_attrs {
   MLX5_IB_ATTR_FLOW_MATCHER_DESTROY_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
@@ -117,6 +118,8 @@
   MLX5_IB_ATTR_CREATE_FLOW_DEST_QP,
   MLX5_IB_ATTR_CREATE_FLOW_DEST_DEVX,
   MLX5_IB_ATTR_CREATE_FLOW_MATCHER,
+  MLX5_IB_ATTR_CREATE_FLOW_ARR_FLOW_ACTIONS,
+  MLX5_IB_ATTR_CREATE_FLOW_TAG,
 };
 enum mlx5_ib_destoy_flow_attrs {
   MLX5_IB_ATTR_DESTROY_FLOW_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
@@ -125,4 +128,19 @@
   MLX5_IB_METHOD_CREATE_FLOW = (1U << UVERBS_ID_NS_SHIFT),
   MLX5_IB_METHOD_DESTROY_FLOW,
 };
+enum mlx5_ib_flow_action_methods {
+  MLX5_IB_METHOD_FLOW_ACTION_CREATE_MODIFY_HEADER = (1U << UVERBS_ID_NS_SHIFT),
+  MLX5_IB_METHOD_FLOW_ACTION_CREATE_PACKET_REFORMAT,
+};
+enum mlx5_ib_create_flow_action_create_modify_header_attrs {
+  MLX5_IB_ATTR_CREATE_MODIFY_HEADER_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
+  MLX5_IB_ATTR_CREATE_MODIFY_HEADER_ACTIONS_PRM,
+  MLX5_IB_ATTR_CREATE_MODIFY_HEADER_FT_TYPE,
+};
+enum mlx5_ib_create_flow_action_create_packet_reformat_attrs {
+  MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
+  MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_TYPE,
+  MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_FT_TYPE,
+  MLX5_IB_ATTR_CREATE_PACKET_REFORMAT_DATA_BUF,
+};
 #endif
diff --git a/libc/kernel/uapi/rdma/mlx5_user_ioctl_verbs.h b/libc/kernel/uapi/rdma/mlx5_user_ioctl_verbs.h
index c9a83cf..dc246e5 100644
--- a/libc/kernel/uapi/rdma/mlx5_user_ioctl_verbs.h
+++ b/libc/kernel/uapi/rdma/mlx5_user_ioctl_verbs.h
@@ -22,4 +22,14 @@
 enum mlx5_ib_uapi_flow_action_flags {
   MLX5_IB_UAPI_FLOW_ACTION_FLAGS_REQUIRE_METADATA = 1 << 0,
 };
+enum mlx5_ib_uapi_flow_table_type {
+  MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_RX = 0x0,
+  MLX5_IB_UAPI_FLOW_TABLE_TYPE_NIC_TX = 0x1,
+};
+enum mlx5_ib_uapi_flow_action_packet_reformat_type {
+  MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 = 0x0,
+  MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL = 0x1,
+  MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 = 0x2,
+  MLX5_IB_UAPI_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL = 0x3,
+};
 #endif
diff --git a/libc/kernel/uapi/rdma/rdma_netlink.h b/libc/kernel/uapi/rdma/rdma_netlink.h
index 48cbc3d..69805f1 100644
--- a/libc/kernel/uapi/rdma/rdma_netlink.h
+++ b/libc/kernel/uapi/rdma/rdma_netlink.h
@@ -173,6 +173,7 @@
 enum rdma_nldev_command {
   RDMA_NLDEV_CMD_UNSPEC,
   RDMA_NLDEV_CMD_GET,
+  RDMA_NLDEV_CMD_SET,
   RDMA_NLDEV_CMD_PORT_GET = 5,
   RDMA_NLDEV_CMD_RES_GET = 9,
   RDMA_NLDEV_CMD_RES_QP_GET,
diff --git a/libc/kernel/uapi/scsi/scsi_bsg_ufs.h b/libc/kernel/uapi/scsi/scsi_bsg_ufs.h
new file mode 100644
index 0000000..177cae9
--- /dev/null
+++ b/libc/kernel/uapi/scsi/scsi_bsg_ufs.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef SCSI_BSG_UFS_H
+#define SCSI_BSG_UFS_H
+#include <linux/types.h>
+#define UFS_CDB_SIZE 16
+#define UPIU_TRANSACTION_UIC_CMD 0x1F
+#define UIC_CMD_SIZE (sizeof(__u32) * 4)
+struct utp_upiu_header {
+  __be32 dword_0;
+  __be32 dword_1;
+  __be32 dword_2;
+};
+struct utp_upiu_query {
+  __u8 opcode;
+  __u8 idn;
+  __u8 index;
+  __u8 selector;
+  __be16 reserved_osf;
+  __be16 length;
+  __be32 value;
+  __be32 reserved[2];
+};
+struct utp_upiu_cmd {
+  __be32 exp_data_transfer_len;
+  __u8 cdb[UFS_CDB_SIZE];
+};
+struct utp_upiu_req {
+  struct utp_upiu_header header;
+  union {
+    struct utp_upiu_cmd sc;
+    struct utp_upiu_query qr;
+    struct utp_upiu_query tr;
+    struct utp_upiu_query uc;
+  };
+};
+struct ufs_bsg_request {
+  __u32 msgcode;
+  struct utp_upiu_req upiu_req;
+};
+struct ufs_bsg_reply {
+  __u32 result;
+  __u32 reply_payload_rcv_len;
+  struct utp_upiu_req upiu_rsp;
+};
+#endif
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 9dfdbc0..c27f884 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1481,14 +1481,6 @@
 
     # Used by libandroid_runtime
     gMallocLeakZygoteChild; # apex
-
-    # TODO(b/120266448) hide these symbols again
-    # Used by libndk_translation
-    __getdents64; # arm x86 mips apex
-    tkill; # arm x86 mips apex
-    # Used by PtsBionicDeviceTestCases
-    __bionic_brk; # arm x86 mips apex
-    __system_property_add; # apex
 } LIBC_P;
 
 LIBC_PRIVATE {
@@ -1565,6 +1557,7 @@
     __arm_fadvise64_64; # arm
     __ashldi3; # arm
     __ashrdi3; # arm
+    __bionic_brk; # arm x86 mips
     __bionic_libgcc_compat_symbols; # arm x86
     __cmpdf2; # arm
     __divdf3; # arm
@@ -1590,6 +1583,7 @@
     __gedf2; # arm
     __get_thread; # arm x86 mips
     __get_tls; # arm x86 mips
+    __getdents64; # arm x86 mips
     __gnu_ldivmod_helper; # arm
     __gnu_uldivmod_helper; # arm
     __gnu_Unwind_Backtrace; # arm
@@ -1697,6 +1691,7 @@
     strntoumax; # arm x86 mips
     strtotimeval; # arm x86 mips
     sysv_signal; # arm x86 mips
+    tkill; # arm x86 mips
     wait3; # arm x86 mips
     wcswcs; # arm x86 mips
 } LIBC_Q;
@@ -1708,6 +1703,7 @@
 
 LIBC_PLATFORM {
   global:
+    __system_property_add;
     __system_property_area__; # var
     __system_property_area_init;
     __system_property_set_filename;
diff --git a/libc/malloc_debug/Config.cpp b/libc/malloc_debug/Config.cpp
index 926b265..dd20b5c 100644
--- a/libc/malloc_debug/Config.cpp
+++ b/libc/malloc_debug/Config.cpp
@@ -132,6 +132,9 @@
     {
         "verify_pointers", {TRACK_ALLOCS, &Config::VerifyValueEmpty},
     },
+    {
+        "abort_on_error", {ABORT_ON_ERROR, &Config::VerifyValueEmpty},
+    },
 };
 
 bool Config::ParseValue(const std::string& option, const std::string& value, size_t min_value,
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 86d1ee4..011dc77 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -44,6 +44,7 @@
 constexpr uint64_t LEAK_TRACK = 0x100;
 constexpr uint64_t RECORD_ALLOCS = 0x200;
 constexpr uint64_t BACKTRACE_FULL = 0x400;
+constexpr uint64_t ABORT_ON_ERROR = 0x800;
 
 // In order to guarantee posix compliance, set the minimum alignment
 // to 8 bytes for 32 bit systems and 16 bytes for 64 bit systems.
diff --git a/libc/malloc_debug/GuardData.cpp b/libc/malloc_debug/GuardData.cpp
index debc14e..c307dc9 100644
--- a/libc/malloc_debug/GuardData.cpp
+++ b/libc/malloc_debug/GuardData.cpp
@@ -64,6 +64,9 @@
   error_log("Backtrace at time of failure:");
   BacktraceAndLog();
   error_log(LOG_DIVIDER);
+  if (g_debug->config().options() & ABORT_ON_ERROR) {
+    abort();
+  }
 }
 
 FrontGuardData::FrontGuardData(DebugData* debug_data, const Config& config, size_t* offset)
diff --git a/libc/malloc_debug/PointerData.cpp b/libc/malloc_debug/PointerData.cpp
index b0e2fc8..638061b 100644
--- a/libc/malloc_debug/PointerData.cpp
+++ b/libc/malloc_debug/PointerData.cpp
@@ -206,7 +206,7 @@
     std::lock_guard<std::mutex> pointer_guard(pointer_mutex_);
     auto entry = pointers_.find(pointer);
     if (entry == pointers_.end()) {
-      // Error.
+      // Attempt to remove unknown pointer.
       error_log("No tracked pointer found for 0x%" PRIxPTR, pointer);
       return;
     }
@@ -283,6 +283,9 @@
   }
 
   error_log(LOG_DIVIDER);
+  if (g_debug->config().options() & ABORT_ON_ERROR) {
+    abort();
+  }
 }
 
 void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
@@ -295,6 +298,9 @@
       error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE",
                 info.pointer, header->tag);
       error_log(LOG_DIVIDER);
+      if (g_debug->config().options() & ABORT_ON_ERROR) {
+        abort();
+      }
 
       // Stop processing here, it is impossible to tell how the header
       // may have been damaged.
diff --git a/libc/malloc_debug/README.md b/libc/malloc_debug/README.md
index a8289b3..93b9b1e 100644
--- a/libc/malloc_debug/README.md
+++ b/libc/malloc_debug/README.md
@@ -394,6 +394,13 @@
 
 **NOTE**: This option is not available until the P release of Android.
 
+### abort\_on\_error
+When malloc debug detects an error, abort after sending the error
+log message.
+
+**NOTE**: If leak\_track is enabled, no abort occurs if leaks have been
+detected when the process is exiting.
+
 Additional Errors
 -----------------
 There are a few other error messages that might appear in the log.
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 9075a9c..2e6afff 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -154,6 +154,9 @@
   error_log("Backtrace at time of failure:");
   BacktraceAndLog();
   error_log(LOG_DIVIDER);
+  if (g_debug->config().options() & ABORT_ON_ERROR) {
+    abort();
+  }
 }
 
 static bool VerifyPointer(const void* pointer, const char* function_name) {
diff --git a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
index a083b4f..fb54ee5 100644
--- a/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_config_tests.cpp
@@ -725,3 +725,21 @@
       "value must be <= 50000000: 100000000\n");
   ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugConfigTest, abort_on_error) {
+  ASSERT_TRUE(InitConfig("abort_on_error")) << getFakeLogPrint();
+  ASSERT_EQ(ABORT_ON_ERROR, config->options());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(MallocDebugConfigTest, trigger_abort_fail) {
+  ASSERT_FALSE(InitConfig("abort_on_error=200")) << getFakeLogPrint();
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  std::string log_msg(
+      "6 malloc_debug malloc_testing: value set for option 'abort_on_error' "
+      "which does not take a value\n");
+  ASSERT_STREQ((log_msg + usage_string).c_str(), getFakeLogPrint().c_str());
+}
diff --git a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
index 2d6346f..44f9795 100644
--- a/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
+++ b/libc/malloc_debug/tests/malloc_debug_unit_tests.cpp
@@ -2380,3 +2380,59 @@
   expected_log += DIVIDER;
   ASSERT_STREQ(expected_log.c_str(), getFakeLogPrint().c_str());
 }
+
+TEST_F(MallocDebugTest, abort_on_error_log_error) {
+  Init("abort_on_error verify_pointers");
+
+  void* pointer = debug_malloc(10);
+  memset(pointer, 0, 10);
+  debug_free(pointer);
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+
+  EXPECT_DEATH(debug_free(pointer), "");
+}
+
+TEST_F(MallocDebugTest, abort_on_error_guard_corrupted) {
+  Init("abort_on_error front_guard=32");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  pointer[-16] = 0x00;
+  EXPECT_DEATH(debug_free(pointer), "");
+  pointer[-16] = 0xaa;
+  debug_free(pointer);
+}
+
+TEST_F(MallocDebugTest, abort_on_error_use_after_free) {
+  Init("abort_on_error free_track=100 free_track_backtrace_num_frames=0");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 100);
+  debug_free(pointer);
+
+  pointer[56] = 0x91;
+
+  EXPECT_DEATH(debug_finalize(), "");
+
+  pointer[56] = 0xef;
+}
+
+TEST_F(MallocDebugTest, abort_on_error_header_tag_corrupted) {
+  Init("abort_on_error free_track=100 free_track_backtrace_num_frames=0 rear_guard");
+
+  uint8_t* pointer = reinterpret_cast<uint8_t*>(debug_malloc(100));
+  ASSERT_TRUE(pointer != nullptr);
+  memset(pointer, 0, 100);
+  debug_free(pointer);
+
+  uint8_t tag_value = pointer[-get_tag_offset()];
+  pointer[-get_tag_offset()] = 0x00;
+
+  EXPECT_DEATH(debug_finalize(), "");
+
+  pointer[-get_tag_offset()] = tag_value;
+}
+
diff --git a/libc/private/ScopedRWLock.h b/libc/private/ScopedRWLock.h
new file mode 100644
index 0000000..f034505
--- /dev/null
+++ b/libc/private/ScopedRWLock.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <pthread.h>
+
+#include "private/bionic_macros.h"
+
+template <bool write> class ScopedRWLock {
+ public:
+  explicit ScopedRWLock(pthread_rwlock_t* rwlock) : rwlock_(rwlock) {
+    (write ? pthread_rwlock_wrlock : pthread_rwlock_rdlock)(rwlock_);
+  }
+
+  ~ScopedRWLock() {
+    pthread_rwlock_unlock(rwlock_);
+  }
+
+ private:
+  pthread_rwlock_t* rwlock_;
+  BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedRWLock);
+};
+
+typedef ScopedRWLock<true> ScopedWriteLock;
+typedef ScopedRWLock<false> ScopedReadLock;
diff --git a/libc/private/bionic_asm_tls.h b/libc/private/bionic_asm_tls.h
index 06e3dce..0f0873f 100644
--- a/libc/private/bionic_asm_tls.h
+++ b/libc/private/bionic_asm_tls.h
@@ -87,11 +87,9 @@
 #define TLS_SLOT_STACK_GUARD      5
 #define TLS_SLOT_SANITIZER        6 // was historically used for dlerror
 #define TLS_SLOT_ART_THREAD_SELF  7
-#define TLS_SLOT_TSAN             8 // should be replaced with TLS_SLOT_SANITIZER
 
 // The maximum slot is fixed by the minimum TLS alignment in Bionic executables.
-// It should be changed to 7 once TLS_SLOT_TSAN is removed.
-#define MAX_TLS_SLOT              8
+#define MAX_TLS_SLOT              7
 
 #elif defined(__i386__) || defined(__x86_64__)
 
@@ -109,10 +107,9 @@
 #define TLS_SLOT_STACK_GUARD      5
 #define TLS_SLOT_SANITIZER        6 // was historically used for dlerror
 #define TLS_SLOT_ART_THREAD_SELF  7
-#define TLS_SLOT_TSAN             8 // should be replaced with TLS_SLOT_SANITIZER
-#define TLS_SLOT_DTV              9
-#define TLS_SLOT_BIONIC_TLS       10
-#define MAX_TLS_SLOT              10 // update this value when reserving a slot
+#define TLS_SLOT_DTV              8
+#define TLS_SLOT_BIONIC_TLS       9
+#define MAX_TLS_SLOT              9 // update this value when reserving a slot
 
 #endif
 
diff --git a/libc/private/bionic_elf_tls.h b/libc/private/bionic_elf_tls.h
index e847669..09e1958 100644
--- a/libc/private/bionic_elf_tls.h
+++ b/libc/private/bionic_elf_tls.h
@@ -28,7 +28,23 @@
 
 #pragma once
 
+#include <link.h>
+#include <pthread.h>
+#include <stdatomic.h>
 #include <stdint.h>
+#include <sys/cdefs.h>
+
+struct TlsSegment {
+  size_t size = 0;
+  size_t alignment = 1;
+  const void* init_ptr = "";    // Field is non-null even when init_size is 0.
+  size_t init_size = 0;
+};
+
+__LIBC_HIDDEN__ bool __bionic_get_tls_segment(const ElfW(Phdr)* phdr_table, size_t phdr_count,
+                                              ElfW(Addr) load_bias, TlsSegment* out);
+
+__LIBC_HIDDEN__ bool __bionic_check_tls_alignment(size_t* alignment);
 
 struct StaticTlsLayout {
   constexpr StaticTlsLayout() {}
@@ -45,13 +61,17 @@
 public:
   size_t offset_bionic_tcb() const { return offset_bionic_tcb_; }
   size_t offset_bionic_tls() const { return offset_bionic_tls_; }
+  size_t offset_thread_pointer() const;
 
   size_t size() const { return offset_; }
   size_t alignment() const { return alignment_; }
   bool overflowed() const { return overflowed_; }
 
-  void reserve_tcb();
+  size_t reserve_exe_segment_and_tcb(const TlsSegment* exe_segment, const char* progname);
   void reserve_bionic_tls();
+  size_t reserve_solib_segment(const TlsSegment& segment) {
+    return reserve(segment.size, segment.alignment);
+  }
   void finish_layout();
 
 private:
@@ -63,3 +83,39 @@
 
   size_t round_up_with_overflow_check(size_t value, size_t alignment);
 };
+
+// A descriptor for a single ELF TLS module.
+struct TlsModule {
+  TlsSegment segment;
+
+  // Offset into the static TLS block or SIZE_MAX for a dynamic module.
+  size_t static_offset = SIZE_MAX;
+
+  // The generation in which this module was loaded. Dynamic TLS lookups use
+  // this field to detect when a module has been unloaded.
+  size_t first_generation = 0;
+
+  // Used by the dynamic linker to track the associated soinfo* object.
+  void* soinfo_ptr = nullptr;
+};
+
+// Table of the ELF TLS modules. Either the dynamic linker or the static
+// initialization code prepares this table, and it's then used during thread
+// creation and for dynamic TLS lookups.
+struct TlsModules {
+  constexpr TlsModules() {}
+
+  // A generation counter. The value is incremented each time an solib is loaded
+  // or unloaded.
+  _Atomic(size_t) generation = 0;
+
+  // Access to the TlsModule[] table requires taking this lock.
+  pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
+
+  // Pointer to a block of TlsModule objects. The first module has ID 1 and
+  // is stored at index 0 in this table.
+  size_t module_count = 0;
+  TlsModule* module_table = nullptr;
+};
+
+void __init_static_tls(void* static_tls);
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index b5e677e..4d40476 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -69,6 +69,7 @@
   abort_msg_t* abort_msg = nullptr;
 
   StaticTlsLayout static_tls_layout;
+  TlsModules tls_modules;
 
   // Values passed from the linker to libc.so.
   const char* init_progname = nullptr;
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/symbol_ordering b/libc/symbol_ordering
new file mode 100644
index 0000000..5b365f0
--- /dev/null
+++ b/libc/symbol_ordering
@@ -0,0 +1,210 @@
+# This file is generated by sorting symbols in the .bss section in libc.so by
+# their sizes and taking out symbols that are unique to a target.  By sorting
+# symbols by size, we usually have less dirty pages at runtime, because small
+# symbols are grouped together.
+
+je_background_thread_enabled_state
+je_can_enable_background_thread
+_ZZ17__find_icu_symbolPKcE9found_icu
+_ZL28g_heapprofd_init_in_progress
+_ZL31g_heapprofd_init_hook_installed
+je_opt_abort
+je_opt_abort_conf
+je_opt_junk_alloc
+je_opt_junk_free
+je_opt_utrace
+je_opt_xmalloc
+je_opt_zero
+malloc_disabled_tcache
+had_conf_error
+malloc_slow_flags
+je_opt_background_thread
+background_thread_enabled_at_fork
+ctl_initialized
+je_log_init_done
+mmap_flags
+os_overcommits
+je_opt_stats_print
+je_tsd_booted
+global_hashtable_initialized
+gmtcheck.gmt_is_set
+restartloop
+_ZZ12bindresvportE4port
+ru_counter
+ru_a
+ru_x
+ru_b
+ru_seed
+ru_g
+ru_seed2
+ru_msb
+je_narenas_auto
+je_ncpus
+je_init_system_thp_mode
+je_nhbins
+je_tsd_tsd
+optreset
+_rs_forked
+daylight
+_ZL17g_icudata_version
+gMallocLeakZygoteChild
+_ZL18netdClientInitOnce
+je_opt_narenas
+narenas_total
+je_malloc_disable.once_control
+je_opt_metadata_thp
+je_opt_thp
+stack_nelms
+tcaches_past
+ncleanups
+error_message_count
+error_one_per_line
+_ZZ13error_at_lineE9last_line
+_ZL13g_locale_once
+_ZL30g_propservice_protocol_version
+_res_cache_once
+_res_key
+_rs_forkdetect._rs_pid
+ru_pid
+lcl_is_set
+__cxa_finalize.call_depth
+seed48.sseed
+ether_aton.addr
+je_background_thread_info
+je_max_background_threads
+je_n_background_threads
+je_malloc_message
+je_tcache_bin_info
+je_tcache_maxclass
+je_tcaches
+optarg
+suboptarg
+timezone
+_ZGVZ17__find_icu_symbolPKcE9found_icu
+_ZL17g_libicuuc_handle
+__malloc_hook
+__realloc_hook
+__free_hook
+__memalign_hook
+_ZL21g_heapprofd_init_func
+je_malloc_conf
+malloc_initializer
+a0
+je_opt_dirty_decay_ms
+je_opt_muzzy_decay_ms
+dirty_decay_ms_default.0
+muzzy_decay_ms_default.0
+pthread_create_fptr
+b0
+ctl_arenas
+ctl_stats
+je_hooks_arena_new_hook
+os_page
+tcaches_avail
+_ZN9prop_area8pa_size_E
+_ZN9prop_area13pa_data_size_E
+_ZL6g_lock
+_ZL6g_tags
+_ZZ8c16rtombE15__private_state
+_ZZ8c32rtombE15__private_state
+environ
+error_print_progname
+_ZZ13error_at_lineE9last_file
+_ZZ14__icu_charTypejE10u_charType
+_ZGVZ14__icu_charTypejE10u_charType
+_ZZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZGVZ25__icu_getIntPropertyValuej9UPropertyE21u_getIntPropertyValue
+_ZZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+_ZGVZ23__icu_hasBinaryPropertyj9UPropertyPFiiEE19u_hasBinaryProperty
+__progname
+_ZZ8mbrtoc16E15__private_state
+_ZZ8mbrtoc32E15__private_state
+_ZL14syslog_log_tag
+__system_property_area__
+_ZZ7mbrtowcE15__private_state
+_ZZ10mbsnrtowcsE15__private_state
+_ZZ7wcrtombE15__private_state
+_ZZ10wcsnrtombsE15__private_state
+_ZZ8iswcntrlE10u_charType
+_ZGVZ8iswcntrlE10u_charType
+_ZZ8iswdigitE9u_isdigit
+_ZGVZ8iswdigitE9u_isdigit
+_ZZ8iswpunctE9u_ispunct
+_ZGVZ8iswpunctE9u_ispunct
+_ZZ8towlowerE9u_tolower
+_ZGVZ8towlowerE9u_tolower
+_ZZ8towupperE9u_toupper
+_ZGVZ8towupperE9u_toupper
+global_hashtable
+handlers
+p5s
+ut
+rs
+rsx
+mbrlen.mbs
+mbtowc.mbs
+wctomb.mbs
+ru_reseed
+ru_prf
+tmpnam.tmpcount
+lastenv
+strtok.last
+__stack_chk_guard
+lclptr
+gmtptr
+_ZGVZ14tzset_unlockedE20persist_sys_timezone
+_ZL13g_thread_list
+__atexit
+je_opt_stats_print_opts
+nuls
+precsize_ntoa.retbuf
+__p_secstodate.output
+_ZL13g_atfork_list
+inet_ntoa.b
+ether_ntoa.buf
+__sym_ntos.unname
+__sym_ntop.unname
+__p_type.typebuf
+__p_class.classbuf
+malloc_disabled_lock
+_ZL11g_arc4_lock
+_res_cache_list_lock
+__p_option.nbuf
+__p_time.nbuf
+atexit_mutex
+random_mutex
+__res_randomid.__libc_mutex_random
+locallock
+g_atexit_lock
+_ZL11g_functions
+_ZL13vendor_passwd
+_ZL12vendor_group
+tm
+_ZL18g_thread_list_lock
+buf_asctime
+__dtoa_locks
+freelist
+__loc_ntoa.tmpbuf
+_ZL8g_locale
+je_arenas_lock
+je_background_thread_lock
+init_lock
+ctl_mtx
+tcaches_mtx
+je_tsd_init_head
+_ZZ14tzset_unlockedE20persist_sys_timezone
+arena_binind_div_info
+__hexdig_D2A
+lcl_TZname
+utmp
+inet_nsap_ntoa_tmpbuf
+_ZL17system_properties
+_ZL7key_map
+private_mem
+__libc_globals
+tmpnam.buf
+_res_cache_list
+_nres
+je_extent_mutex_pool
+je_arenas
+je_extents_rtree
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()
diff --git a/linker/Android.bp b/linker/Android.bp
index 38a53f8..e103ade 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -176,6 +176,11 @@
         "-Wextra",
         "-Wunused",
         "-Werror",
+
+        // Define _USING_LIBCXX so <stdatomic.h> defers to the <atomic> header. When a Soong module
+        // uses the platform libc++, Soong automatically passes this macro, but the dynamic linker
+        // links against libc++ manually.
+        "-D_USING_LIBCXX",
     ],
 
     // TODO: split out the asflags.
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 1f259e1..412b8eb 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -65,8 +65,10 @@
 #include "linker_phdr.h"
 #include "linker_relocs.h"
 #include "linker_reloc_iterators.h"
+#include "linker_tls.h"
 #include "linker_utils.h"
 
+#include "private/bionic_globals.h"
 #include "android-base/macros.h"
 #include "android-base/strings.h"
 #include "android-base/stringprintf.h"
@@ -601,6 +603,9 @@
   }
 
   void set_fd(int fd, bool assume_ownership) {
+    if (fd_ != -1 && close_fd_) {
+      close(fd_);
+    }
     fd_ = fd;
     close_fd_ = assume_ownership;
   }
@@ -1652,6 +1657,7 @@
     if (!si->is_linked() && !si->prelink_image()) {
       return false;
     }
+    register_soinfo_tls(si);
   }
 
   // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is
@@ -1887,6 +1893,7 @@
            si->get_realpath(),
            si);
     notify_gdb_of_unload(si);
+    unregister_soinfo_tls(si);
     get_cfi_shadow()->BeforeUnload(si);
     soinfo_free(si);
   }
@@ -2666,16 +2673,32 @@
 #else
 static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
   if (ELFW(R_TYPE)(rel->r_info) == R_GENERIC_RELATIVE ||
-      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE) {
+      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_IRELATIVE ||
+      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_TLS_DTPREL ||
+      ELFW(R_TYPE)(rel->r_info) == R_GENERIC_TLS_TPREL) {
     return *reinterpret_cast<ElfW(Addr)*>(reloc_addr);
   }
   return 0;
 }
 #endif
 
+static bool is_tls_reloc(ElfW(Word) type) {
+  switch (type) {
+    case R_GENERIC_TLS_DTPMOD:
+    case R_GENERIC_TLS_DTPREL:
+    case R_GENERIC_TLS_TPREL:
+    case R_GENERIC_TLSDESC:
+      return true;
+    default:
+      return false;
+  }
+}
+
 template<typename ElfRelIteratorT>
 bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
                       const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
+  const size_t tls_tp_base = __libc_shared_globals()->static_tls_layout.offset_thread_pointer();
+
   for (size_t idx = 0; rel_iterator.has_next(); ++idx) {
     const auto rel = rel_iterator.next();
     if (rel == nullptr) {
@@ -2698,7 +2721,22 @@
     const ElfW(Sym)* s = nullptr;
     soinfo* lsi = nullptr;
 
-    if (sym != 0) {
+    if (sym == 0) {
+      // Do nothing.
+    } else if (ELF_ST_BIND(symtab_[sym].st_info) == STB_LOCAL && is_tls_reloc(type)) {
+      // In certain situations, the Gold linker accesses a TLS symbol using a
+      // relocation to an STB_LOCAL symbol in .dynsym of either STT_SECTION or
+      // STT_TLS type. Bionic doesn't support these relocations, so issue an
+      // error. References:
+      //  - https://groups.google.com/d/topic/generic-abi/dJ4_Y78aQ2M/discussion
+      //  - https://sourceware.org/bugzilla/show_bug.cgi?id=17699
+      s = &symtab_[sym];
+      sym_name = get_string(s->st_name);
+      DL_ERR("unexpected TLS reference to local symbol \"%s\": "
+             "sym type %d, rel type %u (idx %zu of \"%s\")",
+             sym_name, ELF_ST_TYPE(s->st_info), type, idx, get_realpath());
+      return false;
+    } else {
       sym_name = get_string(symtab_[sym].st_name);
       const version_info* vi = nullptr;
 
@@ -2735,6 +2773,10 @@
           case R_GENERIC_GLOB_DAT:
           case R_GENERIC_RELATIVE:
           case R_GENERIC_IRELATIVE:
+          case R_GENERIC_TLS_DTPMOD:
+          case R_GENERIC_TLS_DTPREL:
+          case R_GENERIC_TLS_TPREL:
+          case R_GENERIC_TLSDESC:
 #if defined(__aarch64__)
           case R_AARCH64_ABS64:
           case R_AARCH64_ABS32:
@@ -2782,12 +2824,21 @@
           }
         }
 #endif
-        if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
-          DL_ERR("unsupported ELF TLS symbol \"%s\" referenced by \"%s\"",
-                 sym_name, get_realpath());
-          return false;
+        if (is_tls_reloc(type)) {
+          if (ELF_ST_TYPE(s->st_info) != STT_TLS) {
+            DL_ERR("reference to non-TLS symbol \"%s\" from TLS relocation in \"%s\"",
+                   sym_name, get_realpath());
+            return false;
+          }
+          sym_addr = s->st_value;
+        } else {
+          if (ELF_ST_TYPE(s->st_info) == STT_TLS) {
+            DL_ERR("reference to TLS symbol \"%s\" from non-TLS relocation in \"%s\"",
+                   sym_name, get_realpath());
+            return false;
+          }
+          sym_addr = lsi->resolve_symbol_address(s);
         }
-        sym_addr = lsi->resolve_symbol_address(s);
 #if !defined(__LP64__)
         if (protect_segments) {
           if (phdr_table_unprotect_segments(phdr, phnum, load_bias) < 0) {
@@ -2860,6 +2911,40 @@
           *reinterpret_cast<ElfW(Addr)*>(reloc) = ifunc_addr;
         }
         break;
+      case R_GENERIC_TLS_TPREL:
+        count_relocation(kRelocRelative);
+        MARK(rel->r_offset);
+        {
+          ElfW(Addr) tpoff = 0;
+          if (sym == 0) {
+            // By convention in ld.bfd and lld, an omitted symbol
+            // (ELFW(R_SYM) == 0) refers to the local module.
+            lsi = this;
+          }
+          if (lsi == nullptr) {
+            // Unresolved weak relocation. Leave tpoff at 0 to resolve
+            // &weak_tls_symbol to __get_tls().
+          } else if (soinfo_tls* lsi_tls = lsi->get_tls()) {
+            const TlsModule& mod = get_tls_module(lsi_tls->module_id);
+            if (mod.static_offset != SIZE_MAX) {
+              tpoff += mod.static_offset - tls_tp_base;
+            } else {
+              DL_ERR("TLS symbol \"%s\" in dlopened \"%s\" referenced from \"%s\" using IE access model",
+                     sym_name, lsi->get_realpath(), get_realpath());
+              return false;
+            }
+          } else {
+            DL_ERR("TLS relocation refers to symbol \"%s\" in solib \"%s\" with no TLS segment",
+                   sym_name, lsi->get_realpath());
+            return false;
+          }
+          tpoff += sym_addr + addend;
+          TRACE_TYPE(RELO, "RELO TLS_TPREL %16p <- %16p %s\n",
+                     reinterpret_cast<void*>(reloc),
+                     reinterpret_cast<void*>(tpoff), sym_name);
+          *reinterpret_cast<ElfW(Addr)*>(reloc) = tpoff;
+        }
+        break;
 
 #if defined(__aarch64__)
       case R_AARCH64_ABS64:
@@ -2961,14 +3046,6 @@
          */
         DL_ERR("%s R_AARCH64_COPY relocations are not supported", get_realpath());
         return false;
-      case R_AARCH64_TLS_TPREL64:
-        TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
-                   reloc, (sym_addr + addend), rel->r_offset);
-        break;
-      case R_AARCH64_TLSDESC:
-        TRACE_TYPE(RELO, "RELO TLSDESC *** %16llx <- %16llx - %16llx\n",
-                   reloc, (sym_addr + addend), rel->r_offset);
-        break;
 #elif defined(__x86_64__)
       case R_X86_64_32:
         count_relocation(kRelocRelative);
@@ -3073,6 +3150,19 @@
                                   &ARM_exidx, &ARM_exidx_count);
 #endif
 
+  TlsSegment tls_segment;
+  if (__bionic_get_tls_segment(phdr, phnum, load_bias, &tls_segment)) {
+    if (!__bionic_check_tls_alignment(&tls_segment.alignment)) {
+      if (!relocating_linker) {
+        DL_ERR("TLS segment alignment in \"%s\" is not a power of 2: %zu",
+               get_realpath(), tls_segment.alignment);
+      }
+      return false;
+    }
+    tls_ = std::make_unique<soinfo_tls>();
+    tls_->segment = tls_segment;
+  }
+
   // Extract useful information from dynamic section.
   // Note that: "Except for the DT_NULL element at the end of the array,
   // and the relative order of DT_NEEDED elements, entries may appear in any order."
diff --git a/linker/linker_logger.cpp b/linker/linker_logger.cpp
index d0e5072..ec07a55 100644
--- a/linker/linker_logger.cpp
+++ b/linker/linker_logger.cpp
@@ -118,11 +118,7 @@
   flags_ |= ParseProperty(debug_ld_app);
 }
 
-void LinkerLogger::Log(uint32_t type, const char* format, ...) {
-  if ((flags_ & type) == 0) {
-    return;
-  }
-
+void LinkerLogger::Log(const char* format, ...) {
   va_list ap;
   va_start(ap, format);
   async_safe_format_log_va_list(ANDROID_LOG_DEBUG, "linker", format, ap);
diff --git a/linker/linker_logger.h b/linker/linker_logger.h
index 1828799..f9fc38e 100644
--- a/linker/linker_logger.h
+++ b/linker/linker_logger.h
@@ -35,10 +35,10 @@
 
 #include <android-base/macros.h>
 
-#define LD_LOG(type, x...) \
-  { \
-    g_linker_logger.Log(type, x); \
-  }
+#define LD_LOG(type, x...)                                       \
+  do {                                                           \
+    if (g_linker_logger.IsEnabled(type)) g_linker_logger.Log(x); \
+  } while (0)
 
 constexpr const uint32_t kLogErrors = 1 << 0;
 constexpr const uint32_t kLogDlopen = 1 << 1;
@@ -49,7 +49,12 @@
   LinkerLogger() : flags_(0) { }
 
   void ResetState();
-  void Log(uint32_t type, const char* format, ...);
+  void Log(const char* format, ...);
+
+  uint32_t IsEnabled(uint32_t type) {
+    return flags_ & type;
+  }
+
  private:
   uint32_t flags_;
 
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 9b4ce47..b0c27dc 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -415,6 +415,8 @@
     }
   }
 
+  linker_setup_exe_static_tls(g_argv[0]);
+
   // Load ld_preloads and dependencies.
   std::vector<const char*> needed_library_name_list;
   size_t ld_preloads_count = 0;
@@ -452,8 +454,7 @@
     si->increment_ref_count();
   }
 
-  layout_linker_static_tls();
-
+  linker_finalize_static_tls();
   __libc_init_main_thread_final();
 
   if (!get_cfi_shadow()->InitialLinkDone(solist)) __linker_cannot_link(g_argv[0]);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 93079ca..dcc6bf3 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -628,6 +628,10 @@
   return secondary_namespaces_;
 }
 
+soinfo_tls* soinfo::get_tls() const {
+  return has_min_version(5) ? tls_.get() : nullptr;
+}
+
 ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
   if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
     return call_ifunc_resolver(s->st_value + load_bias);
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 44bff28..14571de 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -30,8 +30,10 @@
 
 #include <link.h>
 
+#include <memory>
 #include <string>
 
+#include "private/bionic_elf_tls.h"
 #include "linker_namespaces.h"
 
 #define FLAG_LINKED           0x00000001
@@ -61,7 +63,7 @@
                                          // unset.
 #define FLAG_NEW_SOINFO       0x40000000 // new soinfo format
 
-#define SOINFO_VERSION 4
+#define SOINFO_VERSION 5
 
 typedef void (*linker_dtor_function_t)();
 typedef void (*linker_ctor_function_t)(int, char**, char**);
@@ -100,6 +102,16 @@
 // TODO(dimitry): remove reference from soinfo member functions to this class.
 class VersionTracker;
 
+// The first ELF TLS module has ID 1. Zero is reserved for the first word of
+// the DTV, a generation count, and unresolved weak symbols also use module
+// ID 0.
+static constexpr size_t kUninitializedModuleId = 0;
+
+struct soinfo_tls {
+  TlsSegment segment;
+  size_t module_id = kUninitializedModuleId;
+};
+
 #if defined(__work_around_b_24465209__)
 #define SOINFO_NAME_LEN 128
 #endif
@@ -284,6 +296,8 @@
   void add_secondary_namespace(android_namespace_t* secondary_ns);
   android_namespace_list_t& get_secondary_namespaces();
 
+  soinfo_tls* get_tls() const;
+
   void set_mapped_by_caller(bool reserved_map);
   bool is_mapped_by_caller() const;
 
@@ -366,6 +380,9 @@
   // version >= 4
   ElfW(Relr)* relr_;
   size_t relr_count_;
+
+  // version >= 5
+  std::unique_ptr<soinfo_tls> tls_;
 };
 
 // This function is used by dlvsym() to calculate hash of sym_ver
diff --git a/linker/linker_tls.cpp b/linker/linker_tls.cpp
index 3327453..0d1796b 100644
--- a/linker/linker_tls.cpp
+++ b/linker/linker_tls.cpp
@@ -28,20 +28,83 @@
 
 #include "linker_tls.h"
 
+#include <vector>
+
+#include "private/ScopedRWLock.h"
 #include "private/bionic_defs.h"
 #include "private/bionic_elf_tls.h"
 #include "private/bionic_globals.h"
 #include "private/linker_native_bridge.h"
+#include "linker_main.h"
+#include "linker_soinfo.h"
+
+static bool g_static_tls_finished;
+static std::vector<TlsModule> g_tls_modules;
+
+static inline size_t module_id_to_idx(size_t id) { return id - 1; }
+static inline size_t module_idx_to_id(size_t idx) { return idx + 1; }
+
+static size_t get_unused_module_index() {
+  for (size_t i = 0; i < g_tls_modules.size(); ++i) {
+    if (g_tls_modules[i].soinfo_ptr == nullptr) {
+      return i;
+    }
+  }
+  g_tls_modules.push_back({});
+  __libc_shared_globals()->tls_modules.module_count = g_tls_modules.size();
+  __libc_shared_globals()->tls_modules.module_table = g_tls_modules.data();
+  return g_tls_modules.size() - 1;
+}
+
+static void register_tls_module(soinfo* si, size_t static_offset) {
+  // The global TLS module table points at the std::vector of modules declared
+  // in this file, so acquire a write lock before modifying the std::vector.
+  ScopedWriteLock locker(&__libc_shared_globals()->tls_modules.rwlock);
+
+  size_t module_idx = get_unused_module_index();
+
+  soinfo_tls* si_tls = si->get_tls();
+  si_tls->module_id = module_idx_to_id(module_idx);
+
+  g_tls_modules[module_idx] = {
+    .segment = si_tls->segment,
+    .static_offset = static_offset,
+    .first_generation = ++__libc_shared_globals()->tls_modules.generation,
+    .soinfo_ptr = si,
+  };
+}
+
+static void unregister_tls_module(soinfo* si) {
+  ScopedWriteLock locker(&__libc_shared_globals()->tls_modules.rwlock);
+
+  soinfo_tls* si_tls = si->get_tls();
+  TlsModule& mod = g_tls_modules[module_id_to_idx(si_tls->module_id)];
+  CHECK(mod.static_offset == SIZE_MAX);
+  CHECK(mod.soinfo_ptr == si);
+  mod = {};
+  si_tls->module_id = kUninitializedModuleId;
+}
+
+// The reference is valid until a TLS module is registered or unregistered.
+const TlsModule& get_tls_module(size_t module_id) {
+  size_t module_idx = module_id_to_idx(module_id);
+  CHECK(module_idx < g_tls_modules.size());
+  return g_tls_modules[module_idx];
+}
 
 __BIONIC_WEAK_FOR_NATIVE_BRIDGE
 extern "C" void __linker_reserve_bionic_tls_in_static_tls() {
   __libc_shared_globals()->static_tls_layout.reserve_bionic_tls();
 }
 
-// Stub for linker static TLS layout.
-void layout_linker_static_tls() {
+void linker_setup_exe_static_tls(const char* progname) {
+  soinfo* somain = solist_get_somain();
   StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
-  layout.reserve_tcb();
+  if (somain->get_tls() == nullptr) {
+    layout.reserve_exe_segment_and_tcb(nullptr, progname);
+  } else {
+    register_tls_module(somain, layout.reserve_exe_segment_and_tcb(&somain->get_tls()->segment, progname));
+  }
 
   // The pthread key data is located at the very front of bionic_tls. As a
   // temporary workaround, allocate bionic_tls just after the thread pointer so
@@ -49,8 +112,32 @@
   // small enough. Specifically, Golang scans forward 384 words from the TP on
   // ARM.
   //  - http://b/118381796
-  //  - https://groups.google.com/d/msg/golang-dev/yVrkFnYrYPE/2G3aFzYqBgAJ
+  //  - https://github.com/golang/go/issues/29674
   __linker_reserve_bionic_tls_in_static_tls();
+}
 
-  layout.finish_layout();
+void linker_finalize_static_tls() {
+  g_static_tls_finished = true;
+  __libc_shared_globals()->static_tls_layout.finish_layout();
+}
+
+void register_soinfo_tls(soinfo* si) {
+  soinfo_tls* si_tls = si->get_tls();
+  if (si_tls == nullptr || si_tls->module_id != kUninitializedModuleId) {
+    return;
+  }
+  size_t static_offset = SIZE_MAX;
+  if (!g_static_tls_finished) {
+    StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout;
+    static_offset = layout.reserve_solib_segment(si_tls->segment);
+  }
+  register_tls_module(si, static_offset);
+}
+
+void unregister_soinfo_tls(soinfo* si) {
+  soinfo_tls* si_tls = si->get_tls();
+  if (si_tls == nullptr || si_tls->module_id == kUninitializedModuleId) {
+    return;
+  }
+  return unregister_tls_module(si);
 }
diff --git a/linker/linker_tls.h b/linker/linker_tls.h
index 2f0a57d..fbb1dcf 100644
--- a/linker/linker_tls.h
+++ b/linker/linker_tls.h
@@ -28,4 +28,15 @@
 
 #pragma once
 
-void layout_linker_static_tls();
+#include <stdlib.h>
+
+struct TlsModule;
+struct soinfo;
+
+void linker_setup_exe_static_tls(const char* progname);
+void linker_finalize_static_tls();
+
+void register_soinfo_tls(soinfo* si);
+void unregister_soinfo_tls(soinfo* si);
+
+const TlsModule& get_tls_module(size_t module_id);
diff --git a/tests/Android.bp b/tests/Android.bp
index beed07a..8ac0531 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -218,6 +218,44 @@
     generated_headers: ["generated_android_ids"],
 }
 
+cc_test_library {
+    name: "libBionicElfTlsTests",
+    defaults: ["bionic_tests_defaults"],
+    srcs: [
+        "elftls_test.cpp",
+    ],
+    include_dirs: [
+        "bionic/libc",
+    ],
+    shared: {
+        enabled: false,
+    },
+    cflags: [
+        "-fno-emulated-tls",
+    ],
+}
+
+cc_test_library {
+    name: "libBionicElfTlsLoaderTests",
+    defaults: ["bionic_tests_defaults"],
+    srcs: [
+        "elftls_dl_test.cpp",
+    ],
+    include_dirs: [
+        "bionic/libc",
+    ],
+    static_libs: [
+        "liblog",
+        "libbase",
+    ],
+    shared: {
+        enabled: false,
+    },
+    cflags: [
+        "-fno-emulated-tls",
+    ],
+}
+
 // -----------------------------------------------------------------------------
 // Fortify tests.
 // -----------------------------------------------------------------------------
@@ -306,6 +344,7 @@
     defaults: ["bionic_tests_defaults"],
     whole_static_libs: [
         "libBionicStandardTests",
+        "libBionicElfTlsTests",
         "libfortify1-tests-clang",
         "libfortify2-tests-clang",
     ],
@@ -389,6 +428,7 @@
     whole_static_libs: [
         "libBionicTests",
         "libBionicLoaderTests",
+        "libBionicElfTlsLoaderTests",
     ],
 
     static_libs: [
@@ -423,6 +463,8 @@
                 "libdl_preempt_test_1",
                 "libdl_preempt_test_2",
                 "libdl_test_df_1_global",
+                "libtest_elftls_shared_var",
+                "libtest_elftls_tprel",
             ],
             static_libs: [
                 // The order of these libraries matters, do not shuffle them.
@@ -471,6 +513,7 @@
     required: [
         "cfi_test_helper",
         "cfi_test_helper2",
+        "elftls_dlopen_ie_error_helper",
         "exec_linker_helper",
         "exec_linker_helper_lib",
         "libtest_dt_runpath_a",
@@ -528,6 +571,9 @@
         "libtest_dlsym_from_this",
         "libtest_dlsym_weak_func",
         "libtest_dt_runpath_d",
+        "libtest_elftls_shared_var",
+        "libtest_elftls_shared_var_ie",
+        "libtest_elftls_tprel",
         "libtest_empty",
         "libtest_ifunc_variable_impl",
         "libtest_ifunc_variable",
@@ -629,6 +675,8 @@
         "libbase",
         "libdebuggerd_handler",
         "libgtest_isolated",
+        "libtest_elftls_shared_var",
+        "libtest_elftls_tprel",
     ],
 
     static_executable: true,
@@ -662,12 +710,15 @@
     shared_libs: [
         "libdl_preempt_test_1",
         "libdl_preempt_test_2",
-
         "libdl_test_df_1_global",
+        "libtest_elftls_shared_var",
+        "libtest_elftls_tprel",
     ],
 
     whole_static_libs: [
         "libBionicStandardTests",
+        "libBionicElfTlsTests",
+        "libBionicElfTlsLoaderTests",
         "libfortify1-tests-clang",
         "libfortify2-tests-clang",
     ],
diff --git a/tests/__aeabi_read_tp_test.cpp b/tests/__aeabi_read_tp_test.cpp
index ab96af9..6974658 100644
--- a/tests/__aeabi_read_tp_test.cpp
+++ b/tests/__aeabi_read_tp_test.cpp
@@ -32,7 +32,12 @@
 
 #if defined(__arm__)
 extern "C" void* __aeabi_read_tp();
-TEST(aeabi, read_tp) {
-  ASSERT_EQ(__aeabi_read_tp(), static_cast<void*>(__get_tls()));
-}
 #endif
+
+TEST(aeabi, read_tp) {
+#if defined(__arm__)
+  ASSERT_EQ(__aeabi_read_tp(), static_cast<void*>(__get_tls()));
+#else
+  GTEST_LOG_(INFO) << "__aeabi_read_tp is only available on arm32.\n";
+#endif
+}
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 5f48e67..176a6f8 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1086,7 +1086,7 @@
   dlerror(); // Clear any pending errors.
   void* handle = dlopen("libelf-tls-library.so", RTLD_NOW);
   ASSERT_TRUE(handle == nullptr);
-  ASSERT_SUBSTR("unsupported ELF TLS", dlerror());
+  ASSERT_SUBSTR("unknown reloc type ", dlerror());
 }
 
 TEST(dlfcn, dlopen_bad_flags) {
diff --git a/tests/elftls_dl_test.cpp b/tests/elftls_dl_test.cpp
new file mode 100644
index 0000000..0a97c28
--- /dev/null
+++ b/tests/elftls_dl_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dlfcn.h>
+#include <gtest/gtest.h>
+
+#include <thread>
+
+#include "gtest_globals.h"
+#include "utils.h"
+
+// Access libtest_elftls_shared_var.so's TLS variable using an IE access.
+__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
+
+TEST(elftls_dl, dlopen_shared_var_ie) {
+  // libtest_elftls_shared_var_ie.so can be dlopen'ed, even though it contains a
+  // TLS IE access, because its IE access references a TLS variable from
+  // libtest_elftls_shared_var.so, which is DT_NEEDED by the executable. This
+  // pattern appears in sanitizers, which use TLS IE instrumentation in shared
+  // objects to access special variables exported from the executable or from a
+  // preloaded solib.
+  void* lib = dlopen("libtest_elftls_shared_var_ie.so", RTLD_LOCAL | RTLD_NOW);
+  ASSERT_NE(nullptr, lib);
+
+  auto bump_shared_var = reinterpret_cast<int(*)()>(dlsym(lib, "bump_shared_var"));
+  ASSERT_NE(nullptr, bump_shared_var);
+
+  ASSERT_EQ(21, ++elftls_shared_var);
+  ASSERT_EQ(22, bump_shared_var());
+
+  std::thread([bump_shared_var] {
+    ASSERT_EQ(21, ++elftls_shared_var);
+    ASSERT_EQ(22, bump_shared_var());
+  }).join();
+}
+
+TEST(elftls_dl, dlopen_ie_error) {
+  std::string helper = GetTestlibRoot() +
+      "/elftls_dlopen_ie_error_helper/elftls_dlopen_ie_error_helper";
+  std::string src_path = GetTestlibRoot() + "/libtest_elftls_shared_var_ie.so";
+  std::string dst_path = GetTestlibRoot() + "/libtest_elftls_shared_var.so";
+#if defined(__BIONIC__)
+  std::string error =
+      "dlerror: dlopen failed: TLS symbol \"elftls_shared_var\" in dlopened \"" + dst_path + "\" " +
+      "referenced from \"" + src_path + "\" using IE access model\n";
+#else
+  // glibc will reserve some surplus static TLS memory, allowing this test to pass.
+  std::string error = "success\n";
+#endif
+
+  chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
+  ExecTestHelper eth;
+  eth.SetArgs({ helper.c_str(), nullptr });
+  eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, error.c_str());
+}
diff --git a/tests/elftls_test.cpp b/tests/elftls_test.cpp
new file mode 100644
index 0000000..11d41ce
--- /dev/null
+++ b/tests/elftls_test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <thread>
+
+#include "private/__get_tls.h"
+
+// Specify the LE access model explicitly. This file is compiled into the
+// bionic-unit-tests executable, but the compiler sees an -fpic object file
+// output into a static library, so it defaults to dynamic TLS accesses.
+
+// This variable will be zero-initialized (.tbss)
+__attribute__((tls_model("local-exec"))) static __thread int tlsvar_le_zero;
+
+// This variable will have an initializer (.tdata)
+__attribute__((tls_model("local-exec"))) static __thread int tlsvar_le_init = 10;
+
+// Access libtest_elftls_shared_var's TLS variable using an IE access.
+__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
+
+TEST(elftls, basic_le) {
+  // Check the variables on the main thread.
+  ASSERT_EQ(11, ++tlsvar_le_init);
+  ASSERT_EQ(1, ++tlsvar_le_zero);
+
+  // Check variables on a new thread.
+  std::thread([] {
+    ASSERT_EQ(11, ++tlsvar_le_init);
+    ASSERT_EQ(1, ++tlsvar_le_zero);
+  }).join();
+}
+
+TEST(elftls, shared_ie) {
+  ASSERT_EQ(21, ++elftls_shared_var);
+  std::thread([] {
+    ASSERT_EQ(21, ++elftls_shared_var);
+  }).join();
+}
+
+extern "C" int* missing_weak_tls_addr();
+extern "C" int bump_static_tls_var_1();
+extern "C" int bump_static_tls_var_2();
+
+TEST(elftls, tprel_missing_weak) {
+  ASSERT_EQ(static_cast<void*>(__get_tls()), missing_weak_tls_addr());
+  std::thread([] {
+    ASSERT_EQ(static_cast<void*>(__get_tls()), missing_weak_tls_addr());
+  }).join();
+}
+
+TEST(elftls, tprel_addend) {
+  ASSERT_EQ(4, bump_static_tls_var_1());
+  ASSERT_EQ(8, bump_static_tls_var_2());
+  std::thread([] {
+    ASSERT_EQ(4, bump_static_tls_var_1());
+    ASSERT_EQ(8, bump_static_tls_var_2());
+  }).join();
+}
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index ca34205..4b207b6 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -198,7 +198,7 @@
 }
 
 TEST(pwd, getpwnam_app_id_u0_i1) {
-  check_get_passwd("u0_i1", 99001, TYPE_APP);
+  check_get_passwd("u0_i1", 90001, TYPE_APP);
 }
 
 TEST(pwd, getpwnam_app_id_u1_root) {
@@ -218,9 +218,8 @@
 }
 
 TEST(pwd, getpwnam_app_id_u1_i0) {
-  check_get_passwd("u1_i0", 199000, TYPE_APP);
+  check_get_passwd("u1_i0", 190000, TYPE_APP);
 }
-
 #if defined(__BIONIC__)
 template <typename T>
 static void expect_ids(const T& ids) {
@@ -464,7 +463,7 @@
 }
 
 TEST(grp, getgrnam_app_id_u0_i1) {
-  check_get_group("u0_i1", 99001);
+  check_get_group("u0_i1", 90001);
 }
 
 TEST(grp, getgrnam_app_id_u1_root) {
@@ -484,7 +483,7 @@
 }
 
 TEST(grp, getgrnam_app_id_u1_i0) {
-  check_get_group("u1_i0", 199000);
+  check_get_group("u1_i0", 190000);
 }
 
 TEST(grp, getgrnam_r_reentrancy) {
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 79c9a06..05d1ed2 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -40,7 +40,7 @@
 }
 
 // -----------------------------------------------------------------------------
-// Library to test ELF TLS
+// Libraries and helper binaries for ELF TLS
 // -----------------------------------------------------------------------------
 cc_test_library {
     name: "libelf-tls-library",
@@ -50,6 +50,35 @@
     allow_undefined_symbols: true, // __tls_get_addr is undefined.
 }
 
+cc_test_library {
+    name: "libtest_elftls_shared_var",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["elftls_shared_var.cpp"],
+    cflags: ["-fno-emulated-tls"],
+}
+
+cc_test_library {
+    name: "libtest_elftls_shared_var_ie",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["elftls_shared_var_ie.cpp"],
+    cflags: ["-fno-emulated-tls"],
+    shared_libs: ["libtest_elftls_shared_var"],
+}
+
+cc_test_library {
+    name: "libtest_elftls_tprel",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["elftls_tprel.cpp"],
+    cflags: ["-fno-emulated-tls"],
+}
+
+cc_test {
+    name: "elftls_dlopen_ie_error_helper",
+    defaults: ["bionic_testlib_defaults"],
+    srcs: ["elftls_dlopen_ie_error_helper.cpp"],
+    ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
 // -----------------------------------------------------------------------------
 // Library to test gnu-styled hash
 // -----------------------------------------------------------------------------
@@ -237,6 +266,10 @@
         "libnstest_public",
         "libnstest_private",
     ],
+    // The dlext.ns_anonymous test copies the loaded segments of this shared
+    // object into a new mapping, so every segment must be readable. Turn off
+    // eXecute-Only-Memory. See http://b/123034666.
+    xom: false,
 }
 
 cc_test_library {
diff --git a/tests/libs/elftls_dlopen_ie_error_helper.cpp b/tests/libs/elftls_dlopen_ie_error_helper.cpp
new file mode 100644
index 0000000..5902e07
--- /dev/null
+++ b/tests/libs/elftls_dlopen_ie_error_helper.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+// This helper executable attempts to load libtest_elftls_shared_var_ie.so,
+// then reports success or failure. With Bionic, it is expected to fail, because
+// libtest_elftls_shared_var_ie.so tries to access a dynamically-allocated TLS
+// variable using the IE access model intended for static TLS.
+
+int main() {
+  void* lib = dlopen("libtest_elftls_shared_var_ie.so", RTLD_LOCAL | RTLD_NOW);
+  if (lib) {
+    printf("success\n");
+  } else {
+    printf("dlerror: %s\n", dlerror());
+  }
+  return 0;
+}
diff --git a/tests/libs/elftls_shared_var.cpp b/tests/libs/elftls_shared_var.cpp
new file mode 100644
index 0000000..27a15f0
--- /dev/null
+++ b/tests/libs/elftls_shared_var.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This shared object merely declares a global TLS variable without accessing
+// it.
+
+extern "C" __thread int elftls_shared_var = 20;
diff --git a/tests/libs/elftls_shared_var_ie.cpp b/tests/libs/elftls_shared_var_ie.cpp
new file mode 100644
index 0000000..14e2ab0
--- /dev/null
+++ b/tests/libs/elftls_shared_var_ie.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// Accessing a symbol in libtest_elftls_shared_var.so using an IE access should
+// work iff the solib is part of static TLS.
+__attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
+
+extern "C" int bump_shared_var() {
+  return ++elftls_shared_var;
+}
diff --git a/tests/libs/elftls_tprel.cpp b/tests/libs/elftls_tprel.cpp
new file mode 100644
index 0000000..eb2fd93
--- /dev/null
+++ b/tests/libs/elftls_tprel.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This shared object tests TPREL relocations in the dynamic linker. It's always
+// part of static TLS.
+
+// For accesses to these variables, the bfd and lld linkers generate a TPREL
+// relocation with no symbol but a non-zero addend.
+__attribute__((tls_model("initial-exec"))) static __thread int tls_var_1 = 3;
+__attribute__((tls_model("initial-exec"))) static __thread int tls_var_2 = 7;
+
+extern "C" int bump_static_tls_var_1() {
+  return ++tls_var_1;
+}
+
+extern "C" int bump_static_tls_var_2() {
+  return ++tls_var_2;
+}
+
+__attribute__((tls_model("initial-exec"), weak)) extern "C" __thread int missing_weak_tls;
+
+extern "C" int* missing_weak_tls_addr() {
+  // The dynamic linker should resolve a TPREL relocation to this symbol to 0,
+  // which this function adds to the thread pointer.
+  return &missing_weak_tls;
+}
diff --git a/tests/sys_time_test.cpp b/tests/sys_time_test.cpp
index d033364..5dda7ab 100644
--- a/tests/sys_time_test.cpp
+++ b/tests/sys_time_test.cpp
@@ -147,7 +147,7 @@
     tv2.tv_usec += 1000000;
   }
 
-  // Should be less than (a very generous, to try to avoid flakiness) 5ms (5000us).
+  // To try to avoid flakiness we'll accept answers within 10,000us (0.01s).
   ASSERT_EQ(0, tv2.tv_sec);
-  ASSERT_LT(tv2.tv_usec, 5000);
+  ASSERT_LT(tv2.tv_usec, 10'000);
 }
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 4ec5976..50830ee 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -607,9 +607,9 @@
     ts2.tv_nsec += NS_PER_S;
   }
 
-  // Should be less than (a very generous, to try to avoid flakiness) 1000000ns.
+  // To try to avoid flakiness we'll accept answers within 10,000,000ns (0.01s).
   ASSERT_EQ(0, ts2.tv_sec);
-  ASSERT_LT(ts2.tv_nsec, 1000000);
+  ASSERT_LT(ts2.tv_nsec, 10'000'000);
 }
 
 TEST(time, clock_gettime_CLOCK_REALTIME) {