diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /toolkit/crashreporter/pthread_create_interposer | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/crashreporter/pthread_create_interposer')
-rw-r--r-- | toolkit/crashreporter/pthread_create_interposer/moz.build | 12 | ||||
-rw-r--r-- | toolkit/crashreporter/pthread_create_interposer/pthread_create_interposer.cpp | 125 |
2 files changed, 137 insertions, 0 deletions
diff --git a/toolkit/crashreporter/pthread_create_interposer/moz.build b/toolkit/crashreporter/pthread_create_interposer/moz.build new file mode 100644 index 0000000000..d0ff4cae00 --- /dev/null +++ b/toolkit/crashreporter/pthread_create_interposer/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +Library("pthread_create_interposer") + +NoVisibilityFlags() + +UNIFIED_SOURCES += [ + "pthread_create_interposer.cpp", +] diff --git a/toolkit/crashreporter/pthread_create_interposer/pthread_create_interposer.cpp b/toolkit/crashreporter/pthread_create_interposer/pthread_create_interposer.cpp new file mode 100644 index 0000000000..e3ba6b164f --- /dev/null +++ b/toolkit/crashreporter/pthread_create_interposer/pthread_create_interposer.cpp @@ -0,0 +1,125 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <algorithm> + +#include <dlfcn.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/mman.h> + +#include "mozilla/Assertions.h" +#include "mozilla/DebugOnly.h" + +using mozilla::DebugOnly; + +struct SigAltStack { + void* mem; + size_t size; +}; + +struct PthreadCreateParams { + void* (*start_routine)(void*); + void* arg; +}; + +// Install the alternate signal stack, returns a pointer to the memory area we +// mapped to store the stack only if it was installed successfully, otherwise +// returns NULL. +static void* install_sig_alt_stack(size_t size) { + void* alt_stack_mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (alt_stack_mem) { + stack_t alt_stack = { + .ss_sp = alt_stack_mem, + .ss_flags = 0, + .ss_size = size, + }; + + int rv = sigaltstack(&alt_stack, nullptr); + if (rv == 0) { + return alt_stack_mem; + } + + rv = munmap(alt_stack_mem, size); + MOZ_ASSERT(rv == 0); + } + + return nullptr; +} + +// Uninstall the alternate signal handler and unmaps it. Does nothing if +// alt_stack_mem is NULL. +static void uninstall_sig_alt_stack(void* alt_stack_ptr) { + SigAltStack* alt_stack = static_cast<SigAltStack*>(alt_stack_ptr); + if (alt_stack->mem) { + stack_t disable_alt_stack = {}; + disable_alt_stack.ss_flags = SS_DISABLE; + DebugOnly<int> rv = sigaltstack(&disable_alt_stack, nullptr); + MOZ_ASSERT(rv == 0); + rv = munmap(alt_stack->mem, alt_stack->size); + MOZ_ASSERT(rv == 0); + } +} + +// This replaces the routine passed to pthread_create() when a thread is +// started, it handles the alternate signal stack and calls the thread's +// actual routine. +void* set_alt_signal_stack_and_start(PthreadCreateParams* params) { + void* (*start_routine)(void*) = params->start_routine; + void* arg = params->arg; + free(params); + + void* thread_rv = nullptr; + static const size_t kSigStackSize = std::max(size_t(16384), size_t(SIGSTKSZ)); + void* alt_stack_mem = install_sig_alt_stack(kSigStackSize); + SigAltStack alt_stack{alt_stack_mem, kSigStackSize}; + pthread_cleanup_push(uninstall_sig_alt_stack, &alt_stack); + thread_rv = start_routine(arg); + pthread_cleanup_pop(1); + + return thread_rv; +} + +using pthread_create_func_t = int (*)(pthread_t*, const pthread_attr_t*, + void* (*)(void*), void*); + +extern "C" { +// This interposer replaces libpthread's pthread_create() so that we can +// inject an alternate signal stack in every new thread. +__attribute__((visibility("default"))) int pthread_create( + pthread_t* thread, const pthread_attr_t* attr, + void* (*start_routine)(void*), void* arg) { + // static const pthread_create_func_t real_pthread_create = + static const pthread_create_func_t real_pthread_create = + (pthread_create_func_t)dlsym(RTLD_NEXT, "pthread_create"); + + if (real_pthread_create == nullptr) { + MOZ_CRASH( + "pthread_create() interposition failed but the interposer function is " + "still being called, this won't work!"); + } + + if (real_pthread_create == pthread_create) { + MOZ_CRASH( + "We could not obtain the real pthread_create(). Calling the symbol we " + "got would make us enter an infinte loop so stop here instead."); + } + + PthreadCreateParams* params = + (PthreadCreateParams*)malloc(sizeof(PthreadCreateParams)); + params->start_routine = start_routine; + params->arg = arg; + + int result = real_pthread_create( + thread, attr, (void* (*)(void*))set_alt_signal_stack_and_start, params); + + if (result != 0) { + free(params); + } + + return result; +} +} |