From 982b11b88fc2655b9f471a84b427c50fc53cccb9 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 16 Jul 2016 23:55:16 -0400 Subject: [PATCH 01/51] replace VLA formatting with dprintf-like function Signed-off-by: anupritaisno1 --- libc/bionic/bionic_systrace.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/libc/bionic/bionic_systrace.cpp b/libc/bionic/bionic_systrace.cpp index ff222936ccc..7bed3cdfe1f 100644 --- a/libc/bionic/bionic_systrace.cpp +++ b/libc/bionic/bionic_systrace.cpp @@ -29,8 +29,6 @@ #include #include // For ATRACE_TAG_BIONIC. -#define WRITE_OFFSET 32 - static Lock g_lock; static CachedProperty g_debug_atrace_tags_enableflags("debug.atrace.tags.enableflags"); static uint64_t g_tags; @@ -61,15 +59,9 @@ static void trace_begin_internal(const char* message) { return; } - // If bionic tracing has been enabled, then write the message to the - // kernel trace_marker. - int length = strlen(message); - char buf[length + WRITE_OFFSET]; - size_t len = async_safe_format_buffer(buf, length + WRITE_OFFSET, "B|%d|%s", getpid(), message); - // Tracing may stop just after checking property and before writing the message. // So the write is acceptable to fail. See b/20666100. - TEMP_FAILURE_RETRY(write(trace_marker_fd, buf, len)); + async_safe_format_fd(trace_marker_fd, "B|%d|%s", getpid(), message); } void bionic_trace_begin(const char* message) { From 623a065d3a93915ad705af301277e8719819ea2d Mon Sep 17 00:00:00 2001 From: anupritaisno1 Date: Wed, 13 Oct 2021 12:30:25 +0300 Subject: [PATCH 02/51] add a real explicit_bzero implementation Clang, GCC and other compilers special-case standard C functions like memset. Calls to memset will be optimized out. OpenBSD provides explicit_bzero to work around this but Android simply defines it as memset so nothing prevents it from being optimized away. This implementation uses a memory read constraint via empty inline assembly rather than something that may be broken via link-time optimization in the future. --- libc/Android.bp | 1 + libc/bionic/explicit_bzero.cpp | 6 ++++++ libc/include/string.h | 2 ++ libc/libc.map.txt | 1 + libc/upstream-openbsd/android/include/openbsd-compat.h | 4 ---- 5 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 libc/bionic/explicit_bzero.cpp diff --git a/libc/Android.bp b/libc/Android.bp index 3c56ed76552..fdef40659d9 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -939,6 +939,7 @@ cc_library_static { "bionic/exec.cpp", "bionic/execinfo.cpp", "bionic/exit.cpp", + "bionic/explicit_bzero.cpp", "bionic/faccessat.cpp", "bionic/fchmod.cpp", "bionic/fchmodat.cpp", diff --git a/libc/bionic/explicit_bzero.cpp b/libc/bionic/explicit_bzero.cpp new file mode 100644 index 00000000000..e3cc182d68d --- /dev/null +++ b/libc/bionic/explicit_bzero.cpp @@ -0,0 +1,6 @@ +#include + +void explicit_bzero(void* _Nonnull s, size_t n) { + void *ptr = memset(s, 0, n); + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +} diff --git a/libc/include/string.h b/libc/include/string.h index 06793c34e8b..602fef664a9 100644 --- a/libc/include/string.h +++ b/libc/include/string.h @@ -66,6 +66,8 @@ void* _Nonnull memmove(void* _Nonnull __dst, const void* _Nonnull __src, size_t */ void* _Nonnull memset(void* _Nonnull __dst, int __ch, size_t __n); +void explicit_bzero(void* _Nonnull s, size_t n); + #if __ANDROID_API__ >= 34 /** * [memset_explicit(3)](https://man7.org/linux/man-pages/man3/memset_explicit.3.html) diff --git a/libc/libc.map.txt b/libc/libc.map.txt index b0633eb32fe..ebc7972868e 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -333,6 +333,7 @@ LIBC { execvp; execvpe; exit; + explicit_bzero; # introduced=33 faccessat; fallocate; fallocate64; diff --git a/libc/upstream-openbsd/android/include/openbsd-compat.h b/libc/upstream-openbsd/android/include/openbsd-compat.h index b89e09ad8e4..86a67361e5f 100644 --- a/libc/upstream-openbsd/android/include/openbsd-compat.h +++ b/libc/upstream-openbsd/android/include/openbsd-compat.h @@ -41,10 +41,6 @@ extern const char* __progname; #define PROTO_NORMAL(x) #define WRAP(x) x -#if !defined(ANDROID_HOST_MUSL) -#define explicit_bzero(p, s) memset_explicit(p, 0, s) -#endif - #if defined(ANDROID_HOST_MUSL) #define __LIBC_HIDDEN__ __attribute__((visibility("hidden"))) #endif From 6048b67be9f73483f727f21e918cfa253cfbef74 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 8 Feb 2015 01:18:54 -0500 Subject: [PATCH 03/51] replace brk and sbrk with stubs Pretend that there is never room to grow the heap in order to prevent usage of these unsafe legacy functions. There are likely no users of these in practice as it is inherently broken to use them outside of malloc. Signed-off-by: anupritaisno1 --- libc/bionic/brk.cpp | 48 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/libc/bionic/brk.cpp b/libc/bionic/brk.cpp index 566c33a7a6d..ef93055139b 100644 --- a/libc/bionic/brk.cpp +++ b/libc/bionic/brk.cpp @@ -29,48 +29,16 @@ #include #include -#if defined(__LP64__) -static void* __bionic_brk; -#else -void* __bionic_brk; // Accidentally exported by the NDK. +#if !defined(__LP64__) +void* __bionic_brk = reinterpret_cast(-1); // Accidentally exported by the NDK. #endif -extern "C" void* __brk(void* __addr); - -int brk(void* end_data) { - __bionic_brk = __brk(end_data); - if (__bionic_brk < end_data) { - errno = ENOMEM; - return -1; - } - return 0; +int brk(void*) { + errno = ENOMEM; + return -1; } -void* sbrk(ptrdiff_t increment) { - // Initialize __bionic_brk if necessary. - if (__bionic_brk == nullptr) { - __bionic_brk = __brk(nullptr); - } - - // Don't ask the kernel if we already know the answer. - if (increment == 0) { - return __bionic_brk; - } - - // Avoid overflow. - uintptr_t old_brk = reinterpret_cast(__bionic_brk); - if ((increment > 0 && static_cast(increment) > (UINTPTR_MAX - old_brk)) || - (increment < 0 && static_cast(-increment) > old_brk)) { - errno = ENOMEM; - return reinterpret_cast(-1); - } - - void* desired_brk = reinterpret_cast(old_brk + increment); - __bionic_brk = __brk(desired_brk); - if (__bionic_brk < desired_brk) { - errno = ENOMEM; - return reinterpret_cast(-1); - } - - return reinterpret_cast(old_brk); +void* sbrk(ptrdiff_t) { + errno = ENOMEM; + return reinterpret_cast(-1); } From cb0af2abf92e7cbb26113e454aea2dc379594fe7 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 27 Jun 2017 19:27:12 -0400 Subject: [PATCH 04/51] document that fields before cached_pid break it Adding a field above this results in either that field or the tid field (depending on if it's above that too) being set to zero by vfork. Ideally that assembly would be replaced with a C++ wrapper but in the meantime this adds a comment to save time for someone else. Signed-off-by: anupritaisno1 --- libc/bionic/pthread_internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index b3133a92dfa..09aab981e64 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -72,6 +72,7 @@ class pthread_internal_t { pid_t tid; private: + // accessed from vfork asm via offset of field, so don't put fields above this uint32_t cached_pid_ : 31; uint32_t vforked_ : 1; From 9d7d02f8ca215dd7f1a40bd6601c927bba6e9b2d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 4 Mar 2019 04:26:04 -0500 Subject: [PATCH 05/51] use blocking getrandom and avoid urandom fallback --- libc/bionic/getentropy.cpp | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/libc/bionic/getentropy.cpp b/libc/bionic/getentropy.cpp index 5272c34f8d9..bd96be0d41a 100644 --- a/libc/bionic/getentropy.cpp +++ b/libc/bionic/getentropy.cpp @@ -34,22 +34,6 @@ #include "private/ScopedFd.h" -static int getentropy_urandom(void* buffer, size_t buffer_size, int saved_errno) { - ScopedFd fd(TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_NOFOLLOW | O_CLOEXEC, 0))); - if (fd.get() == -1) return -1; - - size_t collected = 0; - while (collected < buffer_size) { - ssize_t count = TEMP_FAILURE_RETRY(read(fd.get(), static_cast(buffer) + collected, - buffer_size - collected)); - if (count == -1) return -1; - collected += count; - } - - errno = saved_errno; - return 0; -} - int getentropy(void* buffer, size_t buffer_size) { if (buffer_size > GETENTROPY_MAX) { errno = EINVAL; @@ -60,22 +44,10 @@ int getentropy(void* buffer, size_t buffer_size) { size_t collected = 0; while (collected < buffer_size) { - long count = TEMP_FAILURE_RETRY(getrandom(static_cast(buffer) + collected, - buffer_size - collected, GRND_NONBLOCK)); + long count = TEMP_FAILURE_RETRY( + getrandom(static_cast(buffer) + collected, buffer_size - collected, 0)); if (count == -1) { - // One of several things could have gone wrong: - // EAGAIN: there isn't enough entropy right now. - // ENOSYS/EINVAL: getrandom(2) or GRND_NONBLOCK isn't supported. - // EFAULT: `buffer` is invalid. - // Realistically we're here because of EAGAIN, - // for which /dev/urandom is the solution --- - // it'll return low entropy randomness where getrandom() won't, - // but we fall back /dev/urandom for all cases because it can't hurt, - // and we don't need to optimize the EFAULT case. - // See https://man7.org/linux/man-pages/man7/random.7.html for getrandom() - // vs /dev/random vs /dev/urandom. - // See http://b/33059407 and http://b/67015565. - return getentropy_urandom(buffer, buffer_size, saved_errno); + return -1; } collected += count; } From 66722667f5a016a51a526f8347bd514346da44d3 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 17 Jul 2015 21:32:05 -0400 Subject: [PATCH 06/51] increase default pthread stack to 8MiB on 64-bit Signed-off-by: anupritaisno1 --- libc/bionic/pthread_internal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index 09aab981e64..c10e25fb926 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -269,7 +269,11 @@ __LIBC_HIDDEN__ void pthread_key_clean_all(void); // stack overflows, we subtracted the same amount we were using there // from the default thread stack size. This should keep memory usage // roughly constant. +#ifdef __LP64__ +#define PTHREAD_STACK_SIZE_DEFAULT ((8 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD) +#else #define PTHREAD_STACK_SIZE_DEFAULT ((1 * 1024 * 1024) - SIGNAL_STACK_SIZE_WITHOUT_GUARD) +#endif // Leave room for a guard page in the internally created signal stacks. #define SIGNAL_STACK_SIZE (SIGNAL_STACK_SIZE_WITHOUT_GUARD + PTHREAD_GUARD_SIZE) From da8e0d318ea42e234d679c7f4ffa300be9072c6d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 2 Dec 2015 23:37:28 -0500 Subject: [PATCH 07/51] switch pthread_atfork handler allocation to mmap Signed-off-by: anupritaisno1 --- libc/bionic/pthread_atfork.cpp | 35 ++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp index 0dcabdfb2de..6306052ee3b 100644 --- a/libc/bionic/pthread_atfork.cpp +++ b/libc/bionic/pthread_atfork.cpp @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include "platform/bionic/macros.h" @@ -43,6 +46,8 @@ struct atfork_t { void* dso_handle; }; +static atfork_t* pool; + class atfork_list_t { public: constexpr atfork_list_t() : first_(nullptr), last_(nullptr) {} @@ -101,7 +106,8 @@ class atfork_list_t { last_ = entry->prev; } - free(entry); + entry->next = pool; + pool = entry; } atfork_t* first_; @@ -154,18 +160,35 @@ void __bionic_atfork_run_parent() { // __register_atfork is the name used by glibc extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void), void* dso) { - atfork_t* entry = reinterpret_cast(malloc(sizeof(atfork_t))); - if (entry == nullptr) { - return ENOMEM; + pthread_mutex_lock(&g_atfork_list_mutex); + + if (!pool) { + size_t page_size = getpagesize(); + char* page = static_cast(mmap(NULL, page_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)); + if (page == MAP_FAILED) { + pthread_mutex_unlock(&g_atfork_list_mutex); + return ENOMEM; + } + + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, page_size, + "atfork handlers"); + + for (char* it = page; it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) { + atfork_t* node = reinterpret_cast(it); + node->next = pool; + pool = node; + } } + atfork_t* entry = pool; + pool = entry->next; + entry->prepare = prepare; entry->parent = parent; entry->child = child; entry->dso_handle = dso; - pthread_mutex_lock(&g_atfork_list_mutex); - g_atfork_list.push_back(entry); pthread_mutex_unlock(&g_atfork_list_mutex); From 5e9e689701bf70ae29a690d0431f38ef80a95ba9 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 3 Dec 2015 12:58:31 -0500 Subject: [PATCH 08/51] add memory protection for pthread_atfork handlers Signed-off-by: anupritaisno1 --- libc/bionic/pthread_atfork.cpp | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp index 6306052ee3b..d59f3ae54bc 100644 --- a/libc/bionic/pthread_atfork.cpp +++ b/libc/bionic/pthread_atfork.cpp @@ -47,6 +47,7 @@ struct atfork_t { }; static atfork_t* pool; +static atfork_t* page_list; class atfork_list_t { public: @@ -160,13 +161,22 @@ void __bionic_atfork_run_parent() { // __register_atfork is the name used by glibc extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void), void* dso) { + size_t page_size = getpagesize(); + pthread_mutex_lock(&g_atfork_list_mutex); + for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) { + mprotect(page_it, page_size, PROT_READ|PROT_WRITE); + } + if (!pool) { - size_t page_size = getpagesize(); char* page = static_cast(mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)); if (page == MAP_FAILED) { + for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) { + mprotect(page_it, page_size, PROT_READ); + } + pthread_mutex_unlock(&g_atfork_list_mutex); return ENOMEM; } @@ -174,11 +184,15 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, page, page_size, "atfork handlers"); - for (char* it = page; it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) { + for (char* it = page + sizeof(atfork_t); it < page + page_size - sizeof(atfork_t); it += sizeof(atfork_t)) { atfork_t* node = reinterpret_cast(it); node->next = pool; pool = node; } + + atfork_t* page_node = reinterpret_cast(page); + page_node->next = page_list; + page_list = page_node; } atfork_t* entry = pool; @@ -191,6 +205,10 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), g_atfork_list.push_back(entry); + for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) { + mprotect(page_it, page_size, PROT_READ); + } + pthread_mutex_unlock(&g_atfork_list_mutex); return 0; @@ -198,8 +216,20 @@ extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void), extern "C" __LIBC_HIDDEN__ void __unregister_atfork(void* dso) { pthread_mutex_lock(&g_atfork_list_mutex); + + size_t page_size = getpagesize(); + + for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) { + mprotect(page_it, page_size, PROT_READ|PROT_WRITE); + } + g_atfork_list.remove_if([&](const atfork_t* entry) { return entry->dso_handle == dso; }); + + for (atfork_t* page_it = page_list; page_it; page_it = page_it->next) { + mprotect(page_it, page_size, PROT_READ); + } + pthread_mutex_unlock(&g_atfork_list_mutex); } From 03010507ae5aa31dad2a8b512979ce806be42b6e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 27 Jan 2016 18:02:15 -0500 Subject: [PATCH 09/51] add XOR mangling mitigation for thread-local dtors memtag_stack struct member is required to be at its exact position by static_assert below. Signed-off-by: anupritaisno1 --- libc/bionic/__cxa_thread_atexit_impl.cpp | 8 +++++--- libc/bionic/libc_init_common.cpp | 2 ++ libc/private/bionic_globals.h | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libc/bionic/__cxa_thread_atexit_impl.cpp b/libc/bionic/__cxa_thread_atexit_impl.cpp index 99077c101df..74608513ef0 100644 --- a/libc/bionic/__cxa_thread_atexit_impl.cpp +++ b/libc/bionic/__cxa_thread_atexit_impl.cpp @@ -13,15 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include #include +#include #include "pthread_internal.h" class thread_local_dtor { public: - void (*func) (void *); + uintptr_t func; void *arg; void *dso_handle; // unused... thread_local_dtor* next; @@ -35,7 +37,7 @@ __BIONIC_WEAK_FOR_NATIVE_BRIDGE int __cxa_thread_atexit_impl(void (*func) (void *), void *arg, void *dso_handle) { thread_local_dtor* dtor = new thread_local_dtor(); - dtor->func = func; + dtor->func = __libc_globals->dtor_cookie ^ reinterpret_cast(func); dtor->arg = arg; dtor->dso_handle = dso_handle; @@ -54,7 +56,7 @@ extern "C" __LIBC_HIDDEN__ void __cxa_thread_finalize() { thread_local_dtor* current = thread->thread_local_dtors; thread->thread_local_dtors = current->next; - current->func(current->arg); + (reinterpret_cast(__libc_globals->dtor_cookie ^ current->func))(current->arg); if (__loader_remove_thread_local_dtor != nullptr) { __loader_remove_thread_local_dtor(current->dso_handle); } diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index 81de336a717..95cee39ce35 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -46,6 +46,7 @@ #include "heap_tagging.h" #include "private/ScopedPthreadMutexLocker.h" #include "private/WriteProtected.h" +#include "private/bionic_arc4random.h" #include "private/bionic_defs.h" #include "private/bionic_globals.h" #include "private/bionic_tls.h" @@ -89,6 +90,7 @@ void __libc_init_globals() { __libc_globals.mutate([](libc_globals* globals) { __libc_init_vdso(globals); __libc_init_setjmp_cookie(globals); + arc4random_buf(&globals->dtor_cookie, sizeof(globals->dtor_cookie)); }); } diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index a7a4afe1d68..7ef22dfe94f 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -49,6 +49,7 @@ struct libc_globals { uintptr_t heap_pointer_tag; _Atomic(bool) decay_time_enabled; _Atomic(bool) memtag; + long dtor_cookie; // In order to allow a complete switch between dispatch tables without // the need for copying each function by function in the structure, From 36c4268bb81b17ca277f62c6570b4802c2fe1aca Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 29 Jan 2016 20:20:09 -0500 Subject: [PATCH 10/51] use a better pthread_attr junk filling pattern Guarantee that junk filled pointers will fault, at least on pure 64-bit. Signed-off-by: anupritaisno1 --- libc/bionic/pthread_attr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/bionic/pthread_attr.cpp b/libc/bionic/pthread_attr.cpp index f27f0eac15b..dcd3acf92d2 100644 --- a/libc/bionic/pthread_attr.cpp +++ b/libc/bionic/pthread_attr.cpp @@ -54,7 +54,7 @@ int pthread_attr_init(pthread_attr_t* attr) { __BIONIC_WEAK_FOR_NATIVE_BRIDGE int pthread_attr_destroy(pthread_attr_t* attr) { - memset(attr, 0x42, sizeof(pthread_attr_t)); + memset(attr, 0xdf, sizeof(pthread_attr_t)); return 0; } From f04912175cbe8568558bafa9a9476fd6cf52384c Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 28 Jul 2024 17:32:49 -0400 Subject: [PATCH 11/51] enforce minimum 64kiB stack guard on arm64 This is required by the AArch64 ABI for the default stack probe size of 64kiB. --- libc/bionic/pthread_create.cpp | 4 ++++ libc/bionic/pthread_internal.h | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 60b5b077234..70a224b26bd 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -301,6 +301,10 @@ static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** chi attr->guard_size = __builtin_align_up(attr->guard_size, page_size()); if (attr->guard_size < unaligned_guard_size) return EAGAIN; +#ifdef __aarch64__ + if (attr->guard_size < 65536) attr->guard_size = 65536; +#endif + mapping = __allocate_thread_mapping(attr->stack_size, attr->guard_size); if (mapping.mmap_base == nullptr) return EAGAIN; diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index c10e25fb926..57065500762 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -250,8 +250,13 @@ __LIBC_HIDDEN__ void pthread_key_clean_all(void); // Address space is precious on LP32, so use the minimum unit: one page. // On LP64, we could use more but there's no obvious advantage to doing // so, and the various media processes use RLIMIT_AS as a way to limit -// the amount of allocation they'll do. +// the amount of allocation they'll do. AArch64 requires 64kiB to handle +// the minimum stack probe size of 64kiB. +#if __aarch64__ +#define PTHREAD_GUARD_SIZE 65536 +#else #define PTHREAD_GUARD_SIZE max_android_page_size() +#endif // SIGSTKSZ (8KiB) is not big enough. // An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack. From 656329f9bf3b241c3834994ed81b10b30cc9fb99 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 23 Oct 2024 05:15:25 -0400 Subject: [PATCH 12/51] Revert "enforce minimum 64kiB stack guard on arm64" This reverts commit 37407d63f47a392bded9c09067d2aed21212117c. This has to be reverted for now due to Facebook adding a buggy stack overflow check to the React Native Hermes JavaScript engine. --- libc/bionic/pthread_create.cpp | 4 ---- libc/bionic/pthread_internal.h | 7 +------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 70a224b26bd..60b5b077234 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -301,10 +301,6 @@ static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** chi attr->guard_size = __builtin_align_up(attr->guard_size, page_size()); if (attr->guard_size < unaligned_guard_size) return EAGAIN; -#ifdef __aarch64__ - if (attr->guard_size < 65536) attr->guard_size = 65536; -#endif - mapping = __allocate_thread_mapping(attr->stack_size, attr->guard_size); if (mapping.mmap_base == nullptr) return EAGAIN; diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h index 57065500762..c10e25fb926 100644 --- a/libc/bionic/pthread_internal.h +++ b/libc/bionic/pthread_internal.h @@ -250,13 +250,8 @@ __LIBC_HIDDEN__ void pthread_key_clean_all(void); // Address space is precious on LP32, so use the minimum unit: one page. // On LP64, we could use more but there's no obvious advantage to doing // so, and the various media processes use RLIMIT_AS as a way to limit -// the amount of allocation they'll do. AArch64 requires 64kiB to handle -// the minimum stack probe size of 64kiB. -#if __aarch64__ -#define PTHREAD_GUARD_SIZE 65536 -#else +// the amount of allocation they'll do. #define PTHREAD_GUARD_SIZE max_android_page_size() -#endif // SIGSTKSZ (8KiB) is not big enough. // An snprintf to a stack buffer of size PATH_MAX consumes ~7KiB of stack. From d4396741ae366d6f5afded0ac92055aee4edfa25 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 1 Oct 2016 05:11:44 -0400 Subject: [PATCH 13/51] make __stack_chk_guard read-only at runtime Signed-off-by: anupritaisno1 --- libc/bionic/__libc_init_main_thread.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp index a057b03293b..f80864af9ed 100644 --- a/libc/bionic/__libc_init_main_thread.cpp +++ b/libc/bionic/__libc_init_main_thread.cpp @@ -28,6 +28,9 @@ #include "libc_init_common.h" +#include +#include + #include #include "private/KernelArgumentBlock.h" @@ -35,14 +38,14 @@ #include "private/bionic_defs.h" #include "private/bionic_elf_tls.h" #include "private/bionic_globals.h" -#include "private/bionic_ssp.h" #include "pthread_internal.h" extern "C" pid_t __getpid(); extern "C" int __set_tid_address(int* tid_address); // Declared in "private/bionic_ssp.h". -uintptr_t __stack_chk_guard = 0; +__attribute__((aligned(max_android_page_size()))) +uintptr_t __stack_chk_guard[max_android_page_size() / sizeof(uintptr_t)] = {0}; BIONIC_USED_BEFORE_LINKER_RELOCATES static pthread_internal_t main_thread; @@ -108,10 +111,16 @@ void __init_tcb_dtv(bionic_tcb* tcb) { // Note in particular that it is not possible to return from any existing // stack frame with stack protector enabled after this function is called. extern "C" void android_reset_stack_guards() { + if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ|PROT_WRITE) == -1) { + async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno)); + } // The TLS stack guard is set from the global, so ensure that we've initialized the global // before we initialize the TLS. Dynamic executables will initialize their copy of the global // stack protector from the one in the main thread's TLS. - __libc_arc4random_buf_or_die(&__stack_chk_guard, sizeof(__stack_chk_guard)); + __libc_arc4random_buf_or_die(&__stack_chk_guard[0], sizeof(__stack_chk_guard[0])); + if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ) == -1) { + async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno)); + } __init_tcb_stack_guard(__get_bionic_tcb()); } From 41b06e6c0609b204003be1b9a0be7cab588c3d73 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 12 Mar 2017 17:49:13 -0400 Subject: [PATCH 14/51] on 64-bit, zero the leading stack canary byte This reduces entropy of the canary from 64-bit to 56-bit in exchange for mitigating non-terminated C string overflows. --- libc/bionic/__libc_init_main_thread.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libc/bionic/__libc_init_main_thread.cpp b/libc/bionic/__libc_init_main_thread.cpp index f80864af9ed..5c76f04839c 100644 --- a/libc/bionic/__libc_init_main_thread.cpp +++ b/libc/bionic/__libc_init_main_thread.cpp @@ -49,6 +49,12 @@ uintptr_t __stack_chk_guard[max_android_page_size() / sizeof(uintptr_t)] = {0}; BIONIC_USED_BEFORE_LINKER_RELOCATES static pthread_internal_t main_thread; +#if __LP64__ +static const uintptr_t canary_mask = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ? + 0xffffffffffffff00UL : + 0x00ffffffffffffffUL; +#endif + // Setup for the main thread. For dynamic executables, this is called by the // linker _before_ libc is mapped in memory. This means that all writes to // globals from this function will apply to linker-private copies and will not @@ -118,6 +124,10 @@ extern "C" void android_reset_stack_guards() { // before we initialize the TLS. Dynamic executables will initialize their copy of the global // stack protector from the one in the main thread's TLS. __libc_arc4random_buf_or_die(&__stack_chk_guard[0], sizeof(__stack_chk_guard[0])); +#if __LP64__ + // Sacrifice 8 bits of entropy on 64-bit to mitigate non-terminated C string overflows + __stack_chk_guard[0] &= canary_mask; +#endif if (mprotect(__stack_chk_guard, sizeof(__stack_chk_guard), PROT_READ) == -1) { async_safe_fatal("mprotect __stack_chk_guard: %s", strerror(errno)); } From 222635835a19d7a15e8f67b97edf13bcae88056a Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Thu, 22 Jul 2021 16:12:55 -0700 Subject: [PATCH 15/51] gmscompat: linker: Add support for opening zip files by fd paths In some cases, it can be useful to load libraries from zip files that are only available by fd reference. For example, file descriptors of APKs containing native libraries may be sent via Binder IPC for clients to use. Unfortunately, while this linker does support loading libraries from file descriptors using android_dlopen_ext, using that API is not an option because our dlopen calls originate from JNI loadLibrary requests in ART. This is necessary for compatibility with Google Play Services' dynamic module system (Dynamite) without weakening the SELinux sandbox to allow other apps to open module APKs from /data/user_de/0/com.google.android.gms/app_chimera/m. Squashed with 7b3fc50d822aaffadb6429a87bfd358ecb7ae58e Change-Id: If44d5c3faf4f50e4704688b520b197ff151ae05a --- linker/linker.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 05f1a469c33..6fb5627096b 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -890,14 +890,14 @@ class ZipArchiveCache { ZipArchiveCache() {} ~ZipArchiveCache(); - bool get_or_open(const char* zip_path, ZipArchiveHandle* handle); + bool get_or_open(const char* zip_path, int zip_fd, ZipArchiveHandle* handle); private: DISALLOW_COPY_AND_ASSIGN(ZipArchiveCache); std::unordered_map cache_; }; -bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle) { +bool ZipArchiveCache::get_or_open(const char* zip_path, int zip_fd, ZipArchiveHandle* handle) { std::string key(zip_path); auto it = cache_.find(key); @@ -906,7 +906,7 @@ bool ZipArchiveCache::get_or_open(const char* zip_path, ZipArchiveHandle* handle return true; } - int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); + int fd = zip_fd != -1 ? dup(zip_fd) : TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); if (fd == -1) { return false; } @@ -957,13 +957,19 @@ static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache, const char* zip_path = buf; const char* file_path = &buf[separator - path + 2]; - int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); + int fd; + if (!strncmp("/gmscompat_fd_", zip_path, strlen("/gmscompat_fd_")) && + sscanf(zip_path, "/gmscompat_fd_%d", &fd) == 1) { + fd = dup(fd); + } else { + fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC)); + } if (fd == -1) { return -1; } ZipArchiveHandle handle; - if (!zip_archive_cache->get_or_open(zip_path, &handle)) { + if (!zip_archive_cache->get_or_open(zip_path, fd, &handle)) { // invalid zip-file (?) close(fd); return -1; From 111589f2bfb7934818744bce8032da89a43a11ba Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 30 Mar 2022 14:15:40 -0400 Subject: [PATCH 16/51] add clarification about sample IPv4 address This function checks if a source address is available for sending data to this sample IPv4 address by making a UDP socket and calling connect which does not perform I/O with the socket since this is UDP, not TCP. The purpose of _find_src_addr is to check whether an attempt could be made to connect or send data to the IP without doing it. --- libc/dns/net/getaddrinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c index cc771f06e0a..4e8516e3329 100644 --- a/libc/dns/net/getaddrinfo.c +++ b/libc/dns/net/getaddrinfo.c @@ -385,7 +385,7 @@ static int _have_ipv4(unsigned mark, uid_t uid) { static const struct sockaddr_in sin_test = { .sin_family = AF_INET, - .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8 + .sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8 (routable public IP, not used to make a connection or send any data) }; sockaddr_union addr = { .in = sin_test }; return _find_src_addr(&addr.generic, NULL, mark, uid) == 1; From a64c4e169036d58ea7351df66f3b1ff5ebe7510e Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 14 Aug 2022 14:57:59 +0300 Subject: [PATCH 17/51] add a wrapper for execveat(2) --- libc/SYSCALLS.TXT | 1 + libc/bionic/exec.cpp | 6 ++++++ libc/include/unistd.h | 1 + libc/libc.map.txt | 1 + 4 files changed, 9 insertions(+) diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index 3622ca4f450..fcecbfa4cea 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -73,6 +73,7 @@ tgkill(pid_t tgid, pid_t tid, int sig) all __brk:brk(void*) all execve(const char*, char* const*, char* const*) all +__execveat:execveat(int, const char*, char* const*, char* const*, int) all __ptrace:ptrace(int request, int pid, void* addr, void* data) all # diff --git a/libc/bionic/exec.cpp b/libc/bionic/exec.cpp index 56544d03905..e76047da876 100644 --- a/libc/bionic/exec.cpp +++ b/libc/bionic/exec.cpp @@ -181,3 +181,9 @@ int fexecve(int fd, char* const* argv, char* const* envp) { if (errno == ENOENT) errno = EBADF; return -1; } + +extern "C" int __execveat(int dirfd, const char* pathname, char* const* argv, char* const* envp, int flags); + +int execveat(int dirfd, const char* pathname, char* const* argv, char* const* envp, int flags) { + return __execveat(dirfd, pathname, argv, envp, flags); +} diff --git a/libc/include/unistd.h b/libc/include/unistd.h index 260019c3a68..b892684ad53 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -159,6 +159,7 @@ int execv(const char* _Nonnull __path, char* _Nullable const* _Nullable __argv); int execvp(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv); int execvpe(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp); int execve(const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp); +int execveat(int dirfd, const char* _Nonnull __file, char* _Nullable const* _Nullable __argv, char* _Nullable const* _Nullable __envp, int flags); int execl(const char* _Nonnull __path, const char* _Nullable __arg0, ...) __attribute__((__sentinel__)); int execlp(const char* _Nonnull __file, const char* _Nullable __arg0, ...) __attribute__((__sentinel__)); int execle(const char* _Nonnull __path, const char* _Nullable __arg0, ... /*, char* const* __envp */) diff --git a/libc/libc.map.txt b/libc/libc.map.txt index ebc7972868e..ae09d9feeef 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -330,6 +330,7 @@ LIBC { execlp; execv; execve; + execveat; execvp; execvpe; exit; From e26c8be76ca196d9831bcb9145ccc310c0837d78 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 5 Dec 2018 08:51:56 +0200 Subject: [PATCH 18/51] use Scudo on 32-bit and hardened_malloc on 64-bit 64-bit Scudo can be swithed to at runtime, see the next commit. Squashed with 6562b94dfc6dec13e1df79a1b029e6c78f4aa9ad Co-authored-by: anupritaisno1 --- libc/Android.bp | 46 ++++++++++++++++++---------- libc/bionic/h_malloc_wrapper.cpp | 51 ++++++++++++++++++++++++++++++++ libc/bionic/malloc_common.h | 25 +++++++++------- 3 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 libc/bionic/h_malloc_wrapper.cpp diff --git a/libc/Android.bp b/libc/Android.bp index fdef40659d9..2752d38cb79 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -45,6 +45,8 @@ libc_common_flags = [ // ever touch 0, 1, or 2 bytes into a call to memset, which was never going // to amortize.) "-fno-builtin", + + "-DH_MALLOC_PREFIX", ] soong_config_module_type { @@ -187,22 +189,26 @@ cc_defaults { cc_defaults { name: "libc_native_allocator_defaults", - whole_static_libs: [ - "libscudo", - ], - cflags: [ - "-DUSE_SCUDO", - ], header_libs: ["gwp_asan_headers"], - product_variables: { - malloc_low_memory: { - cflags: ["-UUSE_SCUDO"], - whole_static_libs: [ + whole_static_libs: ["libscudo"], + + multilib: { + lib32: { + cflags: ["-DUSE_SCUDO"], + exclude_static_libs: [ "libjemalloc5", "libc_jemalloc_wrapper", ], - exclude_static_libs: [ - "libscudo", + }, + lib64: { + srcs: ["bionic/h_malloc_wrapper.cpp"], + cflags: [ + "-DH_MALLOC_PREFIX", + "-DUSE_H_MALLOC", + "-DUSE_SCUDO", + ], + whole_static_libs: [ + "libhardened_malloc", ], }, }, @@ -213,12 +219,20 @@ cc_defaults { cc_library_static { name: "libc_jemalloc_wrapper", defaults: ["libc_defaults"], - srcs: ["bionic/jemalloc_wrapper.cpp"], + multilib: { + lib32: { + // Used to pull in the jemalloc/hardened_malloc include directory so that if the + // library is removed, the include directory is also removed. + srcs: ["bionic/jemalloc_wrapper.cpp"], + static_libs: ["libjemalloc5"], + }, + lib64: { + srcs: ["bionic/h_malloc_wrapper.cpp"], + static_libs: ["libhardened_malloc"], + }, + }, cflags: ["-fvisibility=hidden"], - // Used to pull in the jemalloc include directory so that if the - // library is removed, the include directory is also removed. - static_libs: ["libjemalloc5"], } // ======================================================== diff --git a/libc/bionic/h_malloc_wrapper.cpp b/libc/bionic/h_malloc_wrapper.cpp new file mode 100644 index 00000000000..5fb0968c277 --- /dev/null +++ b/libc/bionic/h_malloc_wrapper.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#include + +#include "h_malloc.h" + +__BEGIN_DECLS +int h_malloc_info(int options, FILE* fp); +__END_DECLS + +int h_malloc_info(int options, FILE* fp) { + if (options != 0) { + errno = EINVAL; + return -1; + } + + fflush(fp); + int fd = fileno(fp); + MallocXmlElem root(fd, "malloc", "version=\"jemalloc-1\""); + + // Dump all of the large allocations in the arenas. + for (size_t i = 0; i < h_mallinfo_narenas(); i++) { + struct mallinfo mi = h_mallinfo_arena_info(i); + if (mi.hblkhd != 0) { + MallocXmlElem arena_elem(fd, "heap", "nr=\"%d\"", i); + { + MallocXmlElem(fd, "allocated-large").Contents("%zu", mi.ordblks); + MallocXmlElem(fd, "allocated-huge").Contents("%zu", mi.uordblks); + MallocXmlElem(fd, "allocated-bins").Contents("%zu", mi.fsmblks); + + size_t total = 0; + for (size_t j = 0; j < h_mallinfo_nbins(); j++) { + struct mallinfo mi = h_mallinfo_bin_info(i, j); + if (mi.ordblks != 0) { + MallocXmlElem bin_elem(fd, "bin", "nr=\"%d\"", j); + MallocXmlElem(fd, "allocated").Contents("%zu", mi.ordblks); + MallocXmlElem(fd, "nmalloc").Contents("%zu", mi.uordblks); + MallocXmlElem(fd, "ndalloc").Contents("%zu", mi.fordblks); + total += mi.ordblks; + } + } + MallocXmlElem(fd, "bins-total").Contents("%zu", total); + } + } + } + + return 0; +} diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h index 4afcc4a8d5f..8852c85a296 100644 --- a/libc/bionic/malloc_common.h +++ b/libc/bionic/malloc_common.h @@ -55,21 +55,26 @@ __END_DECLS #else // __has_feature(hwaddress_sanitizer) -#if defined(USE_SCUDO) - -#include "scudo.h" -#define Malloc(function) scudo_ ## function +#ifdef __LP64__ +#ifndef USE_H_MALLOC +#error missing USE_H_MALLOC +#endif -#elif defined(USE_SCUDO_SVELTE) +#include "h_malloc.h" +#define Malloc(function) h_ ## function +__BEGIN_DECLS +int h_malloc_info(int options, FILE* fp); +__END_DECLS +#if defined(USE_SCUDO) #include "scudo.h" -#define Malloc(function) scudo_svelte_ ## function - -#else +#endif -#include "jemalloc.h" -#define Malloc(function) je_ ## function +#define BOTH_H_MALLOC_AND_SCUDO +#else // 32-bit +#include "scudo.h" +#define Malloc(function) scudo_ ## function #endif #endif From fe18673996867549f840a5e8cb58a4604bf5639c Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 14 Aug 2022 15:13:01 +0300 Subject: [PATCH 19/51] add a runtime option to disable hardened_malloc --- libc/bionic/malloc_common.cpp | 51 +++++++++++++++++++++++++++ libc/bionic/malloc_common.h | 1 + libc/bionic/malloc_common_dynamic.cpp | 4 +++ 3 files changed, 56 insertions(+) diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 2ae9068a398..288df878ec1 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -363,9 +363,60 @@ static constexpr MallocDispatch __libc_malloc_default_dispatch __attribute__((un Malloc(malloc_info), }; +#if defined(BOTH_H_MALLOC_AND_SCUDO) + +#define ScudoMalloc(function) scudo_ ## function + +static constexpr MallocDispatch __scudo_malloc_dispatch __attribute__((unused)) = { + ScudoMalloc(calloc), + ScudoMalloc(free), + ScudoMalloc(mallinfo), + ScudoMalloc(malloc), + ScudoMalloc(malloc_usable_size), + ScudoMalloc(memalign), + ScudoMalloc(posix_memalign), + #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + ScudoMalloc(pvalloc), + #endif + ScudoMalloc(realloc), + ScudoMalloc(reallocarray), + #if defined(HAVE_DEPRECATED_MALLOC_FUNCS) + ScudoMalloc(valloc), + #endif + ScudoMalloc(malloc_iterate), + ScudoMalloc(malloc_disable), + ScudoMalloc(malloc_enable), + ScudoMalloc(mallopt), + ScudoMalloc(aligned_alloc), + ScudoMalloc(malloc_info), +}; + +static const MallocDispatch* native_allocator_dispatch; + +void InitNativeAllocatorDispatch(libc_globals* globals) { + const bool hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr; + + const MallocDispatch* table = hardened_impl ? + &__libc_malloc_default_dispatch : + &__scudo_malloc_dispatch; + + if (!hardened_impl) { + globals->malloc_dispatch_table = __scudo_malloc_dispatch; + globals->current_dispatch_table = &globals->malloc_dispatch_table; + globals->default_dispatch_table = &globals->malloc_dispatch_table; + } + + native_allocator_dispatch = table; +} + +const MallocDispatch* NativeAllocatorDispatch() { + return native_allocator_dispatch; +} +#else const MallocDispatch* NativeAllocatorDispatch() { return &__libc_malloc_default_dispatch; } +#endif #if !defined(LIBC_STATIC) void MallocInitImpl(libc_globals* globals); diff --git a/libc/bionic/malloc_common.h b/libc/bionic/malloc_common.h index 8852c85a296..ef4b1a4be8f 100644 --- a/libc/bionic/malloc_common.h +++ b/libc/bionic/malloc_common.h @@ -68,6 +68,7 @@ __END_DECLS #if defined(USE_SCUDO) #include "scudo.h" +void InitNativeAllocatorDispatch(libc_globals* globals); #endif #define BOTH_H_MALLOC_AND_SCUDO diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index dec8f9f00bd..97a1cba425b 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp @@ -381,6 +381,10 @@ extern "C" size_t __scudo_get_stack_depot_size(); // Initializes memory allocation framework once per process. void MallocInitImpl(libc_globals* globals) { +#if defined(BOTH_H_MALLOC_AND_SCUDO) + InitNativeAllocatorDispatch(globals); +#endif + char prop[PROP_VALUE_MAX]; char* options = prop; From 994a32bef5f7767dbe40887bb5695777999ea490 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 2 May 2023 16:45:26 +0300 Subject: [PATCH 20/51] support assigning ID to path of current executable --- libc/bionic/libc_init_dynamic.cpp | 27 ++++++++++++++++++++++++++- libc/include/stdlib.h | 3 +++ libc/libc.map.txt | 1 + libc/private/bionic_globals.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 9f593706d4f..c3092864c83 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -77,6 +77,28 @@ extern "C" __attribute__((weak)) void __hwasan_library_unloaded(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum); +static void init_prog_id(libc_globals* globals) { + char exe_path[500]; + ssize_t readlink_res = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1 /* space for NUL terminator */); + if (readlink_res <= 0) { + return; + } + exe_path[readlink_res] = '\0'; + + int prog_id = 0; + +#define IS(prog) (!strcmp(exe_path, prog)) + +#undef IS + + // libc_globals struct is write-protected + globals->prog_id = prog_id; +} + +int get_prog_id() { + return __libc_globals->prog_id; +} + // We need a helper function for __libc_preinit because compiling with LTO may // inline functions requiring a stack protector check, but __stack_chk_guard is // not initialized at the start of __libc_preinit. __libc_preinit_impl will run @@ -108,7 +130,10 @@ static void __libc_preinit_impl() { #endif // Hooks for various libraries to let them know that we're starting up. - __libc_globals.mutate(__libc_init_malloc); + __libc_globals.mutate([](libc_globals* globals) { + init_prog_id(globals); + __libc_init_malloc(globals); + }); // Install reserved signal handlers for assisting the platform's profilers. __libc_init_profiling_handlers(); diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index cb1ac1fff1d..05381ed6a8c 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -527,6 +527,9 @@ long double strtold(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ /** Equivalent to strtold() on Android. */ long double strtold_l(const char* _Nonnull __s, char* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) __RENAME(strtold); +int get_prog_id(); +#define is_prog(id) (get_prog_id() == id) + __END_DECLS #endif /* _STDLIB_H */ diff --git a/libc/libc.map.txt b/libc/libc.map.txt index ae09d9feeef..c77e540b4a7 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -425,6 +425,7 @@ LIBC { get_nprocs; # introduced=23 get_nprocs_conf; # introduced=23 get_phys_pages; # introduced=23 + get_prog_id; getaddrinfo; getauxval; getc; diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index 7ef22dfe94f..283cd6a3b88 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -65,6 +65,7 @@ struct libc_globals { // limit is enabled and some other hook is enabled at the same time. _Atomic(const MallocDispatch*) default_dispatch_table; MallocDispatch malloc_dispatch_table; + int prog_id; }; struct memtag_dynamic_entries_t { From 3d824f2ecf2dcfe7ae06b7f32acb30c7813bff11 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 2 May 2023 16:46:56 +0300 Subject: [PATCH 21/51] support disabling hardened_malloc for specific program IDs --- libc/bionic/malloc_common.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 288df878ec1..08aef5fbe64 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -394,7 +394,11 @@ static constexpr MallocDispatch __scudo_malloc_dispatch __attribute__((unused)) static const MallocDispatch* native_allocator_dispatch; void InitNativeAllocatorDispatch(libc_globals* globals) { - const bool hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr; + bool hardened_impl = true; + switch (get_prog_id()) { + default: + hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr; + } const MallocDispatch* table = hardened_impl ? &__libc_malloc_default_dispatch : From f441e4f0de91f0594a7f07eac75697bf4446bfee Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Mon, 23 Oct 2023 20:40:33 +0300 Subject: [PATCH 22/51] support disabling memory tagging in hardened_malloc --- libc/bionic/heap_tagging.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp index c7319708c06..bc4234f1059 100644 --- a/libc/bionic/heap_tagging.cpp +++ b/libc/bionic/heap_tagging.cpp @@ -36,6 +36,8 @@ #include #include +extern "C" void h_malloc_disable_memory_tagging(); + extern "C" void scudo_malloc_disable_memory_tagging(); extern "C" void scudo_malloc_set_track_allocation_stacks(int); @@ -73,19 +75,26 @@ void SetDefaultHeapTaggingLevel() { }; }); -#if defined(USE_SCUDO) && !__has_feature(hwaddress_sanitizer) + switch (heap_tagging_level) { case M_HEAP_TAGGING_LEVEL_TBI: case M_HEAP_TAGGING_LEVEL_NONE: +#if defined(USE_SCUDO) scudo_malloc_disable_memory_tagging(); +#endif +#if defined(USE_H_MALLOC) + h_malloc_disable_memory_tagging(); +#endif break; case M_HEAP_TAGGING_LEVEL_SYNC: +#if defined(USE_SCUDO) scudo_malloc_set_track_allocation_stacks(1); +#endif break; default: break; } -#endif // USE_SCUDO + #endif // aarch64 } @@ -134,6 +143,9 @@ bool SetHeapTaggingLevel(HeapTaggingLevel tag_level) { } #if defined(USE_SCUDO) && !__has_feature(hwaddress_sanitizer) scudo_malloc_disable_memory_tagging(); +#endif +#if defined(USE_H_MALLOC) + h_malloc_disable_memory_tagging(); #endif break; case M_HEAP_TAGGING_LEVEL_TBI: From d59e8224f0439a2e775370aeb0a8a90466015bd5 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 1 Nov 2023 21:27:18 +0200 Subject: [PATCH 23/51] never enable GWP-ASan It weakens hardened_malloc protections, especially when memory tagging is enabled. --- libc/bionic/android_mallopt.cpp | 8 -------- libc/bionic/gwp_asan_wrappers.h | 7 ------- libc/bionic/malloc_common_dynamic.cpp | 2 -- tests/malloc_test.cpp | 23 ----------------------- 4 files changed, 40 deletions(-) diff --git a/libc/bionic/android_mallopt.cpp b/libc/bionic/android_mallopt.cpp index 79e40723765..d6d0257b1f8 100644 --- a/libc/bionic/android_mallopt.cpp +++ b/libc/bionic/android_mallopt.cpp @@ -66,14 +66,6 @@ extern "C" bool android_mallopt(int opcode, void* arg, size_t arg_size) { *reinterpret_cast(arg) = atomic_load(&__libc_globals->decay_time_enabled); return true; } - if (opcode == M_INITIALIZE_GWP_ASAN) { - if (arg == nullptr || arg_size != sizeof(android_mallopt_gwp_asan_options_t)) { - errno = EINVAL; - return false; - } - - return EnableGwpAsan(*reinterpret_cast(arg)); - } if (opcode == M_MEMTAG_STACK_IS_ON) { if (arg == nullptr || arg_size != sizeof(bool)) { errno = EINVAL; diff --git a/libc/bionic/gwp_asan_wrappers.h b/libc/bionic/gwp_asan_wrappers.h index 219da9fc580..9053d4aa4b8 100644 --- a/libc/bionic/gwp_asan_wrappers.h +++ b/libc/bionic/gwp_asan_wrappers.h @@ -35,13 +35,6 @@ #include "private/bionic_globals.h" #include "private/bionic_malloc_dispatch.h" -// Enable GWP-ASan, used by android_mallopt. Should always be called in a -// single-threaded context. -bool EnableGwpAsan(const android_mallopt_gwp_asan_options_t& options); - -// Hooks for libc to possibly install GWP-ASan. -bool MaybeInitGwpAsanFromLibc(libc_globals* globals); - // Returns whether GWP-ASan is the provided dispatch table pointer. Used in // heapprofd's signal-initialization sequence to determine the intermediate // dispatch pointer to use when initing. diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index 97a1cba425b..c7d4e474af6 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp @@ -388,8 +388,6 @@ void MallocInitImpl(libc_globals* globals) { char prop[PROP_VALUE_MAX]; char* options = prop; - MaybeInitGwpAsanFromLibc(globals); - #if defined(USE_SCUDO) && !__has_feature(hwaddress_sanitizer) __libc_shared_globals()->scudo_stack_depot = __scudo_get_stack_depot_addr(); __libc_shared_globals()->scudo_region_info = __scudo_get_region_info_addr(); diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 46f234205af..4a6925659f1 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -940,29 +940,6 @@ TEST(android_mallopt, set_allocation_limit_multiple_threads) { #endif } -#if defined(__BIONIC__) -using Mode = android_mallopt_gwp_asan_options_t::Mode; -TEST(android_mallopt, DISABLED_multiple_enable_gwp_asan) { - android_mallopt_gwp_asan_options_t options; - options.program_name = ""; // Don't infer GWP-ASan options from sysprops. - options.mode = Mode::APP_MANIFEST_NEVER; - // GWP-ASan should already be enabled. Trying to enable or disable it should - // always pass. - ASSERT_TRUE(android_mallopt(M_INITIALIZE_GWP_ASAN, &options, sizeof(options))); - options.mode = Mode::APP_MANIFEST_DEFAULT; - ASSERT_TRUE(android_mallopt(M_INITIALIZE_GWP_ASAN, &options, sizeof(options))); -} -#endif // defined(__BIONIC__) - -TEST(android_mallopt, multiple_enable_gwp_asan) { -#if defined(__BIONIC__) - // Always enable GWP-Asan, with default options. - RunGwpAsanTest("*.DISABLED_multiple_enable_gwp_asan"); -#else - GTEST_SKIP() << "bionic extension"; -#endif -} - TEST(android_mallopt, memtag_stack_is_on) { #if defined(__BIONIC__) bool memtag_stack; From 27973b6408dc3f24ea3f2636b470b97e202160bc Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 17 Nov 2023 17:00:45 +0200 Subject: [PATCH 24/51] add an option to ignore requests to disable heap memory tagging This is needed for forcibly enabling memory tagging in apps that call mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, M_HEAP_TAGGING_LEVEL_NONE) despite being compatible with memory tagging. Some of them likely do this to disable top-byte-ignore (M_HEAP_TAGGING_LEVEL_TBI is disableable with the same API call). Note that switching between M_HEAP_TAGGING_LEVEL_ASYNC and M_HEAP_TAGGING_LEVEL_SYNC is intentionally not blocked: when the device is configured to use "SYNC" memory tagging, it'll use it both in M_HEAP_TAGGING_LEVEL_ASYNC and M_HEAP_TAGGING_LEVEL_SYNC modes. M_HEAP_TAGGING_LEVEL_SYNC is intended for debugging, it enables allocation stack trace collection in Scudo, which significantly lowers performance. --- libc/bionic/heap_tagging.cpp | 19 +++++++++++++++++++ libc/bionic/heap_tagging.h | 2 ++ libc/bionic/malloc_common.cpp | 6 ++++++ libc/include/malloc.h | 1 + 4 files changed, 28 insertions(+) diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp index bc4234f1059..6b29f8e8f27 100644 --- a/libc/bionic/heap_tagging.cpp +++ b/libc/bionic/heap_tagging.cpp @@ -115,12 +115,31 @@ static bool set_tcf_on_all_threads(int tcf) { pthread_mutex_t g_heap_tagging_lock = PTHREAD_MUTEX_INITIALIZER; +static bool block_heap_tagging_level_downgrade; + +// Requires `g_heap_tagging_lock` to be held. +bool BlockHeapTaggingLevelDowngrade() { + if (block_heap_tagging_level_downgrade) { + return false; + } + block_heap_tagging_level_downgrade = true; + return true; +} + // Requires `g_heap_tagging_lock` to be held. bool SetHeapTaggingLevel(HeapTaggingLevel tag_level) { if (tag_level == heap_tagging_level) { return true; } + if (block_heap_tagging_level_downgrade) { + // allow switching between SYNC and ASYNC, but don't allow disabling memory tagging + if (tag_level < heap_tagging_level && tag_level != M_HEAP_TAGGING_LEVEL_ASYNC) { + error_log("SetHeapTaggingLevel: blocked downgrade of tag level from %i to %i", heap_tagging_level, tag_level); + return false; + } + } + switch (tag_level) { case M_HEAP_TAGGING_LEVEL_NONE: __libc_globals.mutate([](libc_globals* globals) { diff --git a/libc/bionic/heap_tagging.h b/libc/bionic/heap_tagging.h index 5bc1da0f463..94fd6b72bc0 100644 --- a/libc/bionic/heap_tagging.h +++ b/libc/bionic/heap_tagging.h @@ -40,6 +40,8 @@ void SetDefaultHeapTaggingLevel(); // useful for RAII on this lock. extern pthread_mutex_t g_heap_tagging_lock; +bool BlockHeapTaggingLevelDowngrade(); + // 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); diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 08aef5fbe64..794caba772e 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -116,6 +116,12 @@ extern "C" int mallopt(int param, int value) { ScopedPthreadMutexLocker locker(&g_heap_tagging_lock); return SetHeapTaggingLevel(static_cast(value)); } + + if (param == M_BIONIC_BLOCK_HEAP_TAGGING_LEVEL_DOWNGRADE) { + ScopedPthreadMutexLocker locker(&g_heap_tagging_lock); + return BlockHeapTaggingLevelDowngrade(); + } + if (param == M_BIONIC_ZERO_INIT) { return SetHeapZeroInitialize(value); } diff --git a/libc/include/malloc.h b/libc/include/malloc.h index f60292eb523..d3c35c0066b 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -342,6 +342,7 @@ int malloc_info(int __must_be_zero, FILE* _Nonnull __fp) __INTRODUCED_IN(23); */ #define M_BIONIC_SET_HEAP_TAGGING_LEVEL (-204) +#define M_BIONIC_BLOCK_HEAP_TAGGING_LEVEL_DOWNGRADE (-1000) /** * Constants for use with the M_BIONIC_SET_HEAP_TAGGING_LEVEL mallopt() option. */ From 88065d307d6553ca852574e8d48310fe6b179f59 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 28 Nov 2023 12:01:10 +0200 Subject: [PATCH 25/51] add option to force default handling of MTE SEGV signals This is needed for forcibly enabling memory tagging for apps that use custom crash handlers, which ignore SIGSEGV in some cases. Even if SIGSEGV isn't ignored by such handler, it usually breaks detection of memory tagging-related crashes (MTEAERR/MTESERR signal codes are consumed by them). Requires the corresponding patch to sigchainlib in art (sigchainlib overrides sigaction() and signal()). --- libc/bionic/malloc_common.cpp | 16 ++++++++++++++++ libc/include/malloc.h | 3 +++ libc/private/bionic_globals.h | 1 + 3 files changed, 20 insertions(+) diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 794caba772e..0e828584eaa 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -122,6 +122,22 @@ extern "C" int mallopt(int param, int value) { return BlockHeapTaggingLevelDowngrade(); } + if (param == M_BIONIC_ENABLE_SIGCHAINLIB_MTE_SIGSEGV_INTERCEPTION) { + if (__libc_globals->is_sigchainlib_mte_sigsegv_interception_enabled) { + return 0; + } + + __libc_globals.mutate([](libc_globals* globals) { + globals->is_sigchainlib_mte_sigsegv_interception_enabled = true; + }); + + return 1; + } + + if (param == M_BIONIC_SIGCHAINLIB_SHOULD_INTERCEPT_MTE_SIGSEGV) { + return __libc_globals->is_sigchainlib_mte_sigsegv_interception_enabled; + } + if (param == M_BIONIC_ZERO_INIT) { return SetHeapZeroInitialize(value); } diff --git a/libc/include/malloc.h b/libc/include/malloc.h index d3c35c0066b..faeeee30823 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -343,6 +343,9 @@ int malloc_info(int __must_be_zero, FILE* _Nonnull __fp) __INTRODUCED_IN(23); #define M_BIONIC_SET_HEAP_TAGGING_LEVEL (-204) #define M_BIONIC_BLOCK_HEAP_TAGGING_LEVEL_DOWNGRADE (-1000) +#define M_BIONIC_ENABLE_SIGCHAINLIB_MTE_SIGSEGV_INTERCEPTION (-1001) +#define M_BIONIC_SIGCHAINLIB_SHOULD_INTERCEPT_MTE_SIGSEGV (-1002) + /** * Constants for use with the M_BIONIC_SET_HEAP_TAGGING_LEVEL mallopt() option. */ diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index 283cd6a3b88..3f7592b3804 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -66,6 +66,7 @@ struct libc_globals { _Atomic(const MallocDispatch*) default_dispatch_table; MallocDispatch malloc_dispatch_table; int prog_id; + bool is_sigchainlib_mte_sigsegv_interception_enabled; }; struct memtag_dynamic_entries_t { From 4426724a946df9d7b27ac121161b97773f2eea84 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sun, 31 Dec 2023 15:25:07 +0200 Subject: [PATCH 26/51] add mallopt option for restoring the default SIGABRT handler --- libc/bionic/libc_init_dynamic.cpp | 3 +++ libc/bionic/malloc_common.cpp | 8 ++++++++ libc/include/malloc.h | 1 + libc/private/bionic_globals.h | 1 + 4 files changed, 13 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index c3092864c83..b8f14d2f550 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -133,6 +133,9 @@ static void __libc_preinit_impl() { __libc_globals.mutate([](libc_globals* globals) { init_prog_id(globals); __libc_init_malloc(globals); + + // save the default SIGABRT handler to support restoring it with mallopt(M_BIONIC_RESTORE_DEFAULT_SIGABRT_HANDLER) + sigaction(SIGABRT, nullptr, &globals->saved_sigabrt_handler); }); // Install reserved signal handlers for assisting the platform's profilers. diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 0e828584eaa..032a0de98c6 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -138,6 +138,14 @@ extern "C" int mallopt(int param, int value) { return __libc_globals->is_sigchainlib_mte_sigsegv_interception_enabled; } + if (param == M_BIONIC_RESTORE_DEFAULT_SIGABRT_HANDLER) { + if (__libc_globals->saved_sigabrt_handler.sa_sigaction != nullptr) { + sigaction(SIGABRT, &__libc_globals->saved_sigabrt_handler, nullptr); + return 1; + } + return 0; + } + if (param == M_BIONIC_ZERO_INIT) { return SetHeapZeroInitialize(value); } diff --git a/libc/include/malloc.h b/libc/include/malloc.h index faeeee30823..edbc3f1d0ed 100644 --- a/libc/include/malloc.h +++ b/libc/include/malloc.h @@ -345,6 +345,7 @@ int malloc_info(int __must_be_zero, FILE* _Nonnull __fp) __INTRODUCED_IN(23); #define M_BIONIC_BLOCK_HEAP_TAGGING_LEVEL_DOWNGRADE (-1000) #define M_BIONIC_ENABLE_SIGCHAINLIB_MTE_SIGSEGV_INTERCEPTION (-1001) #define M_BIONIC_SIGCHAINLIB_SHOULD_INTERCEPT_MTE_SIGSEGV (-1002) +#define M_BIONIC_RESTORE_DEFAULT_SIGABRT_HANDLER (-1003) /** * Constants for use with the M_BIONIC_SET_HEAP_TAGGING_LEVEL mallopt() option. diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index 3f7592b3804..d97ec895db5 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -67,6 +67,7 @@ struct libc_globals { MallocDispatch malloc_dispatch_table; int prog_id; bool is_sigchainlib_mte_sigsegv_interception_enabled; + struct sigaction saved_sigabrt_handler; }; struct memtag_dynamic_entries_t { From fbc321826b28c220febc178642082fca39ff5212 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 19 Apr 2024 22:37:02 +0300 Subject: [PATCH 27/51] make get_property_value() part of internal bionic API --- libc/bionic/sysprop_helpers.cpp | 2 +- libc/bionic/sysprop_helpers.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libc/bionic/sysprop_helpers.cpp b/libc/bionic/sysprop_helpers.cpp index e025edde0d8..d4e276ae6a1 100644 --- a/libc/bionic/sysprop_helpers.cpp +++ b/libc/bionic/sysprop_helpers.cpp @@ -36,7 +36,7 @@ #include -static bool get_property_value(const char* property_name, char* dest, size_t dest_size) { +bool get_property_value(const char* property_name, char* dest, size_t dest_size) { CHECK(property_name); CHECK(dest); CHECK(dest_size != 0); diff --git a/libc/bionic/sysprop_helpers.h b/libc/bionic/sysprop_helpers.h index a02c2dc415b..9ff539f4fdf 100644 --- a/libc/bionic/sysprop_helpers.h +++ b/libc/bionic/sysprop_helpers.h @@ -43,3 +43,5 @@ __LIBC_HIDDEN__ bool get_config_from_env_or_sysprops(const char* env_var_name, const char* const* sys_prop_names, size_t sys_prop_names_size, char* options, size_t options_size); + +__LIBC_HIDDEN__ bool get_property_value(const char* property_name, char* dest, size_t dest_size); From 82ef6c166ea09a5daf53ec824c9b46449d02d714 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 20 Apr 2024 12:02:20 +0300 Subject: [PATCH 28/51] add sysprop for enabling heap memory tagging in vendor processes --- libc/bionic/libc_init_mte.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index d23b0563d0e..15927e6fc6f 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -108,6 +108,10 @@ static HeapTaggingLevel __get_memtag_level_from_note(const ElfW(Phdr) * phdr_sta } } +static bool starts_with(const char* s, const char* prefix) { + return strncmp(s, prefix, strlen(prefix)) == 0; +} + // Returns true if there's an environment setting (either sysprop or env var) // that should overwrite the ELF note, and places the equivalent heap tagging // level into *level. @@ -120,6 +124,15 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { const char* progname = __libc_shared_globals()->init_progname; if (progname == nullptr) return false; + bool is_vendor_prog = starts_with(progname, "/vendor/") || starts_with(progname, "/apex/com.google."); + char prop_value[8]; + if (is_vendor_prog && get_property_value("persist.arm64.memtag.vendor", prop_value, sizeof(prop_value))) { + if (strcmp("1", prop_value) == 0) { + *level = M_HEAP_TAGGING_LEVEL_ASYNC; + return true; + } + } + const char* basename = __gnu_basename(progname); char options_str[PROP_VALUE_MAX]; From b67f2a80520626780cc152a93267d3873a7e189e Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 1 May 2024 16:39:36 +0300 Subject: [PATCH 29/51] enable heap memory tagging in vendor processes --- libc/bionic/libc_init_mte.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index 15927e6fc6f..cdd7a9f737e 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -112,6 +112,11 @@ static bool starts_with(const char* s, const char* prefix) { return strncmp(s, prefix, strlen(prefix)) == 0; } +static bool is_debuggable_build() { + char pv[8]; + return get_property_value("ro.debuggable", pv, sizeof(pv)) && strcmp(pv, "1") == 0; +} + // Returns true if there's an environment setting (either sysprop or env var) // that should overwrite the ELF note, and places the equivalent heap tagging // level into *level. @@ -124,13 +129,13 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { const char* progname = __libc_shared_globals()->init_progname; if (progname == nullptr) return false; - bool is_vendor_prog = starts_with(progname, "/vendor/") || starts_with(progname, "/apex/com.google."); - char prop_value[8]; - if (is_vendor_prog && get_property_value("persist.arm64.memtag.vendor", prop_value, sizeof(prop_value))) { - if (strcmp("1", prop_value) == 0) { - *level = M_HEAP_TAGGING_LEVEL_ASYNC; - return true; - } + const bool is_vendor_prog = starts_with(progname, "/vendor/") || starts_with(progname, "/apex/com.google."); + const bool is_debug_build = is_debuggable_build(); + if (is_vendor_prog) { + *level = M_HEAP_TAGGING_LEVEL_ASYNC; + if (!is_debug_build) { + return true; + } } const char* basename = __gnu_basename(progname); @@ -146,7 +151,7 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { if (!get_config_from_env_or_sysprops("MEMTAG_OPTIONS", sys_prop_names, arraysize(sys_prop_names), options_str, sizeof(options_str))) { - return false; + return is_vendor_prog; } if (strcmp("sync", options_str) == 0) { From 6a8d447483f87e1b760e032ed150907d71004437 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Wed, 1 May 2024 16:42:00 +0300 Subject: [PATCH 30/51] ignore heap memory tagging setting overrides on user builds --- libc/bionic/libc_init_mte.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index cdd7a9f737e..a991305803b 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -138,6 +138,11 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { } } + if (!is_debug_build) { + // ignore heap memory tagging setting overrides on user builds + return false; + } + const char* basename = __gnu_basename(progname); char options_str[PROP_VALUE_MAX]; From 3ae8ca3a1cc5d0b3f5382242fcfcc3ba2338b5d6 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 2 May 2023 16:47:49 +0300 Subject: [PATCH 31/51] disable hardened_malloc for Pixel camera provider service --- libc/bionic/libc_init_dynamic.cpp | 3 +++ libc/bionic/malloc_common.cpp | 3 +++ libc/include/stdlib.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index b8f14d2f550..44c760e6175 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -89,6 +89,9 @@ static void init_prog_id(libc_globals* globals) { #define IS(prog) (!strcmp(exe_path, prog)) + if (IS("/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google")) { + prog_id = PROG_PIXEL_CAMERA_PROVIDER_SERVICE; + } #undef IS // libc_globals struct is write-protected diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 032a0de98c6..42d5096a3d8 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -426,6 +426,9 @@ static const MallocDispatch* native_allocator_dispatch; void InitNativeAllocatorDispatch(libc_globals* globals) { bool hardened_impl = true; switch (get_prog_id()) { + case PROG_PIXEL_CAMERA_PROVIDER_SERVICE: + hardened_impl = false; + break; default: hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr; } diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 05381ed6a8c..8ccdf321019 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -530,6 +530,8 @@ long double strtold_l(const char* _Nonnull __s, char* _Nullable * _Nullable __en int get_prog_id(); #define is_prog(id) (get_prog_id() == id) +#define PROG_PIXEL_CAMERA_PROVIDER_SERVICE 1 + __END_DECLS #endif /* _STDLIB_H */ From bfd6878d1f0ccce2a93f2d48f1801c4a85c3d192 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 12 Dec 2023 20:37:48 +0200 Subject: [PATCH 32/51] disable hardened_malloc for surfaceflinger --- libc/bionic/libc_init_dynamic.cpp | 4 ++++ libc/bionic/malloc_common.cpp | 1 + libc/include/stdlib.h | 1 + 3 files changed, 6 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 44c760e6175..bf8f13bb537 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -92,6 +92,10 @@ static void init_prog_id(libc_globals* globals) { if (IS("/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google")) { prog_id = PROG_PIXEL_CAMERA_PROVIDER_SERVICE; } + else if (IS("/system/bin/surfaceflinger")) { + prog_id = PROG_SURFACEFLINGER; + } + #undef IS // libc_globals struct is write-protected diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 42d5096a3d8..084e4b55389 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -427,6 +427,7 @@ void InitNativeAllocatorDispatch(libc_globals* globals) { bool hardened_impl = true; switch (get_prog_id()) { case PROG_PIXEL_CAMERA_PROVIDER_SERVICE: + case PROG_SURFACEFLINGER: hardened_impl = false; break; default: diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 8ccdf321019..90b499abc60 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -531,6 +531,7 @@ int get_prog_id(); #define is_prog(id) (get_prog_id() == id) #define PROG_PIXEL_CAMERA_PROVIDER_SERVICE 1 +#define PROG_SURFACEFLINGER 2 __END_DECLS From 817522e98e4c2143ce1d1d673b2ba31d8cd7b471 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 15 Nov 2024 19:27:25 +0200 Subject: [PATCH 33/51] add libc_globals flag for disabling hardened_malloc --- libc/bionic/libc_init_dynamic.cpp | 2 ++ libc/bionic/malloc_common.cpp | 6 +++++- libc/private/bionic_globals.h | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index bf8f13bb537..9d0f5d578b8 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -86,6 +86,7 @@ static void init_prog_id(libc_globals* globals) { exe_path[readlink_res] = '\0'; int prog_id = 0; + int flags = 0; #define IS(prog) (!strcmp(exe_path, prog)) @@ -99,6 +100,7 @@ static void init_prog_id(libc_globals* globals) { #undef IS // libc_globals struct is write-protected + globals->flags = flags; globals->prog_id = prog_id; } diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 084e4b55389..5ecabd69109 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp @@ -431,7 +431,11 @@ void InitNativeAllocatorDispatch(libc_globals* globals) { hardened_impl = false; break; default: - hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr; + if (globals->flags & GLOBAL_FLAG_DISABLE_HARDENED_MALLOC) { + hardened_impl = false; + } else { + hardened_impl = getenv("DISABLE_HARDENED_MALLOC") == nullptr; + } } const MallocDispatch* table = hardened_impl ? diff --git a/libc/private/bionic_globals.h b/libc/private/bionic_globals.h index d97ec895db5..713ad4223ec 100644 --- a/libc/private/bionic_globals.h +++ b/libc/private/bionic_globals.h @@ -43,6 +43,8 @@ #include "private/bionic_malloc_dispatch.h" #include "private/bionic_vdso.h" +#define GLOBAL_FLAG_DISABLE_HARDENED_MALLOC 1 + struct libc_globals { vdso_entry vdso[VDSO_END]; long setjmp_cookie; @@ -68,6 +70,7 @@ struct libc_globals { int prog_id; bool is_sigchainlib_mte_sigsegv_interception_enabled; struct sigaction saved_sigabrt_handler; + int flags; }; struct memtag_dynamic_entries_t { From 3fc031c35763ccee8b003d21c32061745608ef29 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Fri, 15 Nov 2024 19:29:03 +0200 Subject: [PATCH 34/51] [temporary] disable hardened_malloc for vendor audio service --- libc/bionic/libc_init_dynamic.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 9d0f5d578b8..ce2b0973491 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -96,6 +96,10 @@ static void init_prog_id(libc_globals* globals) { else if (IS("/system/bin/surfaceflinger")) { prog_id = PROG_SURFACEFLINGER; } + else if (IS("/vendor/bin/hw/android.hardware.audio.service")) { + // needed for Pixel Tablet as of Android 15, see https://github.com/GrapheneOS/os-issue-tracker/issues/4306 + flags = GLOBAL_FLAG_DISABLE_HARDENED_MALLOC; + } #undef IS From d00315f71991a825517901107ae97139f838e17c Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Mon, 30 Jun 2025 14:38:45 +0000 Subject: [PATCH 35/51] userdebug: allow overriding hardened_malloc setting for vendor process --- libc/bionic/libc_init_dynamic.cpp | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index ce2b0973491..572a1dbad03 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -46,12 +46,26 @@ #include "bionic/pthread_internal.h" #include "libc_init_common.h" +#include "async_safe/log.h" #include "private/bionic_elf_tls.h" #include "private/bionic_globals.h" #include "platform/bionic/macros.h" #include "private/bionic_ssp.h" #include "private/bionic_tls.h" #include "private/KernelArgumentBlock.h" +#include "sys/system_properties.h" +#include "sysprop_helpers.h" + +static bool starts_with(const char* s, const char* prefix) { + return strncmp(s, prefix, strlen(prefix)) == 0; +} + +static bool is_debuggable_build() { + char pv[8]; + return get_property_value("ro.debuggable", pv, sizeof(pv)) && strcmp(pv, "1") == 0; +} + +extern "C" const char* __gnu_basename(const char* path); extern "C" { extern void netdClientInit(void); @@ -103,6 +117,24 @@ static void init_prog_id(libc_globals* globals) { #undef IS + bool is_debuggable = is_debuggable_build(); + const bool is_vendor_prog = starts_with(exe_path, "/vendor/") || starts_with(exe_path, "/apex/com.google."); + if (is_debuggable && is_vendor_prog) { + const char* basename = __gnu_basename(exe_path); + static const char propName[] = "persist.device_config.memory_safety_native.hardened_malloc.mode_override.process."; + char sysprop_name[512]; + char sysprop_value[PROP_VALUE_MAX] = {}; + async_safe_format_buffer(sysprop_name, sizeof(sysprop_name), "%s%s", propName, + basename); + get_property_value(sysprop_name, sysprop_value, sizeof(sysprop_value)); + if (strcmp("disabled", sysprop_value) == 0) { + flags = GLOBAL_FLAG_DISABLE_HARDENED_MALLOC; + } else if (strcmp("enabled", sysprop_value) == 0) { + prog_id = 0; + flags = 0; + } + } + // libc_globals struct is write-protected globals->flags = flags; globals->prog_id = prog_id; From 83f18cefdc62b14af4713a01cba8864c77182803 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Sat, 18 May 2024 11:22:48 +0300 Subject: [PATCH 36/51] disable memory tagging for Pixel camera provider service --- libc/bionic/libc_init_mte.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index a991305803b..ac9044d5111 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -132,8 +132,12 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { const bool is_vendor_prog = starts_with(progname, "/vendor/") || starts_with(progname, "/apex/com.google."); const bool is_debug_build = is_debuggable_build(); if (is_vendor_prog) { - *level = M_HEAP_TAGGING_LEVEL_ASYNC; - if (!is_debug_build) { + bool apply_override = + strcmp(progname, "/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google") != 0 + ; + if (apply_override) { + *level = M_HEAP_TAGGING_LEVEL_ASYNC; + } else if (!is_debug_build) { return true; } } From 1a05cccb17049d26c47096d6bc504de5e28767f6 Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:33:27 +0000 Subject: [PATCH 37/51] disable hardened_malloc for shared_modem_platform at 9th gen except tegu --- libc/bionic/libc_init_dynamic.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 572a1dbad03..d09ee083ab9 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -113,6 +113,16 @@ static void init_prog_id(libc_globals* globals) { else if (IS("/vendor/bin/hw/android.hardware.audio.service")) { // needed for Pixel Tablet as of Android 15, see https://github.com/GrapheneOS/os-issue-tracker/issues/4306 flags = GLOBAL_FLAG_DISABLE_HARDENED_MALLOC; + } else if (IS("/vendor/bin/shared_modem_platform")) { + char device_name[PROP_VALUE_MAX]; + get_property_value("ro.product.name", device_name, sizeof(device_name)); + if (strcmp(device_name, "tokay") == 0 + || strcmp(device_name, "caiman") == 0 + || strcmp(device_name, "komodo") == 0 + || strcmp(device_name, "comet") == 0 + ) { + flags = GLOBAL_FLAG_DISABLE_HARDENED_MALLOC; + } } #undef IS From 9373dcd5f6c4938bcda0ed0b2272c2d5eaded65b Mon Sep 17 00:00:00 2001 From: quh4gko8 <88831734+quh4gko8@users.noreply.github.com> Date: Mon, 30 Jun 2025 15:33:51 +0000 Subject: [PATCH 38/51] disable memory tagging for shared_modem_platform for 9th gen except tegu --- libc/bionic/libc_init_mte.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index ac9044d5111..4d46e23aa4f 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -132,8 +132,18 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { const bool is_vendor_prog = starts_with(progname, "/vendor/") || starts_with(progname, "/apex/com.google."); const bool is_debug_build = is_debuggable_build(); if (is_vendor_prog) { + char device_name[PROP_VALUE_MAX]; + get_property_value("ro.product.name", device_name, sizeof(device_name)); bool apply_override = strcmp(progname, "/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google") != 0 + && ( + ( + strcmp(device_name, "tokay") != 0 + && strcmp(device_name, "caiman") != 0 + && strcmp(device_name, "komodo") != 0 + && strcmp(device_name, "comet") != 0 + ) || strcmp(progname, "/vendor/bin/shared_modem_platform") != 0 + ) ; if (apply_override) { *level = M_HEAP_TAGGING_LEVEL_ASYNC; From 40ad99d6449c57caa815cc5622b5c83d777f9625 Mon Sep 17 00:00:00 2001 From: Renlord Date: Thu, 12 Sep 2019 14:51:51 +1000 Subject: [PATCH 39/51] add guard page(s) between static_tls and stack use page size for static TLS guard page --- libc/bionic/pthread_create.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 60b5b077234..3268fb45b6f 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -226,9 +226,13 @@ int __init_thread(pthread_internal_t* thread) { ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_size) { const StaticTlsLayout& layout = __libc_shared_globals()->static_tls_layout; - // Allocate in order: stack guard, stack, static TLS, libgen buffers, guard page. + // Address calculated using stack_size is passed to mprotect later, so make it page-aligned. + stack_size = __builtin_align_up(stack_size, page_size()); + + // Allocate in order: stack guard, stack, guard page, static TLS, libgen buffers, guard page. size_t mmap_size; if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {}; + if (__builtin_add_overflow(mmap_size, page_size(), &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {}; // Add space for the dedicated libgen buffers page(s). @@ -240,8 +244,8 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si mmap_size = __builtin_align_up(mmap_size, page_size()); if (mmap_size < unaligned_size) return {}; - // Create a new private anonymous map. Make the entire mapping PROT_NONE, then carve out a - // read+write area in the middle. + // Create a new private anonymous map. Make the entire mapping PROT_NONE, then carve out + // read+write areas in the middle. const int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; char* const space = static_cast(mmap(nullptr, mmap_size, PROT_NONE, flags, -1, 0)); if (space == MAP_FAILED) { @@ -250,7 +254,6 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si mmap_size); return {}; } - const size_t writable_size = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE; int prot = PROT_READ | PROT_WRITE; const char* prot_str = "R+W"; #ifdef __aarch64__ @@ -259,11 +262,23 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si prot_str = "R+W+MTE"; } #endif - if (mprotect(space + stack_guard_size, writable_size, prot) != 0) { + if (mprotect(space + stack_guard_size, stack_size, prot) != 0) { + async_safe_format_log( + ANDROID_LOG_WARN, "libc", + "pthread_create failed: couldn't mprotect %s %zu-byte stack mapping region: %m", prot_str, + stack_size); + munmap(space, mmap_size); + return {}; + } + + const size_t non_stack_writeable_offset = stack_guard_size + stack_size + page_size(); + const size_t non_stack_writeable_size = mmap_size - non_stack_writeable_offset - PTHREAD_GUARD_SIZE; + + if (mprotect(space + non_stack_writeable_offset, non_stack_writeable_size, PROT_READ | PROT_WRITE) != 0) { async_safe_format_log( ANDROID_LOG_WARN, "libc", - "pthread_create failed: couldn't mprotect %s %zu-byte thread mapping region: %m", prot_str, - writable_size); + "pthread_create failed: couldn't mprotect R+W %zu-byte non-stack mapping region: %m", + non_stack_writeable_size); munmap(space, mmap_size); return {}; } @@ -284,7 +299,7 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si result.libgen_buffers = space + mmap_size - PTHREAD_GUARD_SIZE - libgen_buffers_padded_size; result.static_tls = result.libgen_buffers - layout.size(); result.stack_base = space; - result.stack_top = result.static_tls; + result.stack_top = space + stack_guard_size + stack_size; return result; } From 9eadf2e42b71c1cd72284ad58eb5013c3c8bd211 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 11 Oct 2019 05:52:49 +0300 Subject: [PATCH 40/51] move pthread_internal_t behind guard page --- libc/bionic/pthread_create.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 3268fb45b6f..157e4a2515b 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -228,12 +228,16 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si // Address calculated using stack_size is passed to mprotect later, so make it page-aligned. stack_size = __builtin_align_up(stack_size, page_size()); + // Round up static TLS layout size to be multiple of page size as well. + size_t static_tls_layout_size = __builtin_align_up(layout.size(), page_size()); - // Allocate in order: stack guard, stack, guard page, static TLS, libgen buffers, guard page. + // Allocate in order: stack guard, stack, guard page, pthread_internal_t, static TLS, libgen buffers, guard page. size_t mmap_size; if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, page_size(), &mmap_size)) return {}; - if (__builtin_add_overflow(mmap_size, layout.size(), &mmap_size)) return {}; + size_t thread_page_size = __builtin_align_up(sizeof(pthread_internal_t), page_size()); + if (__builtin_add_overflow(mmap_size, thread_page_size, &mmap_size)) return {}; + if (__builtin_add_overflow(mmap_size, static_tls_layout_size, &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, PTHREAD_GUARD_SIZE, &mmap_size)) return {}; // Add space for the dedicated libgen buffers page(s). size_t libgen_buffers_padded_size = __builtin_align_up(sizeof(libgen_buffers), page_size()); @@ -287,7 +291,8 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si // // [ PTHREAD_GUARD_SIZE ] // [ libgen_buffers_padded_size (for dedicated page(s) for libgen buffers) ] - // [ layout.size() (for static TLS) ] + // [ static_tls_layout_size ] + // [ thread_page_size (for pthread_internal_t) ] // [ stack_size ] // [ stack_guard_size ] @@ -297,7 +302,7 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si result.mmap_base_unguarded = space + stack_guard_size; result.mmap_size_unguarded = mmap_size - stack_guard_size - PTHREAD_GUARD_SIZE; result.libgen_buffers = space + mmap_size - PTHREAD_GUARD_SIZE - libgen_buffers_padded_size; - result.static_tls = result.libgen_buffers - layout.size(); + result.static_tls = result.libgen_buffers - static_tls_layout_size; result.stack_base = space; result.stack_top = space + stack_guard_size + stack_size; return result; @@ -329,13 +334,8 @@ static int __allocate_thread(pthread_attr_t* attr, bionic_tcb** tcbp, void** chi stack_top = static_cast(attr->stack_base) + attr->stack_size; } - // Carve out space from the stack for the thread's pthread_internal_t. This - // memory isn't counted in pthread_attr_getstacksize. - - // To safely access the pthread_internal_t and thread stack, we need to find a 16-byte aligned boundary. - stack_top = __builtin_align_down(stack_top - sizeof(pthread_internal_t), 16); - - pthread_internal_t* thread = reinterpret_cast(stack_top); + pthread_internal_t* thread = reinterpret_cast( + mapping.static_tls - __builtin_align_up(sizeof(pthread_internal_t), page_size())); if (!stack_clean) { // If thread was not allocated by mmap(), it may not have been cleared to zero. // So assume the worst and zero it. From 43cdfd38148efb88b86fe53f8dacf5c2a90dd90c Mon Sep 17 00:00:00 2001 From: Renlord Date: Sun, 20 Oct 2019 00:17:11 +0300 Subject: [PATCH 41/51] add secondary stack randomization Signed-off-by: anupritaisno1 --- libc/bionic/pthread_create.cpp | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp index 157e4a2515b..a55c6cebba9 100644 --- a/libc/bionic/pthread_create.cpp +++ b/libc/bionic/pthread_create.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -231,10 +232,28 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si // Round up static TLS layout size to be multiple of page size as well. size_t static_tls_layout_size = __builtin_align_up(layout.size(), page_size()); - // Allocate in order: stack guard, stack, guard page, pthread_internal_t, static TLS, libgen buffers, guard page. + // Place a randomly sized gap above the stack, up to 10% as large as the stack + // on 32-bit and 50% on 64-bit where virtual memory is plentiful. +#if __LP64__ + size_t max_gap_size = stack_size / 2; +#else + size_t max_gap_size = stack_size / 10; +#endif + // Make sure the random stack top guard size is a multiple of the page size, + // and always reserve at least one guard page between the stack and the + // pthread_internal_t / static TLS region. arc4random_uniform() can return 0, + // and align_up(0, page_size) is 0, which would leave no guard page at all + // and let a stack overflow silently corrupt pthread_internal_t. + // + // For the main thread, the stack isn't in this mapping and we don't need to + // add a random gap. + size_t gap_size = __builtin_align_up(arc4random_uniform(max_gap_size), page_size()); + if (stack_size > 0 && gap_size == 0) gap_size = page_size(); + + // Allocate in order: stack guard, stack, (random) guard page(s), pthread_internal_t, static TLS, libgen buffers, guard page. size_t mmap_size; if (__builtin_add_overflow(stack_size, stack_guard_size, &mmap_size)) return {}; - if (__builtin_add_overflow(mmap_size, page_size(), &mmap_size)) return {}; + if (__builtin_add_overflow(mmap_size, gap_size, &mmap_size)) return {}; size_t thread_page_size = __builtin_align_up(sizeof(pthread_internal_t), page_size()); if (__builtin_add_overflow(mmap_size, thread_page_size, &mmap_size)) return {}; if (__builtin_add_overflow(mmap_size, static_tls_layout_size, &mmap_size)) return {}; @@ -266,6 +285,9 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si prot_str = "R+W+MTE"; } #endif + // Stack is at the lower end of mapped space, stack guard region is at the lower end of stack. + // Make the usable portion of the stack between the guard region and random gap readable and + // writable. if (mprotect(space + stack_guard_size, stack_size, prot) != 0) { async_safe_format_log( ANDROID_LOG_WARN, "libc", @@ -275,7 +297,7 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si return {}; } - const size_t non_stack_writeable_offset = stack_guard_size + stack_size + page_size(); + const size_t non_stack_writeable_offset = stack_guard_size + stack_size + gap_size; const size_t non_stack_writeable_size = mmap_size - non_stack_writeable_offset - PTHREAD_GUARD_SIZE; if (mprotect(space + non_stack_writeable_offset, non_stack_writeable_size, PROT_READ | PROT_WRITE) != 0) { @@ -293,6 +315,7 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si // [ libgen_buffers_padded_size (for dedicated page(s) for libgen buffers) ] // [ static_tls_layout_size ] // [ thread_page_size (for pthread_internal_t) ] + // [ gap_size (for (random) guard page(s)) ] // [ stack_size ] // [ stack_guard_size ] @@ -304,7 +327,10 @@ ThreadMapping __allocate_thread_mapping(size_t stack_size, size_t stack_guard_si result.libgen_buffers = space + mmap_size - PTHREAD_GUARD_SIZE - libgen_buffers_padded_size; result.static_tls = result.libgen_buffers - static_tls_layout_size; result.stack_base = space; - result.stack_top = space + stack_guard_size + stack_size; + // Choose a random base within the first page of the stack. Waste no more + // than the space originally wasted by pthread_internal_t for compatibility. + result.stack_top = space + stack_guard_size + stack_size - arc4random_uniform(sizeof(pthread_internal_t)); + result.stack_top = __builtin_align_down(result.stack_top, 16); return result; } From 48b48bb8dd4d6120441aa07ce91b6463f5612d6d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 29 Nov 2025 02:16:53 -0500 Subject: [PATCH 42/51] disable hardened_malloc for shared_modem_platform on 10th gen Pixels --- libc/bionic/libc_init_dynamic.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index d09ee083ab9..9cfb552d20c 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -120,6 +120,10 @@ static void init_prog_id(libc_globals* globals) { || strcmp(device_name, "caiman") == 0 || strcmp(device_name, "komodo") == 0 || strcmp(device_name, "comet") == 0 + || strcmp(device_name, "frankel") == 0 + || strcmp(device_name, "blazer") == 0 + || strcmp(device_name, "mustang") == 0 + || strcmp(device_name, "rango") == 0 ) { flags = GLOBAL_FLAG_DISABLE_HARDENED_MALLOC; } From 4616808dc66bc3d4f174f4382c59ba65c97ba4f3 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 29 Nov 2025 02:15:48 -0500 Subject: [PATCH 43/51] disable MTE for shared_modem_platform on 10th gen Pixels --- libc/bionic/libc_init_mte.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index 4d46e23aa4f..98d3c3b0788 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -142,6 +142,10 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { && strcmp(device_name, "caiman") != 0 && strcmp(device_name, "komodo") != 0 && strcmp(device_name, "comet") != 0 + && strcmp(device_name, "frankel") != 0 + && strcmp(device_name, "blazer") != 0 + && strcmp(device_name, "mustang") != 0 + && strcmp(device_name, "rango") != 0 ) || strcmp(progname, "/vendor/bin/shared_modem_platform") != 0 ) ; From 262be0697ae91c6fb80ec6d2f88496237cca873e Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 5 Mar 2026 21:19:44 +0000 Subject: [PATCH 44/51] disable hardened_malloc for shared_modem_platform on Pixel 10a --- libc/bionic/libc_init_dynamic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/bionic/libc_init_dynamic.cpp b/libc/bionic/libc_init_dynamic.cpp index 9cfb552d20c..949ffaa3ad7 100644 --- a/libc/bionic/libc_init_dynamic.cpp +++ b/libc/bionic/libc_init_dynamic.cpp @@ -120,6 +120,7 @@ static void init_prog_id(libc_globals* globals) { || strcmp(device_name, "caiman") == 0 || strcmp(device_name, "komodo") == 0 || strcmp(device_name, "comet") == 0 + || strcmp(device_name, "stallion") == 0 || strcmp(device_name, "frankel") == 0 || strcmp(device_name, "blazer") == 0 || strcmp(device_name, "mustang") == 0 From 0ce0b3a92643d9360124a8db7c39845ee16ad979 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 5 Mar 2026 21:19:54 +0000 Subject: [PATCH 45/51] disable MTE for shared_modem_platform on Pixel 10a --- libc/bionic/libc_init_mte.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index 98d3c3b0788..a8dfa2779b4 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -142,6 +142,7 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { && strcmp(device_name, "caiman") != 0 && strcmp(device_name, "komodo") != 0 && strcmp(device_name, "comet") != 0 + && strcmp(device_name, "stallion") != 0 && strcmp(device_name, "frankel") != 0 && strcmp(device_name, "blazer") != 0 && strcmp(device_name, "mustang") != 0 From 1de66ad481aed0ebaff2df24b99c8ac0d54e6878 Mon Sep 17 00:00:00 2001 From: inthewaves Date: Sun, 7 Jun 2026 22:11:50 -0700 Subject: [PATCH 46/51] fix h_malloc_wrapper integration for Cuttlefish builds Fixes build errors: error: frameworks/libs/native_bridge_support/android_api/libc/Android.bp:27:1: m odule "libnative_bridge_guest_libc" variant "android_native_bridge_arm64_armv8-a _static": module source path "frameworks/libs/native_bridge_support/android_api/ libc/bionic/h_malloc_wrapper.cpp" does not exist Test: lunch aosp_cf_x86_64_only_phone-cur-userdebug with hardened_malloc fix boots --- libc/Android.bp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libc/Android.bp b/libc/Android.bp index 2752d38cb79..1fd12a71d83 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -201,7 +201,7 @@ cc_defaults { ], }, lib64: { - srcs: ["bionic/h_malloc_wrapper.cpp"], + srcs: [":libc_h_malloc_wrapper_src"], cflags: [ "-DH_MALLOC_PREFIX", "-DUSE_H_MALLOC", @@ -227,7 +227,7 @@ cc_library_static { static_libs: ["libjemalloc5"], }, lib64: { - srcs: ["bionic/h_malloc_wrapper.cpp"], + srcs: [":libc_h_malloc_wrapper_src"], static_libs: ["libhardened_malloc"], }, }, @@ -1550,6 +1550,11 @@ cc_library_static { ], } +filegroup { + name: "libc_h_malloc_wrapper_src", + srcs: ["bionic/h_malloc_wrapper.cpp"], +} + filegroup { name: "libc_sources_shared", srcs: [ From c6dea151933d646d73275dfa15d20e1da452fa63 Mon Sep 17 00:00:00 2001 From: inthewaves Date: Fri, 19 Jun 2026 23:39:34 -0700 Subject: [PATCH 47/51] disable MTE for Widevine Rikers service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Widevine Rikers is the proprietary Widevine DRM HAL service. In the crash path, its internal resolver decodes requested symbol names such as signal, uses GNU hash metadata to find the matching libc .dynsym entry, and caches the resolved function pointer. The faulting PC is the resolver’s `ldg x8, [x8] instruction` at Rikers offset 0x11c51e8, where x8 points at execute-only libc text for `signal @@ LIBC`, causing SEGV_ACCERR when MTE is enabled. All the tests suites below have encountered failures with the SEGV_ACCERR prior to this commit. Test: atest CtsMediaDrmFrameworkTestCases Test: atest CtsVirtualDevicesAppLaunchTestCases:android.virtualdevice.cts.applaunch.VirtualDeviceDrmTest Test: atest VtsAidlHalDrmTargetTest (requires userdebug with locked bootloader) --- libc/bionic/libc_init_mte.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libc/bionic/libc_init_mte.cpp b/libc/bionic/libc_init_mte.cpp index a8dfa2779b4..a95891b5d32 100644 --- a/libc/bionic/libc_init_mte.cpp +++ b/libc/bionic/libc_init_mte.cpp @@ -136,6 +136,7 @@ static bool get_environment_memtag_setting(HeapTaggingLevel* level) { get_property_value("ro.product.name", device_name, sizeof(device_name)); bool apply_override = strcmp(progname, "/apex/com.google.pixel.camera.hal/bin/hw/android.hardware.camera.provider@2.7-service-google") != 0 + && strcmp(progname, "/apex/com.google.android.widevine/bin/hw/android.hardware.drm-service.widevine-rikers") != 0 && ( ( strcmp(device_name, "tokay") != 0 From 237d1b4483a4e6f7fcdc6f87e339280fcc1534ab Mon Sep 17 00:00:00 2001 From: maade93791 <70593890+maade69@users.noreply.github.com> Date: Fri, 1 May 2026 01:21:30 +0300 Subject: [PATCH 48/51] system_properties: add extended sysprop overrides the implementation is based on appcompat overrides, with several changes: * deny writes to a set of sysprops * inherit overrides from `ro.appcompat_override` --- libc/bionic/system_property_api.cpp | 5 +++ libc/include/sys/system_properties.h | 2 + libc/libc.map.txt | 1 + .../system_properties/system_properties.h | 2 + libc/system_properties/system_properties.cpp | 37 +++++++++++++++++++ 5 files changed, 47 insertions(+) diff --git a/libc/bionic/system_property_api.cpp b/libc/bionic/system_property_api.cpp index 34438e7afd1..580deeee31b 100644 --- a/libc/bionic/system_property_api.cpp +++ b/libc/bionic/system_property_api.cpp @@ -135,3 +135,8 @@ int __system_properties_zygote_reload(void) { CHECK(getpid() == gettid()); return system_properties.EnableOverrides() ? 0 : -1; } + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +int __system_properties_enable_extended_override(void) { + return system_properties.EnableExtendedOverrides() ? 0 : -1; +} diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h index 1e72bf47723..c07e3c2b59f 100644 --- a/libc/include/sys/system_properties.h +++ b/libc/include/sys/system_properties.h @@ -240,6 +240,8 @@ int __system_property_update(prop_info* _Nonnull __pi, const char* _Nonnull __va * Available since API level 35. */ int __system_properties_zygote_reload(void) __INTRODUCED_IN(35); + +int __system_properties_enable_extended_override(void); #endif /** diff --git a/libc/libc.map.txt b/libc/libc.map.txt index c77e540b4a7..ef349bb76eb 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1612,6 +1612,7 @@ LIBC_V { # introduced=35 tzfree; wcsrtombs_l; __system_properties_zygote_reload; # apex + __system_properties_enable_extended_override; # apex } LIBC_U; LIBC_36 { # introduced=36 diff --git a/libc/system_properties/include/system_properties/system_properties.h b/libc/system_properties/include/system_properties/system_properties.h index 6c3b1cd78d9..98c4a8df921 100644 --- a/libc/system_properties/include/system_properties/system_properties.h +++ b/libc/system_properties/include/system_properties/system_properties.h @@ -53,6 +53,7 @@ class SystemProperties { bool Init(const char* filename); bool EnableOverrides(); + bool EnableExtendedOverrides(); bool AreaInit(const char* filename, bool* fsetxattr_failed); bool AreaInit(const char* filename, bool* fsetxattr_failed, bool load_default_path); uint32_t AreaSerial(); @@ -91,6 +92,7 @@ class SystemProperties { bool initialized_; bool use_appcompat_override_; + bool use_extended_override_; PropertiesFilename properties_filename_; PropertiesFilename appcompat_filename_; }; diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp index ca286e8ee78..9043af363f9 100644 --- a/libc/system_properties/system_properties.cpp +++ b/libc/system_properties/system_properties.cpp @@ -53,6 +53,7 @@ #define SERIAL_VALUE_LEN(serial) ((serial) >> 24) #define APPCOMPAT_PREFIX "ro.appcompat_override." #define APPCOMPAT_OVERRIDE_ENV_VAR "BIONIC_APPCOMPAT_OVERRIDE" +#define EXTENDED_OVERRIDE_ENV_VAR "GOS_HIDE_CARRIER_INFO_PROP_OVERRIDE" static bool is_dir(const char* pathname) { struct stat info; @@ -81,6 +82,11 @@ bool SystemProperties::Init(const char* filename) { use_appcompat_override_ = true; } + if (getenv(EXTENDED_OVERRIDE_ENV_VAR) != nullptr) { + use_appcompat_override_ = true; + use_extended_override_ = true; + } + initialized_ = true; return true; } @@ -151,6 +157,33 @@ bool SystemProperties::EnableOverrides() { return true; } +bool SystemProperties::EnableExtendedOverrides() { + CHECK(initialized_); + use_appcompat_override_ = true; + use_extended_override_ = true; + putenv(const_cast(APPCOMPAT_OVERRIDE_ENV_VAR "=1")); + putenv(const_cast(EXTENDED_OVERRIDE_ENV_VAR "=1")); + return true; +} + +static const char* const kHideCarrierInfoDeniedProps[] = { + "gsm.sim.operator.alpha", + "gsm.sim.operator.numeric", + "gsm.sim.operator.iso-country", + "gsm.operator.alpha", + "gsm.operator.numeric", + "gsm.operator.iso-country", + "gsm.operator.isroaming", + "gsm.sim.state", +}; + +static bool is_hide_carrier_info_denied(const char* name) { + for (const char* denied : kHideCarrierInfoDeniedProps) { + if (strcmp(name, denied) == 0) return true; + } + return false; +} + uint32_t SystemProperties::AreaSerial() { if (!initialized_) { return -1; @@ -170,6 +203,10 @@ const prop_info* SystemProperties::Find(const char* name) { return nullptr; } + if (use_extended_override_ && is_hide_carrier_info_denied(name)) { + return nullptr; + } + // if appcompat override is enabled, we first try finding APPCOMPAT_PREFIXed system // property if (use_appcompat_override_) { From 3a2ae1faba5f299514bb5e889e55fa41f40d05ff Mon Sep 17 00:00:00 2001 From: maade93791 <70593890+maade69@users.noreply.github.com> Date: Thu, 25 Jun 2026 20:49:27 +0300 Subject: [PATCH 49/51] system_properties: when doing overrides update SERIAL_VALUE_LEN in new prop_info --- libc/system_properties/system_properties.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libc/system_properties/system_properties.cpp b/libc/system_properties/system_properties.cpp index 9043af363f9..42483e1b761 100644 --- a/libc/system_properties/system_properties.cpp +++ b/libc/system_properties/system_properties.cpp @@ -465,6 +465,11 @@ int SystemProperties::Add(const char* name, unsigned int namelen, const char* va CHECK(getpid() == 1 || getuid() == 0); atomic_thread_fence(memory_order_release); memcpy(other_pi->value, value, valuelen + 1); + // the high byte of serial encodes value length, we need to update it so readers + // (that use SERIAL_VALUE_LEN) return the full overridden string. + uint32_t old_serial = atomic_load_explicit(&other_pi->serial, memory_order_relaxed); + uint32_t new_serial = (valuelen << 24) | (old_serial & 0x00ffffff); + atomic_store_explicit(&other_pi->serial, new_serial, memory_order_release); } } From 76fec707a38009bf134b3138ee18789d815198e7 Mon Sep 17 00:00:00 2001 From: maade93791 <70593890+maade69@users.noreply.github.com> Date: Mon, 4 May 2026 01:57:57 +0300 Subject: [PATCH 50/51] add tests for extended sysprop overrides --- tests/system_properties_test.cpp | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp index b30c8fcfb77..cf9818922b6 100644 --- a/tests/system_properties_test.cpp +++ b/tests/system_properties_test.cpp @@ -227,6 +227,71 @@ TEST(properties, __system_property_getprop_appcompat) { #endif // __BIONIC__ } +TEST(properties, __system_property_add_extended_override) { +#if defined(__BIONIC__) + SystemPropertiesTest system_properties; + ASSERT_TRUE(system_properties.valid()); + + ASSERT_EQ(0, system_properties.Add("gsm.sim.operator.numeric", 24, "123456", 6)); + ASSERT_EQ(0, system_properties.Add("ro.other.prop", 13, "value", 5)); + + char propvalue[PROP_VALUE_MAX]; + + // before enabling: denied prop is readable + ASSERT_EQ(6, system_properties.Get("gsm.sim.operator.numeric", propvalue)); + ASSERT_STREQ(propvalue, "123456"); + ASSERT_NE(nullptr, system_properties.Find("gsm.sim.operator.numeric")); + + system_properties.EnableExtendedOverrides(); + + // after enabling: denied prop hidden from Find and Get + ASSERT_EQ(nullptr, system_properties.Find("gsm.sim.operator.numeric")); + ASSERT_EQ(0, system_properties.Get("gsm.sim.operator.numeric", propvalue)); + ASSERT_STREQ(propvalue, ""); + + // non-denied prop unaffected + ASSERT_EQ(5, system_properties.Get("ro.other.prop", propvalue)); + ASSERT_STREQ(propvalue, "value"); +#else // __BIONIC__ + GTEST_SKIP() << "bionic-only test"; +#endif // __BIONIC__ +} + +TEST(properties, __system_property_update_extended_override_denylist) { +#if defined(__BIONIC__) + SystemPropertiesTest system_properties; + ASSERT_TRUE(system_properties.valid()); + + ASSERT_EQ(0, system_properties.Add("gsm.sim.operator.numeric", 24, "123456", 6)); + ASSERT_EQ(0, system_properties.Add("gsm.version.baseband", 20, "v1", 2)); + + // capture prop_info* before enabling override (Find returns nullptr afterward for denied props) + const prop_info* denied_pi = system_properties.Find("gsm.sim.operator.numeric"); + ASSERT_NE(nullptr, denied_pi); + const prop_info* allowed_pi = system_properties.Find("gsm.version.baseband"); + ASSERT_NE(nullptr, allowed_pi); + + system_properties.EnableExtendedOverrides(); + + // update underlying values (as init would) + system_properties.Update(const_cast(denied_pi), "654321", 6); + system_properties.Update(const_cast(allowed_pi), "v2", 2); + + char propvalue[PROP_VALUE_MAX]; + + // denied prop still hidden after update + ASSERT_EQ(nullptr, system_properties.Find("gsm.sim.operator.numeric")); + ASSERT_EQ(0, system_properties.Get("gsm.sim.operator.numeric", propvalue)); + ASSERT_STREQ(propvalue, ""); + + // allowed prop updated normally + ASSERT_EQ(2, system_properties.Get("gsm.version.baseband", propvalue)); + ASSERT_STREQ(propvalue, "v2"); +#else // __BIONIC__ + GTEST_SKIP() << "bionic-only test"; +#endif // __BIONIC__ +} + TEST(properties, __system_property_update) { #if defined(__BIONIC__) SystemPropertiesTest system_properties; From 99fe6153a7e9d4519d279f51f45c760bebd674b1 Mon Sep 17 00:00:00 2001 From: maade93791 <70593890+maade69@users.noreply.github.com> Date: Mon, 4 May 2026 01:58:38 +0300 Subject: [PATCH 51/51] add a seperate target for sysprop tests --- tests/Android.bp | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/Android.bp b/tests/Android.bp index c5687625a8a..b806cee95d7 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -1322,6 +1322,54 @@ cc_test { ], } +// minial static binary for just the system properties tests +cc_test { + name: "bionic-sysprop-tests", + gtest: false, + defaults: [ + "bionic_tests_defaults", + "large_system_property_node_defaults", + ], + host_supported: false, + test_suites: ["general-tests"], + + srcs: [ + "gtest_globals.cpp", + "gtest_main.cpp", + "system_properties_test.cpp", + "utils.cpp", + ], + + include_dirs: [ + "bionic/libc", + ], + + target: { + bionic: { + whole_static_libs: [ + "libasync_safe", + "libprocinfo", + "libsystemproperties", + ], + }, + }, + + static_libs: [ + "libm", + "libc", + "libdl", + "liblog", + "libbase", + "libgtest_isolated", + ], + + static_executable: true, + stl: "libc++_static", + lto: { + never: true, + }, +} + // ----------------------------------------------------------------------------- // Tests to run on the host and linked against glibc. Run with: // cd bionic/tests; mm bionic-unit-tests-glibc-run