From 8c8344acf968d27624041be2e082b310f3c74c79 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Thu, 17 Jun 2021 08:52:17 -0400 Subject: [PATCH 1/6] configure.ac: Support libunwind configuration This commit adds support for enabling libunwind -- a library that can be used to display stack information. Use --enable-libunwind to check for availability. A diagnostic message is displayed if libunwind cannot be found as requested. --- configure.ac | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/configure.ac b/configure.ac index 30d2b4f09300..317cdcaa613c 100644 --- a/configure.ac +++ b/configure.ac @@ -1786,6 +1786,20 @@ ;; esac + AC_ARG_ENABLE(libunwind, + AS_HELP_STRING([--enable-libunwind],[Enable Libunwind support for diagnostic stacktraces]), + [ enable_libunwind="$enableval"], + [ enable_libunwind="no"]) + + if test "$enable_libunwind" = "yes"; then + AC_CHECK_LIB(unwind,unw_backtrace,,LIBUNW="no") + if test "$LIBUNW" = "no"; then + echo + echo " libunwind library and development headers not found" + echo " stacktrace on SIGSEGV not possible" + echo + fi; + fi; AC_ARG_ENABLE(ebpf, AS_HELP_STRING([--enable-ebpf],[Enable eBPF support]), From 9141c379344755622f340ff594fce964ab2556c7 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Thu, 17 Jun 2021 08:54:30 -0400 Subject: [PATCH 2/6] error: Add error code for SIGSEGV diagnostic This commit adds an error code for the diagnostic code used for SIGSEGV diagnostic messages. --- src/util-error.c | 1 + src/util-error.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/util-error.c b/src/util-error.c index 004158d6dab4..c23441b29e90 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -379,6 +379,7 @@ const char * SCErrorToString(SCError err) CASE_CODE(SC_ERR_RULE_INVALID_UTF8); CASE_CODE(SC_ERR_HASHING_DISABLED); CASE_CODE(SC_WARN_THRESH_CONFIG); + CASE_CODE(SC_ERR_SIGSEGV); CASE_CODE (SC_ERR_MAX); } diff --git a/src/util-error.h b/src/util-error.h index b854364d4e56..19ad1594dc3b 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -369,6 +369,7 @@ typedef enum { SC_ERR_RULE_INVALID_UTF8, SC_ERR_HASHING_DISABLED, SC_WARN_THRESH_CONFIG, + SC_ERR_SIGSEGV, SC_ERR_MAX } SCError; From 6fb6d9a50c8b07b0087eb919f9a30f20f7568320 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Thu, 17 Jun 2021 09:04:56 -0400 Subject: [PATCH 3/6] logging: Stacktrace on SIGSEGV setting This commit adds a configuration setting to enable a stack trace message if Suricata receives a SIGSEGV. --- suricata.yaml.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/suricata.yaml.in b/suricata.yaml.in index ba1a983b3868..133d5b66f0b0 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -555,6 +555,10 @@ logging: # This value is overridden by the SC_LOG_OP_FILTER env var. default-output-filter: + # Requires --enable-libunwind. Display a brief diagnostic message with the + # offending stacktrace when enabled _and_ configured. + #sigsegv-stacktrace: on + # Define your logging outputs. If none are defined, or they are all # disabled you will get the default: console output. outputs: From 0f5d902fd878b8a1c5e2f80d41542d5665853745 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Thu, 17 Jun 2021 09:07:29 -0400 Subject: [PATCH 4/6] logging/diag: Enable stacktrace diagnostic if config'd This commit adds a signal handler for SIGSEGV when configured. The signal handler emits a one line stack trace using SCLogError. The intent is to provide diagnostic information in deployments where core files are not possible. The diagnostic message is from the offending thread and includes the stack trace; each frame includes the symbol + offset. --- src/suricata.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/suricata.c b/src/suricata.c index eb9a3a258099..8f7da5711d54 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -292,6 +292,53 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig) { sigterm_count = 1; } +#ifndef OS_WIN32 +#if HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include +static void SignalHandlerSigsegv(int sig_num, siginfo_t *info, void *context) +{ + char msg[SC_LOG_MAX_LOG_MSG_LEN]; + unw_cursor_t cursor; + int r; + if ((r = unw_init_local(&cursor, (unw_context_t *)(context)) != 0)) { + fprintf(stderr, "unable to obtain stack trace: unw_init_local: %s\n", unw_strerror(r)); + // Abort here! Clearly nothing is going to work. + abort(); + } + + char *temp = msg; + int cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - msg), "stacktrace:"); + temp += cw; + r = 1; + while (r > 0) { + if (unw_is_signal_frame(&cursor) == 0) { + unw_word_t off; + char name[256]; + if (unw_get_proc_name(&cursor, name, sizeof(name), &off) == UNW_ENOMEM) { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - msg), "[unknown]:"); + } else { + cw = snprintf( + temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - msg), "%s+0x%08" PRIx64, name, off); + } + temp += cw; + } + + r = unw_step(&cursor); + if (r > 0) { + cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - msg), ";"); + temp += cw; + } + } + SCLogError(SC_ERR_SIGSEGV, "%s", msg); + + // Die to death, previously this was calling exit which meant that sending SIGSEGV didn't core + // dump. + abort(); +} +#undef UNW_LOCAL_ONLY +#endif /* HAVE_LIBUNWIND */ +#endif /* !OS_WIN32 */ #endif #ifndef OS_WIN32 @@ -1949,6 +1996,21 @@ static int InitSignalHandler(SCInstance *suri) #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION UtilSignalHandlerSetup(SIGINT, SignalHandlerSigint); UtilSignalHandlerSetup(SIGTERM, SignalHandlerSigterm); +#if HAVE_LIBUNWIND + int enabled; + if (ConfGetBool("logging.sigsegv-stacktrace", &enabled) == 0) { + enabled = 1; + } + + if (enabled) { + SCLogInfo("Preparing SIGSEGV handling"); + struct sigaction stacktrace_action; + memset(&stacktrace_action, 0, sizeof(stacktrace_action)); + stacktrace_action.sa_sigaction = SignalHandlerSigsegv; + stacktrace_action.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &stacktrace_action, NULL); + } +#endif /* HAVE_LIBUNWIND */ #endif #ifndef OS_WIN32 UtilSignalHandlerSetup(SIGHUP, SignalHandlerSigHup); From 8be58a9a266a4a7f659d65aa1fd986200d6abaea Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Thu, 17 Jun 2021 09:24:34 -0400 Subject: [PATCH 5/6] general: Fix typo --- doc/userguide/configuration/suricata-yaml.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index a4fcd75fc0c6..48c8ecd8f9bd 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -1501,7 +1501,7 @@ configuration (console, file, syslog) if not otherwise set. line option `. The ``default-log-level`` set in the configuration value can be -overriden by the ``SC_LOG_LEVEL`` environment variable. +overridden by the ``SC_LOG_LEVEL`` environment variable. Default Log Format ~~~~~~~~~~~~~~~~~~ From 58442486179365bb2e36a52108492a99a605cb34 Mon Sep 17 00:00:00 2001 From: Jeff Lucovsky Date: Thu, 17 Jun 2021 09:24:46 -0400 Subject: [PATCH 6/6] doc/yaml: SIGSEGV option description --- doc/userguide/configuration/suricata-yaml.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/userguide/configuration/suricata-yaml.rst b/doc/userguide/configuration/suricata-yaml.rst index 48c8ecd8f9bd..bd899343a339 100644 --- a/doc/userguide/configuration/suricata-yaml.rst +++ b/doc/userguide/configuration/suricata-yaml.rst @@ -2229,6 +2229,19 @@ inspected for possible presence of Teredo. Advanced Options ---------------- +sigsegv +~~~~~~~ +Diagnostic stacktraces when a SIGSEGV occurs are available when Suricata is configured with +``--enable-libunwind`` and the ``libunwind`` library is available. The default value +is to display the diagnostic message if a ``SIGSEGV`` occurs. + +:: + + logging: + # Requires --enable-libunwind. Display a brief diagnostic message with the + # offending stacktrace when enabled _and_ configured. + # sigsegv-stacktrace: on + luajit ~~~~~~