Merge "Add a libc wrapper for statx(2)." into rvc-dev
diff --git a/libc/bionic/android_profiling_dynamic.cpp b/libc/bionic/android_profiling_dynamic.cpp
index 183a614..54f896c 100644
--- a/libc/bionic/android_profiling_dynamic.cpp
+++ b/libc/bionic/android_profiling_dynamic.cpp
@@ -36,6 +36,7 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/ucontext.h>
 #include <sys/un.h>
 
 #include <async_safe/log.h>
@@ -64,10 +65,10 @@
   sigaction(BIONIC_SIGNAL_PROFILER, &action, nullptr);
 }
 
+static void HandleSigsysSeccompOverride(int, siginfo_t*, void*);
 static void HandleTracedPerfSignal();
 
 static void HandleProfilingSignal(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
-  // Avoid clobbering errno.
   ErrnoRestorer errno_restorer;
 
   if (info->si_code != SI_QUEUE) {
@@ -86,6 +87,21 @@
     return;
   }
 
+  // Temporarily override SIGSYS handling, in a best-effort attempt at not
+  // crashing if we happen to be running in a process with a seccomp filter that
+  // disallows some of the syscalls done by this signal handler. This protects
+  // against SECCOMP_RET_TRAP with a crashing SIGSYS handler (typical of android
+  // minijails). Won't help if the filter is using SECCOMP_RET_KILL_*.
+  // Note: the override is process-wide, but short-lived. The syscalls are still
+  // blocked, but the overridden handler recovers from SIGSYS, and fakes the
+  // syscall return value as ENOSYS.
+  struct sigaction sigsys_override = {};
+  sigsys_override.sa_sigaction = &HandleSigsysSeccompOverride;
+  sigsys_override.sa_flags = SA_SIGINFO;
+
+  struct sigaction old_act = {};
+  sigaction(SIGSYS, &sigsys_override, &old_act);
+
   if (signal_value == kHeapprofdSignalValue) {
     HandleHeapprofdSignal();
   } else if (signal_value == kTracedPerfSignalValue) {
@@ -94,6 +110,7 @@
     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "unrecognized profiling signal si_value: %d",
                           signal_value);
   }
+  sigaction(SIGSYS, &old_act, nullptr);
 }
 
 // Open /proc/self/{maps,mem}, connect to traced_perf, send the fds over the
@@ -150,3 +167,33 @@
     async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to sendmsg: %s", strerror(errno));
   }
 }
+
+static void HandleSigsysSeccompOverride(int /*signal_number*/, siginfo_t* info,
+                                        void* void_context) {
+  ErrnoRestorer errno_restorer;
+  if (info->si_code != SYS_SECCOMP) {
+    return;
+  }
+
+  async_safe_format_log(
+      ANDROID_LOG_WARN, "libc",
+      "Profiling setup: trapped seccomp SIGSYS for syscall %d. Returning ENOSYS to caller.",
+      info->si_syscall);
+
+  // The handler is responsible for setting the return value as if the system
+  // call happened (which is arch-specific). Use a plausible unsuccessful value.
+  auto ret = -ENOSYS;
+  ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+
+#if defined(__arm__)
+  ctx->uc_mcontext.arm_r0 = ret;
+#elif defined(__aarch64__)
+  ctx->uc_mcontext.regs[0] = ret;  // x0
+#elif defined(__i386__)
+  ctx->uc_mcontext.gregs[REG_EAX] = ret;
+#elif defined(__x86_64__)
+  ctx->uc_mcontext.gregs[REG_RAX] = ret;
+#else
+#error "unsupported architecture"
+#endif
+}
diff --git a/libc/bionic/ifaddrs.cpp b/libc/bionic/ifaddrs.cpp
index 0e9b544..e89b0bf 100644
--- a/libc/bionic/ifaddrs.cpp
+++ b/libc/bionic/ifaddrs.cpp
@@ -28,7 +28,6 @@
 
 #include <ifaddrs.h>
 
-#include <async_safe/log.h>
 #include <cutils/misc.h>           // FIRST_APPLICATION_UID
 #include <errno.h>
 #include <linux/if_packet.h>
@@ -282,11 +281,9 @@
 
   // Open the netlink socket and ask for all the links and addresses.
   NetlinkConnection nc;
-  // Simulate kernel behavior on R and above: RTM_GETLINK messages can only be
-  // sent by:
+  // SELinux policy only allows RTM_GETLINK messages to be sent by:
   // - System apps
   // - Apps with a target SDK version lower than R
