tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }