From 65ccd641bacea33be23d51da737c2de7543d0f5e Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Mon, 20 Dec 2021 08:41:55 -0300 Subject: debug: Remove catchsegv and libSegfault (BZ #14913) Trapping SIGSEGV within the process is error-prone, adds security issues, and modern analysis design tends to happen out of the process (either by attaching a debugger or by post-mortem analysis). The libSegfault also has some design problems, it uses non async-signal-safe function (backtrace) on signal handler. There are multiple alternatives if users do want to use similar functionality, such as sigsegv gnulib module or libsegfault. --- debug/Makefile | 19 +---- debug/catchsegv.sh | 106 -------------------------- debug/segfault.c | 215 ----------------------------------------------------- 3 files changed, 2 insertions(+), 338 deletions(-) delete mode 100755 debug/catchsegv.sh delete mode 100644 debug/segfault.c (limited to 'debug') diff --git a/debug/Makefile b/debug/Makefile index 9c2ce61a86..5818d751c9 100644 --- a/debug/Makefile +++ b/debug/Makefile @@ -167,12 +167,9 @@ tests-unsupported = tst-chk4 tst-chk5 tst-chk6 tst-chk8 \ tst-lfschk4 tst-lfschk5 tst-lfschk6 endif -extra-libs = libSegFault libpcprofile +extra-libs = libpcprofile extra-libs-others = $(extra-libs) -libSegFault-routines = segfault -libSegFault-inhibit-o = $(filter-out .os,$(object-suffixes)) - libpcprofile-routines = pcprofile libpcprofile-inhibit-o = $(filter-out .os,$(object-suffixes)) @@ -180,10 +177,7 @@ others = pcprofiledump install-bin = pcprofiledump install-bin-script = xtrace -ifeq ($(build-shared),yes) -install-bin-script += catchsegv -endif -generated += catchsegv xtrace +generated += xtrace include ../Rules @@ -209,15 +203,6 @@ endif sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,') -$(objpfx)catchsegv: catchsegv.sh $(common-objpfx)soversions.mk \ - $(common-objpfx)config.make - slibpfx=`echo $(slibdir)|sed 's/lib\(64\|\)$$/\\\\\\\\$$LIB/'`; \ - sed -e 's|@VERSION@|$(version)|' -e "s|@SLIB@|$$slibpfx|" \ - -e 's|@PKGVERSION@|$(PKGVERSION)|' \ - -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $< > $@.new - chmod 555 $@.new - mv -f $@.new $@ - $(objpfx)pcprofiledump: $(objpfx)pcprofiledump.o $(objpfx)xtrace: xtrace.sh diff --git a/debug/catchsegv.sh b/debug/catchsegv.sh deleted file mode 100755 index f8328eee69..0000000000 --- a/debug/catchsegv.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh -# Copyright (C) 1998-2022 Free Software Foundation, Inc. -# This file is part of the GNU C Library. - -# The GNU C Library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. - -# The GNU C Library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public -# License along with the GNU C Library; if not, see -# . - -if test $# -eq 0; then - echo "$0: missing program name" >&2 - echo "Try \`$0 --help' for more information." >&2 - exit 1 -fi - -prog="$1" -shift - -if test $# -eq 0; then - case "$prog" in - --h | --he | --hel | --help) - echo 'Usage: catchsegv PROGRAM ARGS...' - echo ' --help print this help, then exit' - echo ' --version print version number, then exit' - echo 'For bug reporting instructions, please see:' - cat <<\EOF -@REPORT_BUGS_TO@. -EOF - exit 0 - ;; - --v | --ve | --ver | --vers | --versi | --versio | --version) - echo 'catchsegv @PKGVERSION@@VERSION@' - echo 'Copyright (C) 2022 Free Software Foundation, Inc. -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -Written by Ulrich Drepper.' - exit 0 - ;; - *) - ;; - esac -fi - -segv_output=`mktemp ${TMPDIR:-/tmp}/segv_output.XXXXXX` || exit - -# Redirect stderr to avoid termination message from shell. -(exec 3>&2 2>/dev/null -LD_PRELOAD=${LD_PRELOAD:+${LD_PRELOAD}:}@SLIB@/libSegFault.so \ -SEGFAULT_USE_ALTSTACK=1 \ -SEGFAULT_OUTPUT_NAME=$segv_output \ -"$prog" ${1+"$@"} 2>&3 3>&-) -exval=$? - -# Check for output. Even if the program terminated correctly it might -# be that a minor process (clone) failed. Therefore we do not check the -# exit code. -if test -s "$segv_output"; then - # The program caught a signal. The output is in the file with the - # name we have in SEGFAULT_OUTPUT_NAME. In the output the names of - # functions in shared objects are available, but names in the static - # part of the program are not. We use addr2line to get this information. - case $prog in - */*) ;; - *) - old_IFS=$IFS - IFS=: - for p in $PATH; do - test -n "$p" || p=. - if test -f "$p/$prog"; then - prog=$p/$prog - break - fi - done - IFS=$old_IFS - ;; - esac - sed '/Backtrace/q' "$segv_output" - sed '1,/Backtrace/d' "$segv_output" | - (while read line; do - line=`echo $line | sed "s@^$prog\\(\\[.*\\)@\1@"` - case "$line" in - \[*) addr=`echo "$line" | sed 's/^\[\(.*\)\]$/\1/'` - complete=`addr2line -f -e "$prog" $addr 2>/dev/null` - if test $? -eq 0; then - echo "`echo "$complete"|sed 'N;s/\(.*\)\n\(.*\)/\2(\1)/;'`$line" - else - echo "$line" - fi - ;; - *) echo "$line" - ;; - esac - done) -fi -rm -f "$segv_output" - -exit $exval diff --git a/debug/segfault.c b/debug/segfault.c deleted file mode 100644 index 55801d1944..0000000000 --- a/debug/segfault.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Catch segmentation faults and print backtrace. - Copyright (C) 1998-2022 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include <_itoa.h> -#include - -/* This file defines macros to access the content of the sigcontext element - passed up by the signal handler. */ -#include - -#ifdef SA_SIGINFO -# define SIGCONTEXT siginfo_t *info, void * -#endif - -/* Get code to possibly dump the content of all registers. */ -#include - -/* We'll use this a lot. */ -#define WRITE_STRING(s) write (fd, s, strlen (s)) - -/* Name of the output file. */ -static const char *fname; - - -/* Print the signal number SIGNAL. Either strerror or strsignal might - call local internal functions and these in turn call far too many - other functions and might even allocate memory which might fail. */ -static void -write_strsignal (int fd, int signal) -{ - char buf[30]; - char *ptr = _itoa_word (signal, &buf[sizeof (buf)], 10, 0); - WRITE_STRING ("signal "); - write (fd, ptr, &buf[sizeof (buf)] - ptr); -} - - -/* This function is called when a segmentation fault is caught. The system - is in an unstable state now. This means especially that malloc() might - not work anymore. */ -static void -catch_segfault (int signal, SIGCONTEXT ctx) -{ - int fd, cnt, i; - void **arr; - struct sigaction sa; - uintptr_t pc; - - /* This is the name of the file we are writing to. If none is given - or we cannot write to this file write to stderr. */ - fd = 2; - if (fname != NULL) - { - fd = open (fname, O_TRUNC | O_WRONLY | O_CREAT, 0666); - if (fd == -1) - fd = 2; - } - - WRITE_STRING ("*** "); - write_strsignal (fd, signal); - WRITE_STRING ("\n"); - -#ifdef REGISTER_DUMP - REGISTER_DUMP; -#endif - - WRITE_STRING ("\nBacktrace:\n"); - - /* Get the backtrace. */ - arr = alloca (256 * sizeof (void *)); - cnt = backtrace (arr, 256); - - /* Now try to locate the PC from signal context in the backtrace. - Normally it will be found at arr[2], but it might appear later - if there were some signal handler wrappers. Allow a few bytes - difference to cope with as many arches as possible. */ - pc = sigcontext_get_pc (ctx); - for (i = 0; i < cnt; ++i) - if ((uintptr_t) arr[i] >= pc - 16 && (uintptr_t) arr[i] <= pc + 16) - break; - - /* If we haven't found it, better dump full backtrace even including - the signal handler frames instead of not dumping anything. */ - if (i == cnt) - i = 0; - - /* Now generate nicely formatted output. */ - __backtrace_symbols_fd (arr + i, cnt - i, fd); - -#ifdef HAVE_PROC_SELF - /* Now the link map. */ - int mapfd = open ("/proc/self/maps", O_RDONLY); - if (mapfd != -1) - { - write (fd, "\nMemory map:\n\n", 14); - - char buf[256]; - ssize_t n; - - while ((n = TEMP_FAILURE_RETRY (read (mapfd, buf, sizeof (buf)))) > 0) - TEMP_FAILURE_RETRY (write (fd, buf, n)); - - close (mapfd); - } -#endif - - /* Pass on the signal (so that a core file is produced). */ - sa.sa_handler = SIG_DFL; - sigemptyset (&sa.sa_mask); - sa.sa_flags = 0; - sigaction (signal, &sa, NULL); - raise (signal); -} - - -static void -__attribute__ ((constructor)) -install_handler (void) -{ - struct sigaction sa; - const char *sigs = getenv ("SEGFAULT_SIGNALS"); - const char *name; - -#ifdef SA_SIGINFO - sa.sa_sigaction = catch_segfault; - sa.sa_flags = SA_SIGINFO; -#else - sa.sa_handler = (void*) catch_segfault; - sa.sa_flags = 0; -#endif - sigemptyset (&sa.sa_mask); - sa.sa_flags |= SA_RESTART; - - /* Maybe we are expected to use an alternative stack. */ - if (getenv ("SEGFAULT_USE_ALTSTACK") != 0) - { - void *stack_mem = malloc (2 * SIGSTKSZ); - stack_t ss; - - if (stack_mem != NULL) - { - ss.ss_sp = stack_mem; - ss.ss_flags = 0; - ss.ss_size = 2 * SIGSTKSZ; - - if (sigaltstack (&ss, NULL) == 0) - sa.sa_flags |= SA_ONSTACK; - } - } - - if (sigs == NULL) - sigaction (SIGSEGV, &sa, NULL); - else if (sigs[0] == '\0') - /* Do not do anything. */ - return; - else - { - const char *where; - int all = __strcasecmp (sigs, "all") == 0; - -#define INSTALL_FOR_SIG(sig, name) \ - where = __strcasestr (sigs, name); \ - if (all || (where != NULL \ - && (where == sigs || !isalnum (where[-1])) \ - && !isalnum (where[sizeof (name) - 1]))) \ - sigaction (sig, &sa, NULL); - - INSTALL_FOR_SIG (SIGSEGV, "segv"); - INSTALL_FOR_SIG (SIGILL, "ill"); -#ifdef SIGBUS - INSTALL_FOR_SIG (SIGBUS, "bus"); -#endif -#ifdef SIGSTKFLT - INSTALL_FOR_SIG (SIGSTKFLT, "stkflt"); -#endif - INSTALL_FOR_SIG (SIGABRT, "abrt"); - INSTALL_FOR_SIG (SIGFPE, "fpe"); - } - - /* Preserve the output file name if there is any given. */ - name = getenv ("SEGFAULT_OUTPUT_NAME"); - if (name != NULL && name[0] != '\0') - { - int ret = access (name, R_OK | W_OK); - - if (ret == 0 || (ret == -1 && errno == ENOENT)) - fname = __strdup (name); - } -} -- cgit 1.4.1