Allow init to upgrade MTE to sync.

Bug: 169277947
Test: see other change in topic
Change-Id: I9f5820ffaeb23a4f5539bdbe3db1b455e45d84d8
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 79a4019..46eafc6 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -29,6 +29,7 @@
 #include <android/api-level.h>
 #include <elf.h>
 #include <errno.h>
+#include <malloc.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -36,10 +37,9 @@
 #include <sys/auxv.h>
 #include <sys/mman.h>
 
+#include "async_safe/log.h"
+#include "heap_tagging.h"
 #include "libc_init_common.h"
-#include "pthread_internal.h"
-#include "sysprop_helpers.h"
-
 #include "platform/bionic/macros.h"
 #include "platform/bionic/mte.h"
 #include "platform/bionic/page.h"
@@ -51,7 +51,9 @@
 #include "private/bionic_elf_tls.h"
 #include "private/bionic_globals.h"
 #include "private/bionic_tls.h"
+#include "pthread_internal.h"
 #include "sys/system_properties.h"
+#include "sysprop_helpers.h"
 
 #if __has_feature(hwaddress_sanitizer)
 #include <sanitizer/hwasan_interface.h>
@@ -302,7 +304,34 @@
                                                                          void* stack_top) {
   bool memtag_stack;
   HeapTaggingLevel level = __get_heap_tagging_level(phdr_start, phdr_ct, load_bias, &memtag_stack);
-
+  char* env = getenv("BIONIC_MEMTAG_UPGRADE_SECS");
+  int64_t timed_upgrade = 0;
+  if (env) {
+    char* endptr;
+    timed_upgrade = strtoll(env, &endptr, 10);
+    if (*endptr != '\0' || timed_upgrade < 0) {
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+                            "Invalid value for BIONIC_MEMTAG_UPGRADE_SECS: %s",
+                            env);
+      timed_upgrade = 0;
+    }
+    // Make sure that this does not get passed to potential processes inheriting
+    // this environment.
+    unsetenv("BIONIC_MEMTAG_UPGRADE_SECS");
+  }
+  if (timed_upgrade) {
+    if (level == M_HEAP_TAGGING_LEVEL_ASYNC) {
+      async_safe_format_log(ANDROID_LOG_INFO, "libc",
+                            "Attempting timed MTE upgrade from async to sync.");
+      __libc_shared_globals()->heap_tagging_upgrade_timer_sec = timed_upgrade;
+      level = M_HEAP_TAGGING_LEVEL_SYNC;
+    } else if (level != M_HEAP_TAGGING_LEVEL_SYNC) {
+      async_safe_format_log(
+          ANDROID_LOG_ERROR, "libc",
+          "Requested timed MTE upgrade from invalid %s to sync. Ignoring.",
+          DescribeTaggingLevel(level));
+    }
+  }
   if (level == M_HEAP_TAGGING_LEVEL_SYNC || level == M_HEAP_TAGGING_LEVEL_ASYNC) {
     unsigned long prctl_arg = PR_TAGGED_ADDR_ENABLE | PR_MTE_TAG_SET_NONZERO;
     prctl_arg |= (level == M_HEAP_TAGGING_LEVEL_SYNC) ? PR_MTE_TCF_SYNC : PR_MTE_TCF_ASYNC;
@@ -333,6 +362,8 @@
   if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0) {
     __libc_shared_globals()->initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI;
   }
+  // We did not enable MTE, so we do not need to arm the upgrade timer.
+  __libc_shared_globals()->heap_tagging_upgrade_timer_sec = 0;
 }
 #else   // __aarch64__
 void __libc_init_mte(const void*, size_t, uintptr_t, void*) {}
@@ -384,6 +415,8 @@
     __cxa_atexit(__libc_fini,structors->fini_array,nullptr);
   }
 
+  __libc_init_mte_late();
+
   exit(slingshot(args.argc, args.argv, args.envp));
 }