-  // TODO(b/141455849): Remove this check when kernel changes are merged.
   bool getlink_success = false;
   if (getuid() < FIRST_APPLICATION_UID ||
       android_get_application_target_sdk_version() < __ANDROID_API_R__) {
@@ -303,7 +300,6 @@
   }
 
   if (!getlink_success) {
-    async_safe_format_log(ANDROID_LOG_INFO, "ifaddrs", "Failed to send RTM_GETLINK request");
     // If we weren't able to depend on GETLINK messages, it's possible some
     // interfaces never got their name set. Resolve them using if_indextoname or remove them.
     resolve_or_remove_nameless_interfaces(out);
diff --git a/libc/bionic/malloc_heapprofd.cpp b/libc/bionic/malloc_heapprofd.cpp
index 198d2f0..b2a9e3e 100644
--- a/libc/bionic/malloc_heapprofd.cpp
+++ b/libc/bionic/malloc_heapprofd.cpp
@@ -173,26 +173,46 @@
   // not ever have a conflict modifying the globals.
   if (!atomic_exchange(&gGlobalsMutating, true)) {
     if (!atomic_exchange(&gHeapprofdInitInProgress, true)) {
-      // If the backing dispatch is GWP-ASan, we should use GWP-ASan as the
-      // intermediate dispatch table during initialisation. It may be possible
-      // at this point in time that heapprofd is *already* the default dispatch,
-      // and as such we don't want to use heapprofd as the backing store
-      // (otherwise infinite recursion occurs).
-      gPreviousDefaultDispatchTable = nullptr;
       const MallocDispatch* default_dispatch = GetDefaultDispatchTable();
-      if (DispatchIsGwpAsan(default_dispatch)) {
+
+      // Below, we initialize heapprofd lazily by redirecting libc's malloc() to
+      // call MallocInitHeapprofdHook, which spawns off a thread and initializes
+      // heapprofd. During the short period between now and when heapprofd is
+      // initialized, allocations may need to be serviced. There are three
+      // possible configurations:
+
+      if (default_dispatch == nullptr) {
+        //  1. No malloc hooking has been done (heapprofd, GWP-ASan, etc.). In
+        //  this case, everything but malloc() should come from the system
+        //  allocator.
+        gPreviousDefaultDispatchTable = nullptr;
+        gEphemeralDispatch = *NativeAllocatorDispatch();
+      } else if (DispatchIsGwpAsan(default_dispatch)) {
+        //  2. GWP-ASan was installed. We should use GWP-ASan for everything but
+        //  malloc() in the interim period before heapprofd is properly
+        //  installed. After heapprofd is finished installing, we will use
+        //  GWP-ASan as heapprofd's backing allocator to allow heapprofd and
+        //  GWP-ASan to coexist.
         gPreviousDefaultDispatchTable = default_dispatch;
+        gEphemeralDispatch = *default_dispatch;
+      } else {
+        // 3. It may be possible at this point in time that heapprofd is
+        // *already* the default dispatch, and as such we don't want to use
+        // heapprofd as the backing store for itself (otherwise infinite
+        // recursion occurs). We will use the system allocator functions. Note:
+        // We've checked that no other malloc interceptors are being used by
+        // validating `gHeapprofdIncompatibleHooks` above, so we don't need to
+        // worry about that case here.
+        gPreviousDefaultDispatchTable = nullptr;
+        gEphemeralDispatch = *NativeAllocatorDispatch();
       }
 
-      __libc_globals.mutate([](libc_globals* globals) {
-        // Wholesale copy the malloc dispatch table here. If the current/default
-        // dispatch table is pointing to the malloc_dispatch_table, we can't
-        // modify it as it may be racy. This dispatch table copy is ephemeral,
-        // and the dispatch tables will be resolved back to the global
-        // malloc_dispatch_table after initialization finishes.
-        gEphemeralDispatch = globals->malloc_dispatch_table;
-        gEphemeralDispatch.malloc = MallocInitHeapprofdHook;
+      // Now, replace the malloc function so that the next call to malloc() will
+      // initialize heapprofd.
+      gEphemeralDispatch.malloc = MallocInitHeapprofdHook;
 
+      // And finally, install these new malloc-family interceptors.
+      __libc_globals.mutate([](libc_globals* globals) {
         atomic_store(&globals->default_dispatch_table, &gEphemeralDispatch);
         if (!MallocLimitInstalled()) {
           atomic_store(&globals->current_dispatch_table, &gEphemeralDispatch);