From: Michael Altizer (mialtize) Date: Tue, 23 Jun 2020 23:25:24 +0000 (+0000) Subject: Merge pull request #2162 in SNORT/snort3 from ~MIALTIZE/snort3:signals to master X-Git-Tag: 3.0.2-1~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e04e9ad29497d86ea94e06885d1b719016ccc8c9;p=thirdparty%2Fsnort3.git Merge pull request #2162 in SNORT/snort3 from ~MIALTIZE/snort3:signals to master Squashed commit of the following: commit 6a67fa549c3f42cd084d0e99a3d4326b3e89b7eb Author: Michael Altizer Date: Wed Jun 17 17:57:21 2020 -0400 cmake: Properly handle SIGNAL_SNORT_* options in configure_cmake.sh commit 829d1dff292f417db11aee43615be745f7949eb6 Author: Michael Altizer Date: Tue May 26 17:43:27 2020 -0400 helpers: Add support for dumping a backtrace via libunwind on fatal signals Support for this requires the libunwind development headers and library available at build time. The dependency is optional. commit 26b3d8171a7566141b32b411695e55e6a6ab4307 Author: Michael Altizer Date: Tue May 26 17:46:27 2020 -0400 helpers: Dump additional information to stderr when a fatal signal is received This information includes which signal was received, the Snort version, and the current DAQ message information (if the signal was received while processing a message in a packet thread). commit 8acc840fb0185b17957dcaea35ef43346a9502fd Author: Michael Altizer Date: Tue May 26 17:46:13 2020 -0400 helpers: Add a signal-safe formatted printing utility class commit f2fee6377a6325a640e4ea0a858a78edb8e7a6c5 Author: Michael Altizer Date: Mon Apr 13 10:23:26 2020 -0400 oops_handler: Operate on DAQ message instead of Snort Packets commit ff7961a1b5e2315401dbe0be7741346aa1ceb37b Author: Michael Altizer Date: Tue Mar 3 10:21:04 2020 -0500 helpers: Revamp signal handler installation and removal Importantly, back up the previous signal handlers for fatal signals so that we can attempt to reinstall and call them on the way out. This cleans up the interaction with libasan's SIGSEGV handler, for example. commit ed6bccf52f0bb7da4b9676af5fec4a0452e6734e Author: Michael Altizer Date: Mon Mar 16 11:41:34 2020 -0400 build: Use sanity check results (HAVE_*) for optional packages in CMake --- diff --git a/CMakeLists.txt b/CMakeLists.txt index d305e1a32..8ba3c5342 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,6 +125,14 @@ else () ICONV: OFF") endif () +if (HAVE_LIBUNWIND) + message("\ + Libunwind: ON") +else () + message("\ + Libunwind: OFF") +endif () + if (HAVE_LZMA) message("\ LZMA: ON") diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake new file mode 100644 index 000000000..f66800a18 --- /dev/null +++ b/cmake/FindLibunwind.cmake @@ -0,0 +1,43 @@ +# FindLibunwind +# --------- +# +# Find the libunwind includes and library. +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# This module will set the following variables in your project: +# +# ``LIBUNWIND_INCLUDE_DIRS`` +# where to find rpc.h, etc. +# ``LIBUNWIND_LIBRARIES`` +# the libraries to link against to use TIRPC. +# ``LIBUNWIND_VERSION`` +# the version of TIRPC found. +# ``LIBUNWIND_FOUND`` +# true if the TIRPC headers and libraries were found. +# + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBUNWIND libunwind) + +find_path(LIBUNWIND_INCLUDE_DIRS + NAMES libunwind.h + HINTS ${PC_LIBUNWIND_INCLUDE_DIRS} +) + +find_library(LIBUNWIND_LIBRARIES + NAMES unwind + HINTS ${PC_LIBUNWIND_LIBRARY_DIRS} +) + +set(LIBUNWIND_VERSION ${PC_LIBUNWIND_VERSION}) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(Libunwind + REQUIRED_VARS LIBUNWIND_LIBRARIES LIBUNWIND_INCLUDE_DIRS + VERSION_VAR LIBUNWIND_VERSION +) + +mark_as_advanced(LIBUNWIND_INCLUDE_DIRS LIBUNWIND_LIBRARIES) diff --git a/cmake/include_libraries.cmake b/cmake/include_libraries.cmake index 401302f15..811c95ac6 100644 --- a/cmake/include_libraries.cmake +++ b/cmake/include_libraries.cmake @@ -25,3 +25,4 @@ endif (ENABLE_SAFEC) find_package(Flatbuffers QUIET) find_package(ICONV QUIET) find_package(UUID QUIET) +find_package(Libunwind) diff --git a/cmake/sanity_checks.cmake b/cmake/sanity_checks.cmake index de43a4bb0..a748be228 100644 --- a/cmake/sanity_checks.cmake +++ b/cmake/sanity_checks.cmake @@ -150,6 +150,12 @@ if (ICONV_FOUND) set (HAVE_ICONV "1") endif() +if (LIBUNWIND_FOUND) + # We don't actually use backtrace from libunwind, but it's basically the + # only symbol guaranteed to be present. + check_library_exists (${LIBUNWIND_LIBRARIES} backtrace "" HAVE_LIBUNWIND) +endif() + if (SAFEC_FOUND) check_library_exists (${SAFEC_LIBRARIES} printf_s "" HAVE_SAFEC) endif() diff --git a/config.cmake.h.in b/config.cmake.h.in index d6330bc21..56b42fe96 100644 --- a/config.cmake.h.in +++ b/config.cmake.h.in @@ -113,22 +113,29 @@ /* Available libraries */ +/* flatbuffers available */ +#cmakedefine HAVE_FLATBUFFERS 1 + /* hyperscan available */ #cmakedefine HAVE_HYPERSCAN 1 #cmakedefine HAVE_HS_COMPILE_LIT 1 +/* iconv available */ +#cmakedefine HAVE_ICONV 1 + +/* libunwind available */ +#cmakedefine HAVE_LIBUNWIND 1 + /* lzma available */ #cmakedefine HAVE_LZMA 1 /* safec available */ #cmakedefine HAVE_SAFEC 1 -#cmakedefine HAVE_FLATBUFFERS 1 - -#cmakedefine HAVE_ICONV 1 - +/* uuid available */ #cmakedefine HAVE_UUID 1 +/* tirpc should be used for RPC database lookups */ #cmakedefine USE_TIRPC 1 diff --git a/configure_cmake.sh b/configure_cmake.sh index 64d97e895..50cc6fc5d 100755 --- a/configure_cmake.sh +++ b/configure_cmake.sh @@ -145,7 +145,7 @@ append_cache_entry CMAKE_INSTALL_PREFIX PATH $prefix # parse arguments while [ $# -ne 0 ]; do case "$1" in - -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac diff --git a/doc/building.txt b/doc/building.txt index c694d1c02..80f340cd6 100644 --- a/doc/building.txt +++ b/doc/building.txt @@ -18,6 +18,8 @@ present. There is no need to explicitly enable. * *iconv*: for converting UTF16-LE filenames to UTF8 (usually included in glibc) +* *libunwind*: for printing a backtrace when a fatal signal is received. + * *lzma*: for decompression of SWF and PDF files. * *safec*: for additional runtime error checking of some memory copy operations. diff --git a/doc/tutorial.txt b/doc/tutorial.txt index fab457033..c5ba545ed 100644 --- a/doc/tutorial.txt +++ b/doc/tutorial.txt @@ -16,7 +16,8 @@ Required: * dnet from https://github.com/dugsong/libdnet.git for network utility functions -* hwloc from https://www.open-mpi.org/projects/hwloc/ for CPU affinity management +* hwloc from https://www.open-mpi.org/projects/hwloc/ for CPU affinity + management * LuaJIT from http://luajit.org for configuration and scripting @@ -27,7 +28,8 @@ Required: * pcre from http://www.pcre.org for regular expression pattern matching -* pkgconfig from https://www.freedesktop.org/wiki/Software/pkg-config/ to locate build dependencies +* pkgconfig from https://www.freedesktop.org/wiki/Software/pkg-config/ to locate + build dependencies * zlib from http://www.zlib.net for decompression (>= 1.2.8 recommended) @@ -53,6 +55,9 @@ Optional: * iconv from https://ftp.gnu.org/pub/gnu/libiconv/ for converting UTF16-LE filenames to UTF8 (usually included in glibc) +* libunwind from https://www.nongnu.org/libunwind/ to attempt to dump a + somewhat readable backtrace when a fatal signal is received + * lzma >= 5.1.2 from http://tukaani.org/xz/ for decompression of SWF and PDF files diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e5012d33..4285aac27 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,10 +28,25 @@ if ( ENABLE_STATIC_DAQ ) LIST(APPEND EXTERNAL_LIBRARIES ${DAQ_STATIC_MODULE_LIBS}) endif () -if ( FLATBUFFERS_FOUND ) +if ( HAVE_FLATBUFFERS ) LIST(APPEND EXTERNAL_LIBRARIES ${FLATBUFFERS_LIBRARIES}) endif() +if ( HAVE_HYPERSCAN ) + LIST(APPEND EXTERNAL_LIBRARIES ${HS_LIBRARIES}) + LIST(APPEND EXTERNAL_INCLUDES ${HS_INCLUDE_DIRS}) +endif () + +if ( HAVE_ICONV ) + LIST(APPEND EXTERNAL_LIBRARIES ${ICONV_LIBRARY}) + LIST(APPEND EXTERNAL_INCLUDES ${ICONV_INCLUDE_DIR}) +endif () + +if ( HAVE_LIBUNWIND ) + LIST(APPEND EXTERNAL_LIBRARIES ${LIBUNWIND_LIBRARIES}) + LIST(APPEND EXTERNAL_INCLUDES ${LIBUNWIND_INCLUDE_DIRS}) +endif () + if ( HAVE_LZMA ) LIST(APPEND EXTERNAL_LIBRARIES ${LIBLZMA_LIBRARIES}) endif() @@ -46,16 +61,6 @@ if ( HAVE_UUID ) LIST(APPEND EXTERNAL_INCLUDES ${UUID_INCLUDE_DIR}) endif () -if ( HS_FOUND ) - LIST(APPEND EXTERNAL_LIBRARIES ${HS_LIBRARIES}) - LIST(APPEND EXTERNAL_INCLUDES ${HS_INCLUDE_DIRS}) -endif () - -if ( ICONV_FOUND ) - LIST(APPEND EXTERNAL_LIBRARIES ${ICONV_LIBRARY}) - LIST(APPEND EXTERNAL_INCLUDES ${ICONV_INCLUDE_DIR}) -endif () - if ( USE_TIRPC ) LIST(APPEND EXTERNAL_LIBRARIES ${TIRPC_LIBRARIES}) LIST(APPEND EXTERNAL_INCLUDES ${TIRPC_INCLUDE_DIRS}) diff --git a/src/helpers/CMakeLists.txt b/src/helpers/CMakeLists.txt index af5367f0f..c51eb69e3 100644 --- a/src/helpers/CMakeLists.txt +++ b/src/helpers/CMakeLists.txt @@ -40,6 +40,8 @@ add_library (helpers OBJECT process.h ring.h ring_logic.h + sigsafe.cc + sigsafe.h scratch_allocator.cc ) @@ -53,5 +55,11 @@ add_catch_test( base64_encoder_test base64_encoder.cc ) +add_catch_test( sigsafe_test + NO_TEST_SOURCE + SOURCES + sigsafe.cc +) + add_subdirectory(test) diff --git a/src/helpers/process.cc b/src/helpers/process.cc index c5cb9f0c8..55f31220f 100644 --- a/src/helpers/process.cc +++ b/src/helpers/process.cc @@ -24,7 +24,13 @@ #include -#if defined(HAVE_MALLOC_TRIM) +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include +#include +#endif + +#ifdef HAVE_MALLOC_TRIM #include #endif @@ -33,6 +39,7 @@ #include "log/messages.h" #include "main.h" +#include "main/build.h" #include "main/oops_handler.h" #include "main/snort_config.h" #include "utils/stats.h" @@ -40,9 +47,9 @@ #include "markup.h" #include "ring.h" +#include "sigsafe.h" using namespace snort; -using namespace std; #ifndef SIGNAL_SNORT_RELOAD #define SIGNAL_SNORT_RELOAD SIGHUP @@ -74,8 +81,38 @@ static Ring sig_ring(4); static volatile sig_atomic_t child_ready_signal = 0; static THREAD_LOCAL bool is_main_thread = false; -typedef void (* sighandler_t)(int); -static bool add_signal(int sig, sighandler_t, bool check_needed); +// Backup copies of the original fatal signal actions. Kept here because they must +// be trivially accessible to signal handlers. +#ifdef HAVE_SIGACTION +static struct +{ + int signal; + struct sigaction original_sigaction; +} +original_sigactions[] = +{ + { SIGABRT, { } }, + { SIGBUS, { } }, + { SIGSEGV, { } }, + { 0, { } }, +}; +#else +static struct +{ + int signal; + sighandler_t original_sighandler; +} +original_sighandlers[] = +{ + { SIGABRT, SIG_DFL }, + { SIGBUS, SIG_DFL }, + { SIGSEGV, SIG_DFL }, + { 0, SIG_DFL }, +}; +#endif + +static bool add_signal(int sig, sighandler_t); +static bool restore_signal(int sig, bool silent = false); static bool exit_pronto = true; @@ -85,19 +122,6 @@ void set_quick_exit(bool b) void set_main_thread() { is_main_thread = true; } -static void exit_log(const char* why) -{ - // printf() etc not allowed here - char buf[256] = "\n\0"; - - strncat(buf, get_prompt(), sizeof(buf)-strlen(buf)-1); - strncat(buf, " caught ", sizeof(buf)-strlen(buf)-1); - strncat(buf, why, sizeof(buf)-strlen(buf)-1); - strncat(buf, " signal, exiting\n", sizeof(buf)-strlen(buf)-1); - - (void)write(STDOUT_FILENO, buf, strlen(buf)); // FIXIT-W ignoring return value -} - static void exit_handler(int signal) { PigSignal s; @@ -105,15 +129,15 @@ static void exit_handler(int signal) switch ( signal ) { - case SIGTERM: s = PIG_SIG_TERM; t = "term"; break; - case SIGQUIT: s = PIG_SIG_QUIT; t = "quit"; break; - case SIGINT: s = PIG_SIG_INT; t = "int"; break; - default: return; + case SIGTERM: s = PIG_SIG_TERM; t = "term"; break; + case SIGQUIT: s = PIG_SIG_QUIT; t = "quit"; break; + case SIGINT: s = PIG_SIG_INT; t = "int"; break; + default: return; } if ( exit_pronto ) { - exit_log(t); + SigSafePrinter(STDOUT_FILENO).printf("%s caught %s signal, exiting\n", get_prompt(), t); _exit(0); } @@ -146,22 +170,114 @@ static void reload_attrib_handler(int /*signal*/) sig_ring.put(PIG_SIG_RELOAD_HOSTS); } -static void ignore_handler(int /*signal*/) +static void child_ready_handler(int /*signal*/) { + child_ready_signal = 1; } -static void child_ready_handler(int /*signal*/) +#ifdef HAVE_LIBUNWIND +static void print_backtrace(SigSafePrinter& ssp) { - child_ready_signal = 1; + int ret; + + // grab the machine context and initialize the cursor + unw_context_t context; + if ((ret = unw_getcontext(&context)) < 0) + { + ssp.printf("unw_getcontext failed: %s (%d)\n", unw_strerror(ret), ret); + return; + } + + unw_cursor_t cursor; + if ((ret = unw_init_local(&cursor, &context)) < 0) + { + ssp.printf("unw_init_local failed: %s (%d)\n", unw_strerror(ret), ret); + return; + } + + ssp.printf("Backtrace:\n"); + + // walk the stack frames + unsigned frame_num = 0; + while ((ret = unw_step(&cursor)) > 0) + { + // skip printing any frames until we've found the frame that received the signal + if (frame_num == 0 && !unw_is_signal_frame(&cursor)) + continue; + + unw_word_t pc; + if ((ret = unw_get_reg(&cursor, UNW_REG_IP, &pc)) < 0) + { + ssp.printf("unw_get_reg failed for instruction pointer: %s (%d)\n", + unw_strerror(ret), ret); + return; + } + + unw_proc_info_t pip; + if ((ret = unw_get_proc_info(&cursor, &pip)) < 0) + { + ssp.printf("unw_get_proc_info failed: %s (%d)\n", unw_strerror(ret), ret); + return; + } + + ssp.printf(" #%u 0x%x", frame_num, pc); + + char sym[256]; + unw_word_t offset; + if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) + ssp.printf(" in %s+0x%x", sym, offset); + + Dl_info dlinfo; + if (dladdr((void *)(uintptr_t)(pip.start_ip + offset), &dlinfo) + && dlinfo.dli_fname && *dlinfo.dli_fname) + { + ssp.printf(" (%s @0x%x)", dlinfo.dli_fname, dlinfo.dli_fbase); + } + + ssp.printf("\n"); + + frame_num++; + } + if (ret < 0) + ssp.printf("unw_step failed: %s (%d)\n", unw_strerror(ret), ret); + + ssp.printf("\n"); } +#endif static void oops_handler(int signal) { + // First things first, restore the original signal handler. + restore_signal(signal, true); + + // Log the Snort version and signal caught. + const char* sigstr = "???\n"; + switch (signal) + { + case SIGABRT: + sigstr = STRINGIFY(SIGABRT) " (" STRINGIFY_MX(SIGABRT) ")"; + break; + case SIGBUS: + sigstr = STRINGIFY(SIGBUS) " (" STRINGIFY_MX(SIGBUS) ")"; + break; + case SIGSEGV: + sigstr = STRINGIFY(SIGSEGV) " (" STRINGIFY_MX(SIGSEGV) ")"; + break; + } + SigSafePrinter ssp(STDERR_FILENO); + ssp.printf("\nSnort (PID %u) caught fatal signal: %s\n", getpid(), sigstr); + ssp.printf("Version: " VERSION " Build " BUILD "\n\n"); + +#ifdef HAVE_LIBUNWIND + // Try to pretty-print a stack trace using libunwind to traverse the stack. + print_backtrace(ssp); +#endif + // FIXIT-L what should we capture if this is the main thread? if ( !is_main_thread ) - OopsHandler::handle_crash(); + OopsHandler::handle_crash(STDERR_FILENO); - add_signal(signal, SIG_DFL, false); + // Finally, raise the signal so that the original handler can handle it. raise(signal); } @@ -186,34 +302,101 @@ const char* get_signal_name(PigSignal s) // signal management //------------------------------------------------------------------------- -// If check needed, also check whether previous signal_handler is neither -// SIG_IGN nor SIG_DFL - -// FIXIT-L convert sigaction, etc. to c++11 -static bool add_signal(int sig, sighandler_t signal_handler, bool check_needed) +static bool add_signal(int sig, sighandler_t signal_handler) { - sighandler_t pre_handler; - #ifdef HAVE_SIGACTION struct sigaction action; - struct sigaction old_action; + // Mask all other signals while in the signal handler sigfillset(&action.sa_mask); + // Make compatible system calls restartable across signals action.sa_flags = SA_RESTART; action.sa_handler = signal_handler; - sigaction(sig, &action, &old_action); - pre_handler = old_action.sa_handler; + + struct sigaction* old_action = nullptr; + for (unsigned i = 0; original_sigactions[i].signal; i++) + { + if (original_sigactions[i].signal == sig) + { + old_action = &original_sigactions[i].original_sigaction; + break; + } + } + + if (sigaction(sig, &action, old_action) != 0) + { + ErrorMessage("Could not add handler for signal %d: %s (%d)\n", sig, get_error(errno), errno); + return false; + } #else - pre_handler = signal(sig, signal_handler); + sighandler_t original_handler = signal(sig, signal_handler); + if (original_handler == SIG_ERR) + { + ErrorMessage("Could not add handler for signal %d: %s (%d)\n", sig, get_error(errno), errno); + return false; + } + + for (unsigned i = 0; original_sighandlers[i].signal; i++) + { + if (original_sigactions[i].signal == sig) + { + original_sigactions[i].original_handler = original_handler; + break; + } + } #endif - if (SIG_ERR == pre_handler) + + return true; +} + +static bool restore_signal(int sig, bool silent) +{ +#ifdef HAVE_SIGACTION + struct sigaction* new_action = nullptr; + struct sigaction action; + + for (unsigned i = 0; original_sigactions[i].signal; i++) + { + if (original_sigactions[i].signal == sig) + { + new_action = &original_sigactions[i].original_sigaction; + break; + } + } + + if (!new_action) + { + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = SIG_DFL; + new_action = &action; + } + + if (sigaction(sig, new_action, nullptr) != 0) { - ParseError("Could not add handler for signal %d \n", sig); + if (!silent) + ErrorMessage("Could not restore handler for signal %d: %s (%d)\n", sig, get_error(errno), errno); return false; } - else if (check_needed && (SIG_IGN != pre_handler) && (SIG_DFL!= pre_handler)) +#else + sighandler_t signal_handler = SIG_DFL; + + for (unsigned i = 0; original_sighandlers[i].signal; i++) + { + if (original_sigactions[i].signal == sig) + { + signal_handler = original_sigactions[i].original_handler; + break; + } + } + + if (signal(sig, signal_handler) == SIG_ERR) { - ParseWarning(WARN_CONF, "handler is already installed for signal %d.\n", sig); + if (!silent) + ErrorMessage("Could not restore handler for signal %d: %s (%d)\n", sig, get_error(errno), errno); + return false; } +#endif + return true; } @@ -225,53 +408,50 @@ void init_signals() // FIXIT-L this is undefined for multithreaded apps sigprocmask(SIG_SETMASK, &set, nullptr); - /* Make this prog behave nicely when signals come along. - * Windows doesn't like all of these signals, and will - * set errno for some. Ignore/reset this error so it - * doesn't interfere with later checks of errno value. */ - add_signal(SIGTERM, exit_handler, true); - add_signal(SIGINT, exit_handler, true); - add_signal(SIGQUIT, dirty_handler, true); + // Make this program behave nicely when signals come along. + add_signal(SIGTERM, exit_handler); + add_signal(SIGINT, exit_handler); + add_signal(SIGQUIT, dirty_handler); - add_signal(SIGNAL_SNORT_DUMP_STATS, dump_stats_handler, true); - add_signal(SIGNAL_SNORT_ROTATE_STATS, rotate_stats_handler, true); - add_signal(SIGNAL_SNORT_RELOAD, reload_config_handler, true); - add_signal(SIGNAL_SNORT_READ_ATTR_TBL, reload_attrib_handler, true); + add_signal(SIGNAL_SNORT_DUMP_STATS, dump_stats_handler); + add_signal(SIGNAL_SNORT_ROTATE_STATS, rotate_stats_handler); + add_signal(SIGNAL_SNORT_RELOAD, reload_config_handler); + add_signal(SIGNAL_SNORT_READ_ATTR_TBL, reload_attrib_handler); - add_signal(SIGPIPE, ignore_handler, true); - add_signal(SIGABRT, oops_handler, true); - add_signal(SIGSEGV, oops_handler, true); - add_signal(SIGBUS, oops_handler, true); + add_signal(SIGPIPE, SIG_IGN); + add_signal(SIGABRT, oops_handler); + add_signal(SIGSEGV, oops_handler); + add_signal(SIGBUS, oops_handler); errno = 0; } void term_signals() { - add_signal(SIGTERM, SIG_DFL, false); - add_signal(SIGINT, SIG_DFL, false); - add_signal(SIGQUIT, SIG_DFL, false); - - add_signal(SIGNAL_SNORT_DUMP_STATS, SIG_DFL, false); - add_signal(SIGNAL_SNORT_ROTATE_STATS, SIG_DFL, false); - add_signal(SIGNAL_SNORT_RELOAD, SIG_DFL, false); - add_signal(SIGNAL_SNORT_READ_ATTR_TBL, SIG_DFL, false); - - add_signal(SIGPIPE, SIG_DFL, false); - add_signal(SIGABRT, SIG_DFL, false); - add_signal(SIGSEGV, SIG_DFL, false); - add_signal(SIGBUS, SIG_DFL, false); + restore_signal(SIGTERM); + restore_signal(SIGINT); + restore_signal(SIGQUIT); + + restore_signal(SIGNAL_SNORT_DUMP_STATS); + restore_signal(SIGNAL_SNORT_ROTATE_STATS); + restore_signal(SIGNAL_SNORT_RELOAD); + restore_signal(SIGNAL_SNORT_READ_ATTR_TBL); + + restore_signal(SIGPIPE); + restore_signal(SIGABRT); + restore_signal(SIGSEGV); + restore_signal(SIGBUS); } static void help_signal(unsigned n, const char* name, const char* h) { - cout << Markup::item(); + std::cout << Markup::item(); - cout << Markup::emphasis_on(); - cout << name; - cout << Markup::emphasis_off(); + std::cout << Markup::emphasis_on(); + std::cout << name; + std::cout << Markup::emphasis_off(); - cout << "(" << n << "): " << h << endl; + std::cout << "(" << n << "): " << h << std::endl; } void help_signals() @@ -325,7 +505,7 @@ void daemonize() LogMessage("initializing daemon mode\n"); // register signal handler so that parent can trap signal - add_signal(SIGNAL_SNORT_CHILD_READY, child_ready_handler, true); + add_signal(SIGNAL_SNORT_CHILD_READY, child_ready_handler); pid_t cpid = fork(); diff --git a/src/helpers/sigsafe.cc b/src/helpers/sigsafe.cc new file mode 100644 index 000000000..332b9dd51 --- /dev/null +++ b/src/helpers/sigsafe.cc @@ -0,0 +1,451 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// sigsafe.cc author Michael Altizer + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sigsafe.h" + +#include + +#include +#include +#include + +/* + * Signal safety of functions called from here (POSIX async-signal-safe requirement): + * strlen POSIX.1-2016 + * write POSIX.1-2001 + */ + +static int sigsafe_format_uint64_dec(uint64_t num, char* buf, size_t buf_len) +{ + uint64_t divisor; + size_t len; + + // ceil(log10(0xFFFFFFFFFFFFFFFF)) = 20 + 1 for '\0' + if (buf_len > 21) + buf_len = 21; + + for (len = 1, divisor = 10; + len < buf_len - 1 && num / divisor; + len++, divisor *= 10); + + for (size_t i = len, divisor = 1; i > 0; i--, divisor *= 10) + buf[i - 1] = '0' + ((num / divisor) % 10); + + buf[len] = '\0'; + return len; +} + +static int sigsafe_format_uint64_hex(uint64_t num, char* buf, size_t buf_len) +{ + uint64_t divisor; + size_t len; + + // log16(0xFFFFFFFFFFFFFFFF) = 16 + 1 for '\0' + if (buf_len > 17) + buf_len = 17; + + for (len = 1, divisor = 0x10; + len < buf_len - 1 && num / divisor; + len++, divisor *= 0x10); + + for (size_t i = len, divisor = 1; i > 0; i--, divisor *= 0x10) + { + int val = (num / divisor) % 0x10; + + if (val < 10) + buf[i - 1] = '0' + val; + else + buf[i - 1] = 'a' + val - 10; + } + + buf[len] = '\0'; + return len; +} + +static void sigsafe_vsnprintf(char* str, size_t size, const char* format, va_list ap) +{ + size_t fmt_idx = 0; + size_t str_idx = 0; + size_t fmt_len = strlen(format); + char number[32]; + const char* string_arg; + int64_t i64_arg; + uint64_t u64_arg; + size_t arg_len; + bool negative; + + if (size == 0) + return; + + for (; fmt_idx < fmt_len && str_idx < size - 1; fmt_idx++) + { + if (format[fmt_idx] != '%') + { + str[str_idx++] = format[fmt_idx]; + continue; + } + if (++fmt_idx >= fmt_len) + break; + + bool zpad = false; + if (format[fmt_idx] == '0') + { + zpad = true; + if (++fmt_idx >= fmt_len) + break; + } + + size_t min_width = 0; + if (format[fmt_idx] >= '1' && format[fmt_idx] <= '9') + { + while (format[fmt_idx] >= '0' && format[fmt_idx] <= '9') + { + min_width = min_width * 10 + (format[fmt_idx] - '0'); + if (++fmt_idx >= fmt_len) + break; + } + if (fmt_idx >= fmt_len) + break; + } + + switch(format[fmt_idx]) + { + case 'd': + i64_arg = va_arg(ap, int64_t); + if (i64_arg < 0) + { + negative = true; + u64_arg = -i64_arg; + } + else + { + negative = false; + u64_arg = i64_arg; + } + arg_len = sigsafe_format_uint64_dec(u64_arg, number, sizeof(number)); + if (arg_len < min_width) + { + for (size_t padding = arg_len; padding < min_width && str_idx < size - 1; padding++) + { + if (negative && ((padding == arg_len && zpad) || (padding + 1 == min_width && !zpad))) + str[str_idx++] = '-'; + else + str[str_idx++] = zpad ? '0' : ' '; + } + } + else if (negative && str_idx < size - 1) + str[str_idx++] = '-'; + for (size_t arg_idx = 0; arg_idx < arg_len && str_idx < size - 1; arg_idx++) + str[str_idx++] = number[arg_idx]; + break; + + case 'u': + u64_arg = va_arg(ap, uint64_t); + arg_len = sigsafe_format_uint64_dec(u64_arg, number, sizeof(number)); + for (size_t padding = arg_len; padding < min_width && str_idx < size - 1; padding++) + str[str_idx++] = zpad ? '0' : ' '; + for (size_t arg_idx = 0; arg_idx < arg_len && str_idx < size - 1; arg_idx++) + str[str_idx++] = number[arg_idx]; + break; + + case 's': + string_arg = va_arg(ap, const char*); + if (!string_arg) + string_arg = "(null)"; + arg_len = strlen(string_arg); + for (size_t padding = arg_len; padding < min_width && str_idx < size - 1; padding++) + str[str_idx++] = ' '; + for (size_t arg_idx = 0; arg_idx < arg_len && str_idx < size - 1; arg_idx++) + str[str_idx++] = string_arg[arg_idx]; + break; + + case 'x': + u64_arg = va_arg(ap, uint64_t); + arg_len = sigsafe_format_uint64_hex(u64_arg, number, sizeof(number)); + for (size_t padding = arg_len; padding < min_width && str_idx < size - 1; padding++) + str[str_idx++] = zpad ? '0' : ' '; + for (size_t arg_idx = 0; arg_idx < arg_len && str_idx < size - 1; arg_idx++) + str[str_idx++] = number[arg_idx]; + break; + + default: + break; + } + } + + str[str_idx] = '\0'; +} + +static void sigsafe_snprintf(char* str, size_t size, const char* format, ...) +{ + va_list ap; + va_start(ap, format); + sigsafe_vsnprintf(str, size, format, ap); + va_end(ap); +} + +SigSafePrinter::SigSafePrinter(char *buf, size_t size) : buf(buf), buf_size(size) +{ + buf[0] = '\0'; +} + +void SigSafePrinter::write_string(const char* str) +{ + size_t len = strlen(str); + if (fd >= 0) + write(fd, str, len); + else if (buf) + { + if (len > buf_size - buf_idx - 1) + len = buf_size - buf_idx - 1; + strncpy(buf + buf_idx, str, len); + buf_idx += len; + buf[buf_idx] = '\0'; + } +} + +void SigSafePrinter::hex_dump(const uint8_t* data, unsigned len) +{ + char line[41]; + unsigned lidx = 0; + + for (unsigned i = 0; i < len; i++) + { + if (i > 0) + { + if (i % 16 == 0) + { + line[lidx++] = '\n'; + line[lidx] = '\0'; + write_string(line); + lidx = 0; + } + else if (i % 2 == 0) + line[lidx++] = ' '; + } + sigsafe_snprintf(line + lidx, sizeof(line) - lidx, "%02x", data[i]); + lidx += 2; + } + if (lidx) + { + line[lidx++] = '\n'; + line[lidx] = '\0'; + write_string(line); + } +} + +void SigSafePrinter::printf(const char *format, ...) +{ + char fmt_buf[1024]; + va_list ap; + va_start(ap, format); + sigsafe_vsnprintf(fmt_buf, sizeof(fmt_buf), format, ap); + va_end(ap); + write_string(fmt_buf); +} + +#ifdef CATCH_TEST_BUILD + +#include + +#include "catch/catch.hpp" + +TEST_CASE("sigsafe printer", "[SigsafePrinter]") +{ + using Catch::Matchers::Equals; + + uint64_t unsigned_tests[] = + { + 0, // Zero + 5, // Single digit number + 12, // Two digit decimal number + 37, // Two digit hex number + 0xC90B2, // Large < 32 bit number + 0x15D027BF211B37A, // Large > 32 bit number + 0xFFFFFFFFFFFFFFFF, // Maximum 64-bit number + }; + int64_t signed_tests[] = + { + 0, // Zero + 5, // Single digit number + 12, // Two digit decimal number + 37, // Two digit hex number + 0xC90B2, // Large < 32 bit number + 0x15D027BF211B37A, // Large > 32 bit number + 0x7FFFFFFFFFFFFFFF, // Maximum 64-bit signed number + -1, // Single digit number + -12, // Two digit decimal number + -0xC90B2, // Large < 32 bit number + -0x15D027BF211B37A, // Large > 32 bit number + -0x7FFFFFFFFFFFFFFF, // Maximum 64-bit signed number + } ; + char expected[1024]; + char actual[1024]; + SECTION("unsigned decimal") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%" PRIu64, unsigned_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%u", unsigned_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("padded unsigned decimal") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%32" PRIu64, unsigned_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%32u", unsigned_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("0-padded unsigned decimal") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%032" PRIu64, unsigned_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%032u", unsigned_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("signed decimal") + { + for (size_t i = 0; i < sizeof(signed_tests) / sizeof(*signed_tests); i++) + { + snprintf(expected, sizeof(expected), "%" PRId64, signed_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%d", signed_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("padded signed decimal") + { + for (size_t i = 0; i < sizeof(signed_tests) / sizeof(*signed_tests); i++) + { + snprintf(expected, sizeof(expected), "%32" PRId64, signed_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%32d", signed_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("0-padded signed decimal") + { + for (size_t i = 0; i < sizeof(signed_tests) / sizeof(*signed_tests); i++) + { + snprintf(expected, sizeof(expected), "%032" PRId64, signed_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%032d", signed_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("hex") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%" PRIx64, unsigned_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%x", unsigned_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("padded hex") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%2" PRIx64, unsigned_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%2x", unsigned_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("0-padded hex") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%02" PRIx64, unsigned_tests[i]); + SigSafePrinter(actual, sizeof(actual)).printf("%02x", unsigned_tests[i]); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("string") + { + snprintf(expected, sizeof(expected), "%s", "foobar"); + SigSafePrinter(actual, sizeof(actual)).printf("%s", "foobar"); + CHECK_THAT(expected, Equals(actual)); + } + SECTION("null string") + { + const char* nullstr = nullptr; + snprintf(expected, sizeof(expected), "%s", nullstr); + SigSafePrinter(actual, sizeof(actual)).printf("%s", nullstr); + CHECK_THAT(expected, Equals(actual)); + } + SECTION("padded string") + { + snprintf(expected, sizeof(expected), "%32s", "foobar"); + SigSafePrinter(actual, sizeof(actual)).printf("%32s", "foobar"); + CHECK_THAT(expected, Equals(actual)); + } + SECTION("all together now") + { + for (size_t i = 0; i < sizeof(unsigned_tests) / sizeof(*unsigned_tests); i++) + { + snprintf(expected, sizeof(expected), "%" PRIu64 " is %" PRIx64 " in %s!", + unsigned_tests[i], unsigned_tests[i], "hex"); + SigSafePrinter(actual, sizeof(actual)).printf("%u is %x in %s!", + unsigned_tests[i], unsigned_tests[i], "hex"); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("unrecognized conversion specifiers") + { + char format[32]; + snprintf(expected, sizeof(expected), "Nothing to see here: ."); + for (char c = 'A'; c < 'z'; c++) + { + if (c == 'd' || c == 's' || c == 'u' || c == 'x') + continue; + snprintf(format, sizeof(format), "Nothing to see here: %%%c.", c); + SigSafePrinter(actual, sizeof(actual)).printf(format, 0xDEADBEEF); + CHECK_THAT(expected, Equals(actual)); + } + } + SECTION("hexdump") + { + uint8_t data[32]; + unsigned offset = 0; + for (unsigned i = 0; i < sizeof(data); i++) + { + data[i] = i; + if (i > 0) + { + if (i % 16 == 0) + offset += snprintf(expected + offset, sizeof(expected) - offset, "\n"); + else if (i % 2 == 0) + offset += snprintf(expected + offset, sizeof(expected) - offset, " "); + } + offset += snprintf(expected + offset, sizeof(expected) - offset, "%02x", data[i]); + } + snprintf(expected + offset, sizeof(expected) - offset, "\n"); + SigSafePrinter(actual, sizeof(actual)).hex_dump(data, sizeof(data)); + CHECK_THAT(expected, Equals(actual)); + } +} + +#endif + diff --git a/src/helpers/sigsafe.h b/src/helpers/sigsafe.h new file mode 100644 index 000000000..ab1b24226 --- /dev/null +++ b/src/helpers/sigsafe.h @@ -0,0 +1,46 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program 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 +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- +// sigsafe.h author Michael Altizer + +#ifndef SIGSAFE_H +#define SIGSAFE_H + +#include +#include + +class SigSafePrinter +{ +public: + SigSafePrinter(char *buf, size_t size); + SigSafePrinter(int fd) : fd(fd) { } + + void hex_dump(const uint8_t* data, unsigned len); + void printf(const char* format, ...); + +private: + void write_string(const char* str); + +private: + char* buf = nullptr; + size_t buf_size = 0; + size_t buf_idx = 0; + int fd = -1; +}; + +#endif + diff --git a/src/main/analyzer.cc b/src/main/analyzer.cc index dcc89bf67..98c193b01 100644 --- a/src/main/analyzer.cc +++ b/src/main/analyzer.cc @@ -395,6 +395,7 @@ void Analyzer::post_process_daq_pkt_msg(Packet* p) if (verdict == DAQ_VERDICT_BLOCK or verdict == DAQ_VERDICT_BLACKLIST) p->active->send_reason_to_daq(*p); + oops_handler->set_current_message(nullptr); p->pkth = nullptr; // No longer avail after finalize_message. { @@ -417,7 +418,6 @@ void Analyzer::process_daq_pkt_msg(DAQ_Msg_h msg, bool retry) switcher->start(); Packet* p = switcher->get_context()->packet; - oops_handler->set_current_packet(p); p->context->wire_packet = p; p->context->packet_number = get_packet_number(); set_default_policy(p->context->conf); @@ -437,13 +437,13 @@ void Analyzer::process_daq_pkt_msg(DAQ_Msg_h msg, bool retry) switcher->stop(); } - oops_handler->set_current_packet(nullptr); Stream::handle_timeouts(false); HighAvailabilityManager::process_receive(); } void Analyzer::process_daq_msg(DAQ_Msg_h msg, bool retry) { + oops_handler->set_current_message(msg); DAQ_Verdict verdict = DAQ_VERDICT_PASS; switch (daq_msg_get_type(msg)) { @@ -463,6 +463,7 @@ void Analyzer::process_daq_msg(DAQ_Msg_h msg, bool retry) } break; } + oops_handler->set_current_message(nullptr); { Profile profile(daqPerfStats); daq_instance->finalize_message(msg, verdict); @@ -682,7 +683,7 @@ void Analyzer::term() HighAvailabilityManager::thread_term(); SideChannelManager::thread_term(); - oops_handler->set_current_packet(nullptr); + oops_handler->set_current_message(nullptr); daq_instance->stop(); SFDAQ::set_local_instance(nullptr); @@ -715,6 +716,7 @@ Analyzer::Analyzer(SFDAQInstance* instance, unsigned i, const char* s, uint64_t exit_after_cnt = msg_cnt; source = s ? s : ""; daq_instance = instance; + oops_handler = new OopsHandler(); retry_queue = new RetryQueue(200); set_state(State::NEW); } @@ -728,7 +730,7 @@ Analyzer::~Analyzer() void Analyzer::operator()(Swapper* ps, uint16_t run_num) { - oops_handler = new OopsHandler(); + oops_handler->tinit(); set_thread_type(STHREAD_TYPE_PACKET); set_instance_id(id); @@ -761,6 +763,8 @@ void Analyzer::operator()(Swapper* ps, uint16_t run_num) term(); set_state(State::STOPPED); + + oops_handler->tterm(); } /* Note: This will be called from the main thread. Everything it does must be diff --git a/src/main/oops_handler.cc b/src/main/oops_handler.cc index 890ce1652..b270da127 100644 --- a/src/main/oops_handler.cc +++ b/src/main/oops_handler.cc @@ -23,38 +23,58 @@ #include "oops_handler.h" -#include "protocols/packet.h" +#include + +#include +#include + +#include "helpers/sigsafe.h" + +#include "thread.h" static THREAD_LOCAL OopsHandler* local_oops_handler = nullptr; -void OopsHandler::handle_crash() +void OopsHandler::handle_crash(int fd) { if (local_oops_handler) - local_oops_handler->eternalize(); + local_oops_handler->eternalize(fd); } -OopsHandler::OopsHandler() +void OopsHandler::tinit() { assert(local_oops_handler == nullptr); local_oops_handler = this; } -OopsHandler::~OopsHandler() +void OopsHandler::tterm() { local_oops_handler = nullptr; } -void OopsHandler::eternalize() +void OopsHandler::eternalize(int fd) { - // Copy the crashed thread's data. C++11 specs ensure the - // thread that segfaulted will still be running. - if (packet && packet->pkth) - { - pkth = *(packet->pkth); - if (packet->pkt) - { - memcpy(data, packet->pkt, 0xFFFF & packet->pktlen); - packet->pkt = data; - } - } + if (!msg) + return; + + // Copy the crashed thread's data. C++11 specs ensure the thread that segfaulted will + // still be running. + // Signal safety of functions called from here (POSIX async-signal-safe requirement): + // memcpy POSIX.1-2016 + type = daq_msg_get_type(msg); + header_len = daq_msg_get_hdr_len(msg); + memcpy(header, daq_msg_get_hdr(msg), std::min(header_len, sizeof(header))); + data_len = daq_msg_get_data_len(msg); + memcpy(data, daq_msg_get_data(msg), std::min(data_len, sizeof(data))); + + if (fd < 0) + return; + + // Dump the eternalized information to the file descriptor for coreless debugging + SigSafePrinter ssp(fd); + ssp.printf("= Current DAQ Message (Type %u) =\n\n", static_cast(type)); + ssp.printf("== Header (%u) ==\n", header_len); + ssp.hex_dump(header, header_len); + ssp.printf("\n== Data (%u) ==\n", data_len); + ssp.hex_dump(data, data_len); + ssp.printf("\n"); } diff --git a/src/main/oops_handler.h b/src/main/oops_handler.h index 61685f915..a6570136e 100644 --- a/src/main/oops_handler.h +++ b/src/main/oops_handler.h @@ -22,25 +22,29 @@ #include -namespace snort -{ -struct Packet; -} - class OopsHandler { public: - static void handle_crash(); + static void handle_crash(int fd); + + OopsHandler() = default; + ~OopsHandler() = default; - OopsHandler(); - ~OopsHandler(); - void set_current_packet(snort::Packet* p) { packet = p; } - void eternalize(); + void tinit(); + void set_current_message(DAQ_Msg_h cm) { msg = cm; } + void tterm(); + +private: + void eternalize(int fd); private: - DAQ_PktHdr_t pkth = { }; - uint8_t data[65535] = { }; - snort::Packet* packet = nullptr; + DAQ_Msg_h msg = nullptr; + // Eternalized data + DAQ_MsgType type = static_cast(0); + uint8_t header[UINT16_MAX] = { }; + size_t header_len = 0; + uint8_t data[UINT16_MAX] = { }; + uint32_t data_len = 0; }; #endif diff --git a/src/main/test/stubs.h b/src/main/test/stubs.h index 7c3581a76..ac572c840 100644 --- a/src/main/test/stubs.h +++ b/src/main/test/stubs.h @@ -69,8 +69,8 @@ void Profiler::consolidate_stats() { } void ThreadConfig::implement_thread_affinity(SThreadType, unsigned) { } void Swapper::apply(Analyzer&) { } Swapper::~Swapper() { } -OopsHandler::OopsHandler() { } -OopsHandler::~OopsHandler() { } +void OopsHandler::tinit() { } +void OopsHandler::tterm() { } uint16_t get_run_num() { return 0; } void set_run_num(uint16_t) { } void set_instance_id(unsigned) { } diff --git a/src/network_inspectors/perf_monitor/CMakeLists.txt b/src/network_inspectors/perf_monitor/CMakeLists.txt index f13548656..0ae753917 100644 --- a/src/network_inspectors/perf_monitor/CMakeLists.txt +++ b/src/network_inspectors/perf_monitor/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( FLATBUFFERS_FOUND ) +if ( HAVE_FLATBUFFERS ) set( FLATBUFFERS_SOURCE fbs_formatter.h fbs_formatter.cc ) endif() @@ -39,7 +39,7 @@ else (STATIC_INSPECTORS) endif (STATIC_INSPECTORS) -if ( FLATBUFFERS_FOUND ) +if ( HAVE_FLATBUFFERS ) target_include_directories( perf_monitor PRIVATE ${FLATBUFFERS_INCLUDE_DIR} ) endif() @@ -57,7 +57,7 @@ add_catch_test( json_formatter_test perf_formatter.cc ) -if ( FLATBUFFERS_FOUND ) +if ( HAVE_FLATBUFFERS ) add_catch_test( fbs_formatter_test NO_TEST_SOURCE SOURCES diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index d22b039ca..a8ebc8e6f 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -43,7 +43,7 @@ add_library ( utils OBJECT ${TEST_FILES} ) -if ( FLATBUFFERS_FOUND ) +if ( HAVE_FLATBUFFERS ) target_include_directories( utils PRIVATE ${FLATBUFFERS_INCLUDE_DIR} ) endif() diff --git a/tools/flatbuffers/CMakeLists.txt b/tools/flatbuffers/CMakeLists.txt index 201ded1c6..f0d716727 100644 --- a/tools/flatbuffers/CMakeLists.txt +++ b/tools/flatbuffers/CMakeLists.txt @@ -1,4 +1,4 @@ -if ( FLATBUFFERS_FOUND ) +if ( HAVE_FLATBUFFERS ) add_executable( fbstreamer fbstreamer.cc )