Call the debuggerd first chance handler in sigchain for recoverable GWP-ASan

Recoverable GWP-ASan is a new feature in Android U that allows GWP-ASan
to detect use-after-free and heap-buffer-overflow (like it currently
does), and for a bug report to be printed, but *now* the app that
contained the bug won't crash.

This may allow us to deploy GWP-ASan as an opt-out feature, rather than
an opt-in feature as it currently is. Previously, AppCompat meant that
we couldn't have opt-in GWP-ASan, because an OS upgrade could now cause
"working before" (just with silent memory corruption) apps to suddenly
crash.

Bug: 247012630

Test: Patch an OS build with aosp/2394588, then use `setprop
libc.debug.gwp_asan.recoverable.com.sanitizers.app.none true` (where
com.sanitizers.app.none is an app that can trigger a use-after-free) to
enable recoverable GWP-ASan. Then, trigger the use-after-free, and make
sure that the sigchain handler calls the debuggerd handler first,
returning from sigchain.

Change-Id: I01ff2ad6bf16cbebec4e86156d5a0357b1f98e59
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 668d75e..208f7ed 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -340,6 +340,12 @@
 
 static bool is_signal_hook_debuggable = false;
 
+// Weak linkage, as the ART APEX might be deployed on devices where this symbol doesn't exist (i.e.
+// all OS's before Android U). This symbol comes from libdl.
+__attribute__((weak)) extern "C" bool android_handle_signal(int signal_number,
+                                                            siginfo_t* info,
+                                                            void* context);
+
 void SignalChain::Handler(int signo, siginfo_t* siginfo, void* ucontext_raw) {
   // Try the special handlers first.
   // If one of them crashes, we'll reenter this handler and pass that crash onto the user handler.
@@ -369,6 +375,25 @@
     }
   }
 
+  // In Android 14, there's a special feature called "recoverable" GWP-ASan. GWP-ASan is a tool that
+  // finds heap-buffer-overflow and heap-use-after-free on native heap allocations (e.g. malloc()
+  // inside of JNI, not the ART heap). The way it catches buffer overflow (roughly) is by rounding
+  // up the malloc() so that it's page-sized, and mapping an inaccessible page on the left- and
+  // right-hand side. It catches use-after-free by mprotecting the allocation page to be PROT_NONE
+  // on free(). The new "recoverable" mode is designed to allow debuggerd to print a crash report,
+  // but for the app or process in question to not crash (i.e. recover) and continue even after the
+  // bug is detected. Sigchain thus must allow debuggerd to handle the signal first, and if
+  // debuggerd has promised that it can recover, and it's done the steps to allow recovery (as
+  // identified by android_handle_signal returning true), then we should return from this handler
+  // and let the app continue.
+  //
+  // For all non-GWP-ASan-recoverable crashes, or crashes where recovery is not possible,
+  // android_handle_signal returns false, and we will continue to the rest of the sigchain handler
+  // logic.
+  if (android_handle_signal != nullptr && android_handle_signal(signo, siginfo, ucontext_raw)) {
+    return;
+  }
+
   // Forward to the user's signal handler.
   int handler_flags = chains[signo].action_.sa_flags;
   ucontext_t* ucontext = static_cast<ucontext_t*>(ucontext_raw);