From e3ecba162e79cc0396cc93f5e954dc68f35516d3 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 2 Apr 2020 16:44:12 +0000 Subject: [PATCH] libpthread-416.60.2.tar.gz --- src/internal.h | 49 ++++++++++++++++++++++++++++----- src/pthread.c | 58 ++++++++++++++++++++++++++-------------- src/pthread_cancelable.c | 6 +++++ src/pthread_tsd.c | 4 ++- src/qos.c | 3 +++ 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/src/internal.h b/src/internal.h index daa2179..a98d86f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -70,12 +70,14 @@ typedef struct _pthread_attr_t pthread_attr_t; #include #include #include +#include #include #include #define __OS_EXPOSE_INTERNALS__ 1 #include #include +#include #if TARGET_IPHONE_SIMULATOR #error Unsupported target @@ -132,6 +134,8 @@ typedef os_unfair_lock _pthread_lock; extern int __is_threaded; extern int __unix_conforming; +PTHREAD_NOEXPORT +extern uintptr_t _pthread_ptr_munge_token; // List of all pthreads in the process. TAILQ_HEAD(__pthread_list, _pthread); @@ -176,7 +180,7 @@ typedef struct _pthread { // // ABI - These fields are externally known as struct _opaque_pthread_t. // - long sig; // _PTHREAD_SIG + long sig; struct __darwin_pthread_handler_rec *__cleanup_stack; // @@ -415,10 +419,17 @@ _Static_assert(sizeof(_pthread_rwlock) == sizeof(pthread_rwlock_t), "Incorrect _pthread_rwlock structure size"); // Internal references to pthread_self() use TSD slot 0 directly. -inline static pthread_t __attribute__((__pure__)) +__header_always_inline __pure2 pthread_t _pthread_self_direct(void) { - return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); +#if TARGET_OS_SIMULATOR || defined(__i386__) || defined(__x86_64__) + return (pthread_t)_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); +#elif defined(__arm__) || defined(__arm64__) + uintptr_t tsd_base = (uintptr_t)_os_tsd_get_base(); + return (pthread_t)(tsd_base - offsetof(struct _pthread, tsd)); +#else +#error unsupported architecture +#endif } #define pthread_self() _pthread_self_direct() @@ -681,6 +692,33 @@ _pthread_rwlock_check_signature_init(_pthread_rwlock *rwlock) return (rwlock->sig == _PTHREAD_RWLOCK_SIG_init); } +PTHREAD_ALWAYS_INLINE +static inline void +_pthread_validate_signature(pthread_t thread) +{ + pthread_t th = (pthread_t)(thread->sig ^ _pthread_ptr_munge_token); +#if __has_feature(ptrauth_calls) + th = ptrauth_auth_data(th, ptrauth_key_process_dependent_data, + ptrauth_string_discriminator("pthread.signature")); +#endif + if (os_unlikely(th != thread)) { + /* OS_REASON_LIBSYSTEM_CODE_PTHREAD_CORRUPTION == 4 */ + abort_with_reason(OS_REASON_LIBSYSTEM, 4, "pthread_t was corrupted", 0); + } +} + +PTHREAD_ALWAYS_INLINE +static inline void +_pthread_init_signature(pthread_t thread) +{ + pthread_t th = thread; +#if __has_feature(ptrauth_calls) + th = ptrauth_sign_unauthenticated(th, ptrauth_key_process_dependent_data, + ptrauth_string_discriminator("pthread.signature")); +#endif + thread->sig = (uintptr_t)th ^ _pthread_ptr_munge_token; +} + /* * ALWAYS called without list lock and return with list lock held on success * @@ -696,9 +734,7 @@ _pthread_validate_thread_and_list_lock(pthread_t thread) _PTHREAD_LOCK(_pthread_list_lock); TAILQ_FOREACH(p, &__pthread_head, tl_plist) { if (p != thread) continue; - if (os_unlikely(p->sig != _PTHREAD_SIG)) { - PTHREAD_CLIENT_CRASH(0, "pthread_t was corrupted"); - } + _pthread_validate_signature(p); return true; } _PTHREAD_UNLOCK(_pthread_list_lock); @@ -714,6 +750,7 @@ _pthread_is_valid(pthread_t thread, mach_port_t *portp) bool valid; if (thread == pthread_self()) { + _pthread_validate_signature(thread); valid = true; kport = _pthread_kernel_thread(thread); } else if (!_pthread_validate_thread_and_list_lock(thread)) { diff --git a/src/pthread.c b/src/pthread.c index 8eca496..a8729bb 100644 --- a/src/pthread.c +++ b/src/pthread.c @@ -186,7 +186,7 @@ static uint8_t min_priority; #endif // !VARIANT_DYLD static int _pthread_count = 1; static int pthread_concurrency; -static uintptr_t _pthread_ptr_munge_token; +uintptr_t _pthread_ptr_munge_token; static void (*exitf)(int) = __exit; #if !VARIANT_DYLD @@ -887,6 +887,7 @@ _pthread_start(pthread_t self, mach_port_t kport, } PTHREAD_DEBUG_ASSERT(MACH_PORT_VALID(kport)); PTHREAD_DEBUG_ASSERT(_pthread_kernel_thread(self) == kport); + _pthread_validate_signature(self); _pthread_markcancel_if_canceled(self, kport); _pthread_set_self_internal(self); @@ -899,9 +900,7 @@ static inline void _pthread_struct_init(pthread_t t, const pthread_attr_t *attrs, void *stackaddr, size_t stacksize, void *freeaddr, size_t freesize) { - PTHREAD_DEBUG_ASSERT(t->sig != _PTHREAD_SIG); - - t->sig = _PTHREAD_SIG; + _pthread_init_signature(t); t->tsd[_PTHREAD_TSD_SLOT_PTHREAD_SELF] = t; t->tsd[_PTHREAD_TSD_SLOT_ERRNO] = &t->err_no; if (attrs->schedset == 0) { @@ -1209,6 +1208,8 @@ pthread_setname_np(const char *name) len = strlen(name); } + _pthread_validate_signature(self); + /* protytype is in pthread_internals.h */ res = __proc_info(5, getpid(), 2, (uint64_t)0, (void*)name, (int)len); if (res == 0) { @@ -1478,6 +1479,7 @@ pthread_exit(void *exit_value) PTHREAD_CLIENT_CRASH(0, "pthread_exit() called from a thread " "not created by pthread_create()"); } + _pthread_validate_signature(self); _pthread_exit(self, exit_value); } @@ -1542,6 +1544,7 @@ pthread_setschedparam(pthread_t t, int policy, const struct sched_param *param) // since the main thread will not get de-allocated from underneath us if (t == pthread_self() || t == main_thread()) { + _pthread_validate_signature(t); kport = _pthread_kernel_thread(t); } else { bypass = 0; @@ -1782,19 +1785,32 @@ static void parse_ptr_munge_params(const char *envp[], const char *apple[]) { const char *p, *s; + uintptr_t token = 0; p = _simple_getenv(apple, "ptr_munge"); if (p) { - _pthread_ptr_munge_token = _pthread_strtoul(p, &s, 16); + token = _pthread_strtoul(p, &s, 16); bzero((char *)p, strlen(p)); } #if !DEBUG - if (_pthread_ptr_munge_token) return; + if (!token) { #endif - p = _simple_getenv(envp, "PTHREAD_PTR_MUNGE_TOKEN"); - if (p) { - uintptr_t t = _pthread_strtoul(p, &s, 16); - if (t) _pthread_ptr_munge_token = t; + p = _simple_getenv(envp, "PTHREAD_PTR_MUNGE_TOKEN"); + if (p) { + uintptr_t t = _pthread_strtoul(p, &s, 16); + if (t) token = t; + } +#if !DEBUG + } + + if (!token) { + PTHREAD_INTERNAL_CRASH(token, "Token from the kernel is 0"); } +#endif // DEBUG + + _pthread_ptr_munge_token = token; + // we need to refresh the main thread signature now that we changed + // the munge token. We need to do it while TSAN will not look at it + _pthread_init_signature(_main_thread_ptr); } int @@ -1812,6 +1828,18 @@ __pthread_init(const struct _libpthread_functions *pthread_funcs, } } + // libpthread.a in dyld "owns" the main thread structure itself and sets + // up the tsd to point to it. So take the pthread_self() from there + // and make it our main thread point. + pthread_t thread = (pthread_t)_pthread_getspecific_direct( + _PTHREAD_TSD_SLOT_PTHREAD_SELF); + if (os_unlikely(thread == NULL)) { + PTHREAD_INTERNAL_CRASH(0, "PTHREAD_SELF TSD not initialized"); + } + _main_thread_ptr = thread; + // this needs to be done early so that pthread_self() works in TSAN + _pthread_init_signature(thread); + // // Get host information // @@ -1860,16 +1888,6 @@ __pthread_init(const struct _libpthread_functions *pthread_funcs, // Initialize random ptr_munge token from the kernel. parse_ptr_munge_params(envp, apple); - // libpthread.a in dyld "owns" the main thread structure itself and sets - // up the tsd to point to it. So take the pthread_self() from there - // and make it our main thread point. - pthread_t thread = (pthread_t)_pthread_getspecific_direct( - _PTHREAD_TSD_SLOT_PTHREAD_SELF); - if (os_unlikely(thread == NULL)) { - PTHREAD_INTERNAL_CRASH(0, "PTHREAD_SELF TSD not initialized"); - } - _main_thread_ptr = thread; - PTHREAD_DEBUG_ASSERT(_pthread_attr_default.qosclass == _pthread_default_priority(0)); _pthread_struct_init(thread, &_pthread_attr_default, diff --git a/src/pthread_cancelable.c b/src/pthread_cancelable.c index 3df57a7..f209672 100644 --- a/src/pthread_cancelable.c +++ b/src/pthread_cancelable.c @@ -158,6 +158,7 @@ _pthread_exit_if_canceled(int error) if (((error & 0xff) == EINTR) && __unix_conforming && (__pthread_canceled(0) == 0)) { pthread_t self = pthread_self(); + _pthread_validate_signature(self); self->cancel_error = error; self->canceled = true; pthread_exit(PTHREAD_CANCELED); @@ -179,6 +180,7 @@ _pthread_testcancel(int isconforming) { pthread_t self = pthread_self(); if (_pthread_is_canceled(self)) { + _pthread_validate_signature(self); // 4597450: begin self->canceled = (isconforming != PTHREAD_CONFORM_DARWIN_LEGACY); // 4597450: end @@ -218,6 +220,8 @@ _pthread_setcancelstate_internal(int state, int *oldstateptr, int conforming) { pthread_t self = pthread_self(); + _pthread_validate_signature(self); + switch (state) { case PTHREAD_CANCEL_ENABLE: if (conforming) { @@ -276,6 +280,7 @@ pthread_setcanceltype(int type, int *oldtype) (type != PTHREAD_CANCEL_ASYNCHRONOUS)) return EINVAL; self = pthread_self(); + _pthread_validate_signature(self); int oldstate = _pthread_update_cancel_state(self, _PTHREAD_CANCEL_TYPE_MASK, type); if (oldtype) { *oldtype = oldstate & _PTHREAD_CANCEL_TYPE_MASK; @@ -448,6 +453,7 @@ _pthread_join(pthread_t thread, void **value_ptr, int conforming) if (!_pthread_validate_thread_and_list_lock(thread)) { return ESRCH; } + _pthread_validate_signature(self); if (!thread->tl_joinable || (thread->tl_join_ctx != NULL)) { res = EINVAL; diff --git a/src/pthread_tsd.c b/src/pthread_tsd.c index b8e5d1a..c76bba6 100644 --- a/src/pthread_tsd.c +++ b/src/pthread_tsd.c @@ -377,5 +377,7 @@ pthread_key_init_np(int key, void (*destructor)(void *)) pthread_t pthread_self(void) { - return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); + pthread_t self = _pthread_self_direct(); + _pthread_validate_signature(self); + return self; } diff --git a/src/qos.c b/src/qos.c index 039b06b..dea72f8 100644 --- a/src/qos.c +++ b/src/qos.c @@ -146,6 +146,7 @@ pthread_set_qos_class_np(pthread_t thread, qos_class_t qc, int relpri) */ return EPERM; } + _pthread_validate_signature(thread); return pthread_set_qos_class_self_np(qc, relpri); } @@ -219,6 +220,8 @@ _pthread_set_properties_self(_pthread_set_flags_t flags, _pthread_set_flags_t kflags = flags; int rv = 0; + _pthread_validate_signature(self); + if (self->wq_outsideqos && (flags & _PTHREAD_SET_SELF_OUTSIDE_QOS_SKIP)) { // A number of properties cannot be altered if we are a workloop // thread that has outside of QoS properties applied to it. -- 2.45.2