// Check if we're looking for ourselves before acquiring the lock. if (thread == __get_thread()) return thread;
{ // Make sure to release the lock before the abort below. Otherwise, // some apps might deadlock in their own crash handlers (see b/6565627).
ScopedReadLock locker(&g_thread_list_lock); for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { if (t == thread) return thread;
}
}
// Historically we'd return null, but from API level 26 we catch this error. if (android_get_application_target_sdk_version() >= 26) { if (thread == nullptr) { // This seems to be a common mistake, and it's relatively harmless because // there will never be a valid thread at address 0, whereas other invalid // addresses might sometimes contain threads or things that look enough like // threads for us to do some real damage by continuing. // TODO: try getting rid of this when Treble lets us keep vendor blobs on an old API level.
async_safe_format_log(ANDROID_LOG_WARN, "libc", "invalid pthread_t (0) passed to %s", caller);
} else {
async_safe_fatal("invalid pthread_t %p passed to %s", thread, caller);
}
} return nullptr;
}
static uintptr_t __get_main_stack_startstack() {
FILE* fp = fopen("/proc/self/stat", "re"); if (fp == nullptr) {
async_safe_fatal("couldn't open /proc/self/stat: %m");
}
// See man 5 proc. There's no reason comm can't contain ' ' or ')', // so we search backwards for the end of it. We're looking for this field: // // startstack %lu (28) The address of the start (i.e., bottom) of the stack.
uintptr_t startstack = 0; constchar* end_of_comm = strrchr(line, ')'); if (sscanf(end_of_comm + 1, " %*c " "%*d %*d %*d %*d %*d " "%*u %*u %*u %*u %*u %*u %*u " "%*d %*d %*d %*d %*d %*d " "%*u %*u %*d %*u %*u %*u %" SCNuPTR,
&startstack) != 1) {
async_safe_fatal("couldn't parse /proc/self/stat");
}
return startstack;
}
void __find_main_stack_limits(uintptr_t* low, uintptr_t* high) { // Ask the kernel where our main thread's stack started.
uintptr_t startstack = __get_main_stack_startstack();
// Hunt for the region that contains that address.
FILE* fp = fopen("/proc/self/maps", "re"); if (fp == nullptr) {
async_safe_fatal("couldn't open /proc/self/maps: %m");
} char line[BUFSIZ] __attribute__((__uninitialized__)); while (fgets(line, sizeof(line), fp) != nullptr) {
uintptr_t lo, hi; if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) { if (lo <= startstack && startstack <= hi) {
*low = lo;
*high = hi;
fclose(fp); return;
}
}
}
async_safe_fatal("stack not found in /proc/self/maps");
}
#ifdefined(__aarch64__)
__LIBC_HIDDEN__ void* __allocate_stack_mte_ringbuffer(size_t n, pthread_internal_t* thread) { constchar* name; if (thread == nullptr) {
name = "stack_mte_ring:main";
} else { // The kernel doesn't copy the name string, but this variable will last at least as long as the // mapped area. We unmap the ring buffer before unmapping the rest of the thread storage. auto& name_buffer = thread->stack_mte_ringbuffer_vma_name_buffer;
static_assert(arraysize(name_buffer) >= arraysize("stack_mte_ring:") + 11 + 1);
async_safe_format_buffer(name_buffer, arraysize(name_buffer), "stack_mte_ring:%d", thread->tid);
name = name_buffer;
} void* ret = stack_mte_ringbuffer_allocate(n, name); if (!ret) async_safe_fatal("error: failed to allocate stack mte ring buffer"); return ret;
} #endif
bool __pthread_internal_remap_stack_with_mte() { #ifdefined(__aarch64__)
ScopedWriteLock creation_locker(&g_thread_creation_lock);
ScopedReadLock list_locker(&g_thread_list_lock); // If process already uses memtag-stack ABI, we don't need to do anything. if (__libc_memtag_stack_abi) returnfalse;
__libc_memtag_stack_abi = true;
for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { // should_allocate_stack_mte_ringbuffer indicates the thread is already // aware that this process requires stack MTE, and will allocate the // ring buffer in __pthread_start. if (t->terminating || t->should_allocate_stack_mte_ringbuffer) continue;
t->bionic_tcb->tls_slot(TLS_SLOT_STACK_MTE) =
__allocate_stack_mte_ringbuffer(0, t->is_main() ? nullptr : t);
} if (!atomic_load(&__libc_globals->memtag)) returnfalse; if (atomic_exchange(&__libc_memtag_stack, true)) returnfalse;
uintptr_t lo, hi;
__find_main_stack_limits(&lo, &hi);
if (mprotect(reinterpret_cast<void*>(lo), hi - lo,
PROT_READ | PROT_WRITE | PROT_MTE | PROT_GROWSDOWN)) {
async_safe_fatal("error: failed to set PROT_MTE on main thread");
} for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { if (t->terminating || t->is_main()) continue; if (mprotect(t->mmap_base_unguarded, t->mmap_size_unguarded,
PROT_READ | PROT_WRITE | PROT_MTE)) {
async_safe_fatal("error: failed to set PROT_MTE on thread: %d", t->tid);
}
} returntrue; #else returnfalse; #endif// defined(__aarch64__)
}
bool android_run_on_all_threads(bool (*func)(void*), void* arg) { // Take the locks in this order to avoid inversion (pthread_create -> // __pthread_internal_add).
ScopedWriteLock creation_locker(&g_thread_creation_lock);
ScopedReadLock list_locker(&g_thread_list_lock);
// Call the function directly for the current thread so that we don't need to worry about // the consequences of synchronizing with ourselves. if (!func(arg)) { returnfalse;
}
pid_t my_pid = getpid();
size_t num_tids = 0; for (pthread_internal_t* t = g_thread_list; t != nullptr; t = t->next) { // The function is called directly for the current thread above, so no need to send a signal to // ourselves to call it here. if (t == __get_thread()) continue;
// If a thread is terminating (has blocked signals) or has already terminated, our signal will // never be received, so we need to check for that condition and skip the thread if it is the // case. if (atomic_load(&t->terminating)) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.