#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
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);
//
// ABI - These fields are externally known as struct _opaque_pthread_t.
//
- long sig; // _PTHREAD_SIG
+ long sig;
struct __darwin_pthread_handler_rec *__cleanup_stack;
//
"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()
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
*
_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);
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)) {
#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
}
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);
_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) {
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) {
PTHREAD_CLIENT_CRASH(0, "pthread_exit() called from a thread "
"not created by pthread_create()");
}
+ _pthread_validate_signature(self);
_pthread_exit(self, exit_value);
}
// 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;
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
}
}
+ // 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
//
// 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,
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);
{
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
{
pthread_t self = pthread_self();
+ _pthread_validate_signature(self);
+
switch (state) {
case PTHREAD_CANCEL_ENABLE:
if (conforming) {
(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;
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;
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;
}
*/
return EPERM;
}
+ _pthread_validate_signature(thread);
return pthread_set_qos_class_self_np(qc, relpri);
}
_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.