Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

log/diag: Support diagnostic stacktraces on SIGSEGV #6201

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down
14 changes: 13 additions & 1 deletion doc/userguide/configuration/suricata-yaml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,7 @@ configuration (console, file, syslog) if not otherwise set.
line option <cmdline-option-v>`.

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
~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -2229,6 +2229,18 @@ 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.

::

logging:
# Requires --enable-libunwind. Display a brief diagnostic message with the
# offending stacktrace when enabled _and_ configured.
sigsegv-stacktrace: on

luajit
~~~~~~

Expand Down
59 changes: 59 additions & 0 deletions src/suricata.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,53 @@ static void SignalHandlerSigterm(/*@unused@*/ int sig)
{
sigterm_count = 1;
}
#ifndef OS_WIN32
#if HAVE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
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
Expand Down Expand Up @@ -1947,6 +1994,18 @@ 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) == 1) {
if (enabled) {
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
#endif
#ifndef OS_WIN32
UtilSignalHandlerSetup(SIGHUP, SignalHandlerSigHup);
Expand Down
1 change: 1 addition & 0 deletions src/util-error.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/util-error.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -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: off
jlucovsky marked this conversation as resolved.
Show resolved Hide resolved

# Define your logging outputs. If none are defined, or they are all
# disabled you will get the default: console output.
outputs:
Expand Down