Add some slack at the end of large allocations when target SDK level < S.

This works around buggy applications that read a few bytes past the
end of their allocation, which would otherwise cause a segfault with
the concurrent Scudo change that aligns large allocations to the right.

Because the implementation of
android_set_application_target_sdk_version() lives in the linker,
we need to introduce a hook so that libc is notified when the target
SDK version changes.

Bug: 181344545
Change-Id: Id4be6645b94fad3f64ae48afd16c0154f1de448f
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 01cd2e5..d9dcdc4 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -131,6 +131,14 @@
   pthread_atfork(arc4random_fork_handler, _thread_arc4_unlock, _thread_arc4_unlock);
 }
 
+extern "C" void scudo_malloc_set_add_large_allocation_slack(int add_slack);
+
+__BIONIC_WEAK_FOR_NATIVE_BRIDGE void __libc_set_target_sdk_version(int target __unused) {
+#if defined(USE_SCUDO)
+  scudo_malloc_set_add_large_allocation_slack(target < __ANDROID_API_S__);
+#endif
+}
+
 __noreturn static void __early_abort(int line) {
   // We can't write to stdout or stderr because we're aborting before we've checked that
   // it's safe for us to use those file descriptors. We probably can't strace either, so
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index a899089..15c747e 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -66,4 +66,6 @@
 // pthread_atfork may call malloc() during its once-init.
 __LIBC_HIDDEN__ void __libc_init_fork_handler();
 
+__LIBC_HIDDEN__ void __libc_set_target_sdk_version(int target);
+
 #endif
diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp
index 175fa3e..4625fa1 100644
--- a/libc/bionic/libc_init_dynamic.cpp
+++ b/libc/bionic/libc_init_dynamic.cpp
@@ -46,6 +46,7 @@
 #include <elf.h>
 #include "libc_init_common.h"
 
+#include "private/bionic_defs.h"
 #include "private/bionic_elf_tls.h"
 #include "private/bionic_globals.h"
 #include "platform/bionic/macros.h"
@@ -107,6 +108,8 @@
   __libc_shared_globals()->unload_hook = __hwasan_library_unloaded;
 #endif
 
+  __libc_shared_globals()->set_target_sdk_version_hook = __libc_set_target_sdk_version;
+
   netdClientInit();
 }
 
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp
index 2e4ee11..069ebb0 100644
--- a/libc/bionic/libc_init_static.cpp
+++ b/libc/bionic/libc_init_static.cpp
@@ -400,6 +400,7 @@
 
 extern "C" void android_set_application_target_sdk_version(int target) {
   g_target_sdk_version = target;
+  __libc_set_target_sdk_version(target);
 }
 
 // This function is called in the dynamic linker before ifunc resolvers have run, so this file is
diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h
index 8132261..0d35db8 100644
--- a/libc/private/bionic_globals.h
+++ b/libc/private/bionic_globals.h
@@ -95,9 +95,10 @@
   TlsModules tls_modules;
   BionicAllocator tls_allocator;
 
-  // Values passed from the HWASan runtime (via libc.so) to the loader.
+  // Values passed from libc.so to the loader.
   void (*load_hook)(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum) = nullptr;
   void (*unload_hook)(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum) = nullptr;
+  void (*set_target_sdk_version_hook)(int target) = nullptr;
 
   // Values passed from the linker to libc.so.
   const char* init_progname = nullptr;