]> git.saurik.com Git - apple/libpthread.git/commitdiff
libpthread-416.60.2.tar.gz macos-10152 macos-10153 v416.60.2
authorApple <opensource@apple.com>
Thu, 2 Apr 2020 16:44:12 +0000 (16:44 +0000)
committerApple <opensource@apple.com>
Thu, 2 Apr 2020 16:44:12 +0000 (16:44 +0000)
src/internal.h
src/pthread.c
src/pthread_cancelable.c
src/pthread_tsd.c
src/qos.c

index daa2179040879b42efa5880e36e4d99e38e8e7fb..a98d86f17ee710e16102cc4571d3288c5ad83314 100644 (file)
@@ -70,12 +70,14 @@ typedef struct _pthread_attr_t pthread_attr_t;
 #include <mach/mach.h>
 #include <mach/mach_error.h>
 #include <sys/queue.h>
+#include <sys/reason.h>
 #include <pthread/bsdthread_private.h>
 #include <pthread/workqueue_syscalls.h>
 
 #define __OS_EXPOSE_INTERNALS__ 1
 #include <os/internal/internal_shared.h>
 #include <os/once_private.h>
+#include <os/reason_private.h>
 
 #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)) {
index 8eca496e496194d7436954bfbc69798d8a9631da..a8729bbf60c8daab9fc0ff3b52339b24a2148f76 100644 (file)
@@ -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,
index 3df57a7953cab52c7704b02f6c6e58baa3d6fc29..f2096722c632d01439d6e0f96481801d21de60b4 100644 (file)
@@ -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;
index b8e5d1aeef0dc3ce826a13fe94cea2547f5b5f2a..c76bba69b05f1140b1372729a516630a6369ae70 100644 (file)
@@ -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;
 }
index 039b06baa73c5afffa0d215eb2ad5f05c241bdc4..dea72f89a5d1171c309e98821d115a83d8b9a1da 100644 (file)
--- 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.