[GWP-ASan] Fix non-reentrant libc_globals init behaviour.

The WriteProtected mutator for __libc_globals isn't reentrant.
Previously we were calling __libc_globals.mutate() inside of GWP-ASan's
libc initialisation, which is called inside the __libc_globals.mutate().
This causes problems with malloc_debug and other malloc shims, as they
fail to install when GWP-ASan is sampling their processes.

Bug: 135634846
Test: atest bionic
Change-Id: Iae51faa8d78677eeab6204b6ab4f3ae1b7517ba5
diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp
index 680c5e7..1feb871 100644
--- a/libc/bionic/gwp_asan_wrappers.cpp
+++ b/libc/bionic/gwp_asan_wrappers.cpp
@@ -195,7 +195,7 @@
   return false;
 }
 
-bool MaybeInitGwpAsanFromLibc() {
+bool MaybeInitGwpAsanFromLibc(libc_globals* globals) {
   // Never initialize the Zygote here. A Zygote chosen for sampling would also
   // have all of its children sampled. Instead, the Zygote child will choose
   // whether it samples or not just after the Zygote forks. For
@@ -205,14 +205,14 @@
   if (progname && strncmp(progname, "app_process", 11) == 0) {
     return false;
   }
-  return MaybeInitGwpAsan(false);
+  return MaybeInitGwpAsan(globals);
 }
 
 static bool GwpAsanInitialized = false;
 
 // Maybe initializes GWP-ASan. Called by android_mallopt() and libc's
 // initialisation. This should always be called in a single-threaded context.
-bool MaybeInitGwpAsan(bool force_init) {
+bool MaybeInitGwpAsan(libc_globals* globals, bool force_init) {
   if (GwpAsanInitialized) {
     error_log("GWP-ASan was already initialized for this process.");
     return false;
@@ -239,17 +239,15 @@
 
   // GWP-ASan's initialization is always called in a single-threaded context, so
   // we can initialize lock-free.
-  __libc_globals.mutate([](libc_globals* globals) {
-    // Set GWP-ASan as the malloc dispatch table.
-    globals->malloc_dispatch_table = gwp_asan_dispatch;
-    atomic_store(&globals->default_dispatch_table, &gwp_asan_dispatch);
+  // Set GWP-ASan as the malloc dispatch table.
+  globals->malloc_dispatch_table = gwp_asan_dispatch;
+  atomic_store(&globals->default_dispatch_table, &gwp_asan_dispatch);
 
-    // If malloc_limit isn't installed, we can skip the default_dispatch_table
-    // lookup.
-    if (GetDispatchTable() == nullptr) {
-      atomic_store(&globals->current_dispatch_table, &gwp_asan_dispatch);
-    }
-  });
+  // If malloc_limit isn't installed, we can skip the default_dispatch_table
+  // lookup.
+  if (GetDispatchTable() == nullptr) {
+    atomic_store(&globals->current_dispatch_table, &gwp_asan_dispatch);
+  }
 
 #ifndef LIBC_STATIC
   SetGlobalFunctions(gwp_asan_gfunctions);
diff --git a/libc/bionic/gwp_asan_wrappers.h b/libc/bionic/gwp_asan_wrappers.h
index 9bbc593..fd9c547 100644
--- a/libc/bionic/gwp_asan_wrappers.h
+++ b/libc/bionic/gwp_asan_wrappers.h
@@ -28,11 +28,12 @@
 
 #pragma once
 
-#include <stddef.h>
+#include <private/bionic_globals.h>
 #include <private/bionic_malloc_dispatch.h>
+#include <stddef.h>
 
 // Hooks for libc to possibly install GWP-ASan.
-bool MaybeInitGwpAsanFromLibc();
+bool MaybeInitGwpAsanFromLibc(libc_globals* globals);
 
 // Maybe initialize GWP-ASan. Set force_init to true to bypass process sampling.
-bool MaybeInitGwpAsan(bool force_init = false);
+bool MaybeInitGwpAsan(libc_globals* globals, bool force_init = false);
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index da68c80..ed5537f 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -322,7 +322,9 @@
       errno = EINVAL;
       return false;
     }
-    return MaybeInitGwpAsan(*reinterpret_cast<bool*>(arg));
+    __libc_globals.mutate([&](libc_globals* globals) {
+      return MaybeInitGwpAsan(globals, *reinterpret_cast<bool*>(arg));
+    });
   }
   errno = ENOTSUP;
   return false;
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index 79d2521..ad28cb3 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -379,7 +379,7 @@
   char prop[PROP_VALUE_MAX];
   char* options = prop;
 
-  MaybeInitGwpAsanFromLibc();
+  MaybeInitGwpAsanFromLibc(globals);
 
   // Prefer malloc debug since it existed first and is a more complete
   // malloc interceptor than the hooks.
@@ -529,7 +529,9 @@
       errno = EINVAL;
       return false;
     }
-    return MaybeInitGwpAsan(*reinterpret_cast<bool*>(arg));
+    __libc_globals.mutate([&](libc_globals* globals) {
+      return MaybeInitGwpAsan(globals, *reinterpret_cast<bool*>(arg));
+    });
   }
   // Try heapprofd's mallopt, as it handles options not covered here.
   return HeapprofdMallopt(opcode, arg, arg_size);