From 6bc7929d0598cacceeeecbb5e1e926dea4aa03cb Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:53:31 -0500 Subject: [PATCH] Some signal safety and refactoring, also don't LD_PRELOAD for the tracer program (#4) --- libSegFault/config.cpp | 11 ------- libSegFault/config.hpp | 1 - libSegFault/segfault.cpp | 8 +++-- libSegFault/signal-safe-trace.cpp | 50 ++++++++++++++++++++++++++----- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/libSegFault/config.cpp b/libSegFault/config.cpp index 844f15d..03b993f 100644 --- a/libSegFault/config.cpp +++ b/libSegFault/config.cpp @@ -1,17 +1,6 @@ #include #include -const char *getTracerProgram() -{ - static const char *emptystr = ""; - if (const char *value = getenv("LIBSEGFAULT_TRACER")) - { - return value; - } - - return emptystr; -} - bool isDebugMode() { if (const char *value = getenv("LIBSEGFAULT_DEBUG")) diff --git a/libSegFault/config.hpp b/libSegFault/config.hpp index 7a4a23a..25c0691 100644 --- a/libSegFault/config.hpp +++ b/libSegFault/config.hpp @@ -1,7 +1,6 @@ #pragma once bool isDebugMode(); -const char *getTracerProgram(); bool useAlternativeStack(); bool dumpRegisters(); bool dumpMemory(); diff --git a/libSegFault/segfault.cpp b/libSegFault/segfault.cpp index 8733f0c..722fd9d 100644 --- a/libSegFault/segfault.cpp +++ b/libSegFault/segfault.cpp @@ -32,8 +32,8 @@ #include #include -#include "signal-safe-trace.hpp" #include "config.hpp" +#include "signal-safe-trace.hpp" #ifdef SA_SIGINFO #define SIGCONTEXT siginfo_t *info, void * @@ -59,6 +59,8 @@ static void write_strsignal(int fd, int signal) TEMP_FAILURE_RETRY(write(fd, ptr, &buf[sizeof(buf)] - ptr)); } +const auto dump_registers = dumpRegisters(); +const auto dump_memory = dumpMemory(); /* This function is called when a segmentation fault is caught. The system is in an unstable state now. This means especially that malloc() might @@ -85,7 +87,7 @@ static void catch_segfault(int signal, SIGCONTEXT ctx) WRITE_STRING("\n"); #ifdef REGISTER_DUMP - if (dumpRegisters()) + if (dump_registers) { REGISTER_DUMP; } @@ -96,7 +98,7 @@ static void catch_segfault(int signal, SIGCONTEXT ctx) do_signal_safe_trace(); #ifdef HAVE_PROC_SELF - if (dumpMemory()) + if (dump_memory) { /* Now the link map. */ int mapfd = open("/proc/self/maps", O_RDONLY); diff --git a/libSegFault/signal-safe-trace.cpp b/libSegFault/signal-safe-trace.cpp index 16b0067..8c2947b 100644 --- a/libSegFault/signal-safe-trace.cpp +++ b/libSegFault/signal-safe-trace.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,40 @@ void warmup_cpptrace() cpptrace::get_safe_object_frame(buffer[0], &frame); } +std::string tracer_program = [] +{ + const char *value = getenv("LIBSEGFAULT_TRACER"); + return value ? value : ""; +}(); + +extern char **environ; + +std::vector tracer_env = [] +{ + std::vector tracer_env; + for (char **s = environ; *s; s++) + { + std::string_view var = *s; + if (!var.starts_with("LD_PRELOAD=")) + { + tracer_env.emplace_back(var); + } + } + return tracer_env; +}(); + +const std::vector tracer_env_buffer = [] +{ + std::vector tracer_env_buffer; + for (auto &var : tracer_env) + { + tracer_env_buffer.emplace_back(var.data()); + } + tracer_env_buffer.emplace_back(nullptr); + return tracer_env_buffer; +}(); + +const bool is_debug = isDebugMode(); [[gnu::constructor]] void init() { @@ -48,10 +83,11 @@ void warmup_cpptrace() } const auto fork_failure_message = "fork() failed, unable to collect trace\n"sv; -const auto no_tracer_message = "exec(signal_tracer) failed: Please supply the environment variable LIBSEGFAULT_TRACER.\n"sv; +const auto no_tracer_message = "exec(signal_tracer) failed: Please supply the environment variable " + "LIBSEGFAULT_TRACER.\n"sv; -const auto exec_failure_message = -"exec(signal_tracer) failed: Make sure the signal_tracer exists and the executable permissions are correct.\n"sv; +const auto exec_failure_message = "exec(signal_tracer) failed: Make sure the signal_tracer exists and the executable " + "permissions are correct.\n"sv; void do_signal_safe_trace() { @@ -74,21 +110,19 @@ void do_signal_safe_trace() close(input_pipe.read_end); close(input_pipe.write_end); - bool is_debug = isDebugMode(); - const char *tracer_program = getTracerProgram(); - if (strlen(tracer_program) == 0) + if (tracer_program.size() == 0) { std::ignore = write(STDERR_FILENO, no_tracer_message.data(), no_tracer_message.size()); } else { - execl(tracer_program, tracer_program, nullptr); + execle(tracer_program.c_str(), tracer_program.c_str(), nullptr, tracer_env_buffer.data()); if (is_debug) { auto errcode = errno; fprintf(stderr, "errno: %d\n", errcode); - fprintf(stderr, "tried to execute: %s\n", tracer_program); + fprintf(stderr, "tried to execute: %s\n", tracer_program.c_str()); } // https://linux.die.net/man/3/execl - execl() only returns when an error has occured