[Tagged Pointers] Allow probing the current TP level w/ locking.

aosp/1484976 introduced a breaking change where
DisableMemoryMitigations() now indiscriminately turns tagged pointers
off. When android_mallopt(M_DISABLE_MEMORY_MITIGATIONS) is called, the
correct behaviour is:
 - In SYNC/ASYNC MTE mode -> disable all tagged pointers.
 - If all tagged pointers are already disabled -> nop.
 - If we're in TBI mode -> nop (keep the TBI mode as-is).

In order to do that we have to allow probing of the current heap tagging
mode. In order to prevent TOCTOU between GetHeapTaggingLevel() and
SetHeapTaggingLevel(), we expose a global mutex that should be held when
calling these functions.

Bug: 174263432
Test: atest CtsTaggingHostTestCases on Flame
Change-Id: Ia96f7269d542c9041270458806aee36766d2fbbb
diff --git a/libc/bionic/memory_mitigation_state.cpp b/libc/bionic/memory_mitigation_state.cpp
index abb1e8d..4761d88 100644
--- a/libc/bionic/memory_mitigation_state.cpp
+++ b/libc/bionic/memory_mitigation_state.cpp
@@ -39,8 +39,10 @@
 #include <bionic/malloc.h>
 #include <bionic/mte.h>
 
+#include <private/ScopedPthreadMutexLocker.h>
+#include <private/ScopedRWLock.h>
+
 #include "heap_tagging.h"
-#include "private/ScopedRWLock.h"
 #include "pthread_internal.h"
 
 extern "C" void scudo_malloc_set_zero_contents(int zero_contents);
@@ -54,8 +56,13 @@
   scudo_malloc_set_zero_contents(0);
 #endif
 
-  HeapTaggingLevel level = M_HEAP_TAGGING_LEVEL_NONE;
-  SetHeapTaggingLevel(reinterpret_cast<void*>(&level), sizeof(level));
+  ScopedPthreadMutexLocker locker(&g_heap_tagging_lock);
+
+  HeapTaggingLevel current_level = GetHeapTaggingLevel();
+  if (current_level != M_HEAP_TAGGING_LEVEL_NONE && current_level != M_HEAP_TAGGING_LEVEL_TBI) {
+    HeapTaggingLevel level = M_HEAP_TAGGING_LEVEL_NONE;
+    SetHeapTaggingLevel(reinterpret_cast<void*>(&level), sizeof(level));
+  }
 
   return true;
 }