pthread_create_interposer.cpp (3169B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include <algorithm> 6 7 #include <pthread.h> 8 #include <signal.h> 9 #include <stdlib.h> 10 #include <sys/mman.h> 11 12 #include "mozilla/Assertions.h" 13 #include "mozilla/DebugOnly.h" 14 15 #include "InterposerHelper.h" 16 17 using mozilla::DebugOnly; 18 19 struct SigAltStack { 20 void* mem; 21 size_t size; 22 }; 23 24 struct PthreadCreateParams { 25 void* (*start_routine)(void*); 26 void* arg; 27 }; 28 29 // Install the alternate signal stack, returns a pointer to the memory area we 30 // mapped to store the stack only if it was installed successfully, otherwise 31 // returns NULL. 32 static void* install_sig_alt_stack(size_t size) { 33 void* alt_stack_mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, 34 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 35 if (alt_stack_mem) { 36 stack_t alt_stack = { 37 .ss_sp = alt_stack_mem, 38 .ss_flags = 0, 39 .ss_size = size, 40 }; 41 42 int rv = sigaltstack(&alt_stack, nullptr); 43 if (rv == 0) { 44 return alt_stack_mem; 45 } 46 47 rv = munmap(alt_stack_mem, size); 48 MOZ_ASSERT(rv == 0); 49 } 50 51 return nullptr; 52 } 53 54 // Uninstall the alternate signal handler and unmaps it. Does nothing if 55 // alt_stack_mem is NULL. 56 static void uninstall_sig_alt_stack(void* alt_stack_ptr) { 57 SigAltStack* alt_stack = static_cast<SigAltStack*>(alt_stack_ptr); 58 if (alt_stack->mem) { 59 stack_t disable_alt_stack = {}; 60 disable_alt_stack.ss_flags = SS_DISABLE; 61 DebugOnly<int> rv = sigaltstack(&disable_alt_stack, nullptr); 62 MOZ_ASSERT(rv == 0); 63 rv = munmap(alt_stack->mem, alt_stack->size); 64 MOZ_ASSERT(rv == 0); 65 } 66 } 67 68 // This replaces the routine passed to pthread_create() when a thread is 69 // started, it handles the alternate signal stack and calls the thread's 70 // actual routine. 71 void* set_alt_signal_stack_and_start(PthreadCreateParams* params) { 72 void* (*start_routine)(void*) = params->start_routine; 73 void* arg = params->arg; 74 free(params); 75 76 void* thread_rv = nullptr; 77 static const size_t kSigStackSize = std::max(size_t(16384), size_t(SIGSTKSZ)); 78 void* alt_stack_mem = install_sig_alt_stack(kSigStackSize); 79 SigAltStack alt_stack{alt_stack_mem, kSigStackSize}; 80 pthread_cleanup_push(uninstall_sig_alt_stack, &alt_stack); 81 thread_rv = start_routine(arg); 82 pthread_cleanup_pop(1); 83 84 return thread_rv; 85 } 86 87 extern "C" { 88 // This interposer replaces libpthread's pthread_create() so that we can 89 // inject an alternate signal stack in every new thread. 90 MFBT_API int pthread_create(pthread_t* thread, const pthread_attr_t* attr, 91 void* (*start_routine)(void*), void* arg) { 92 static const auto real_pthread_create = GET_REAL_SYMBOL(pthread_create); 93 94 PthreadCreateParams* params = 95 (PthreadCreateParams*)malloc(sizeof(PthreadCreateParams)); 96 params->start_routine = start_routine; 97 params->arg = arg; 98 99 int result = real_pthread_create( 100 thread, attr, (void* (*)(void*))set_alt_signal_stack_and_start, params); 101 102 if (result != 0) { 103 free(params); 104 } 105 106 return result; 107 } 108 }