Allow init to upgrade MTE to sync.
Bug: 169277947
Test: see other change in topic
Change-Id: I9f5820ffaeb23a4f5539bdbe3db1b455e45d84d8
diff --git a/libc/bionic/heap_tagging.h b/libc/bionic/heap_tagging.h
index a3588b8..5bc1da0 100644
--- a/libc/bionic/heap_tagging.h
+++ b/libc/bionic/heap_tagging.h
@@ -43,3 +43,19 @@
// This function can be called in a multithreaded context, and thus should
// only be called when holding the `g_heap_tagging_lock`.
bool SetHeapTaggingLevel(HeapTaggingLevel level);
+
+// This is static because libc_nomalloc uses this but does not need to link the
+// cpp file.
+__attribute__((unused)) static inline const char* DescribeTaggingLevel(
+ HeapTaggingLevel level) {
+ switch (level) {
+ case M_HEAP_TAGGING_LEVEL_NONE:
+ return "none";
+ case M_HEAP_TAGGING_LEVEL_TBI:
+ return "tbi";
+ case M_HEAP_TAGGING_LEVEL_ASYNC:
+ return "async";
+ case M_HEAP_TAGGING_LEVEL_SYNC:
+ return "sync";
+ }
+}
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 8084e73..5d5ecac 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -27,11 +27,12 @@
*/
#include "libc_init_common.h"
-#include "heap_tagging.h"
+#include <async_safe/log.h>
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -42,8 +43,8 @@
#include <sys/time.h>
#include <unistd.h>
-#include <async_safe/log.h>
-
+#include "heap_tagging.h"
+#include "private/ScopedPthreadMutexLocker.h"
#include "private/WriteProtected.h"
#include "private/bionic_defs.h"
#include "private/bionic_globals.h"
@@ -104,6 +105,51 @@
}
__BIONIC_WEAK_FOR_NATIVE_BRIDGE
+__attribute__((no_sanitize("hwaddress", "memtag"))) void
+__libc_init_mte_late() {
+#if defined(__aarch64__)
+ if (!__libc_shared_globals()->heap_tagging_upgrade_timer_sec) {
+ return;
+ }
+ struct sigevent event = {};
+ static timer_t timer;
+ event.sigev_notify = SIGEV_THREAD;
+ event.sigev_notify_function = [](union sigval) {
+ async_safe_format_log(ANDROID_LOG_INFO, "libc",
+ "Downgrading MTE to async.");
+ ScopedPthreadMutexLocker l(&g_heap_tagging_lock);
+ SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_ASYNC);
+ timer_delete(timer);
+ };
+
+ if (timer_create(CLOCK_REALTIME, &event, &timer) == -1) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "Failed to create MTE downgrade timer: %m");
+ // Revert back to ASYNC. If we fail to create or arm the timer, otherwise
+ // the process would be indefinitely stuck in SYNC.
+ SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_ASYNC);
+ return;
+ }
+
+ struct itimerspec timerspec = {};
+ timerspec.it_value.tv_sec =
+ __libc_shared_globals()->heap_tagging_upgrade_timer_sec;
+ if (timer_settime(timer, /* flags= */ 0, &timerspec, nullptr) == -1) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "Failed to arm MTE downgrade timer: %m");
+ // Revert back to ASYNC. If we fail to create or arm the timer, otherwise
+ // the process would be indefinitely stuck in SYNC.
+ SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_ASYNC);
+ timer_delete(timer);
+ return;
+ }
+ async_safe_format_log(
+ ANDROID_LOG_INFO, "libc", "Armed MTE downgrade timer for %" PRId64 " s",
+ __libc_shared_globals()->heap_tagging_upgrade_timer_sec);
+#endif
+}
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE
void __libc_add_main_thread() {
// Get the main thread from TLS and add it to the thread list.
pthread_internal_t* main_thread = __get_thread();
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 15c747e..6b39d6d 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -60,6 +60,8 @@
__LIBC_HIDDEN__ void __libc_init_scudo();
+__LIBC_HIDDEN__ void __libc_init_mte_late();
+
__LIBC_HIDDEN__ void __libc_init_AT_SECURE(char** envp);
// The fork handler must be initialised after __libc_init_malloc, as
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 24efbf5..c61810e 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -154,6 +154,8 @@
__cxa_atexit(__libc_fini,structors->fini_array,nullptr);
}
+ __libc_init_mte_late();
+
exit(slingshot(args.argc - __libc_shared_globals()->initial_linker_arg_count,
args.argv + __libc_shared_globals()->initial_linker_arg_count,
args.envp));
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));
}
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 3c86ef5..c7e951d 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -29,19 +29,19 @@
#ifndef _PRIVATE_BIONIC_GLOBALS_H
#define _PRIVATE_BIONIC_GLOBALS_H
+#include <inttypes.h>
+#include <link.h>
+#include <platform/bionic/malloc.h>
+#include <pthread.h>
#include <stdatomic.h>
#include <sys/cdefs.h>
-#include <link.h>
-#include <pthread.h>
+#include "private/WriteProtected.h"
#include "private/bionic_allocator.h"
#include "private/bionic_elf_tls.h"
#include "private/bionic_fdsan.h"
#include "private/bionic_malloc_dispatch.h"
#include "private/bionic_vdso.h"
-#include "private/WriteProtected.h"
-
-#include <platform/bionic/malloc.h>
struct libc_globals {
vdso_entry vdso[VDSO_END];
@@ -114,6 +114,7 @@
HeapTaggingLevel initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
bool initial_memtag_stack = false;
+ int64_t heap_tagging_upgrade_timer_sec = 0;
};
__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals();