diff options
author | teor <teor@torproject.org> | 2019-09-04 17:16:49 +1000 |
---|---|---|
committer | teor <teor@torproject.org> | 2019-09-09 14:56:42 +1000 |
commit | 1609916c79612b5cc3a9b363a22f1a9035f2f77b (patch) | |
tree | 3b67c49c864222489cd01da12a8db120a7311b1c | |
parent | a22fbab98690f802ae3bda276078cc7fc767feba (diff) | |
download | tor-1609916c79612b5cc3a9b363a22f1a9035f2f77b.tar.gz tor-1609916c79612b5cc3a9b363a22f1a9035f2f77b.zip |
log: Close log and err file descriptors before aborting
Part of 31594.
-rw-r--r-- | src/lib/err/backtrace.c | 2 | ||||
-rw-r--r-- | src/lib/err/torerr.c | 16 | ||||
-rw-r--r-- | src/lib/err/torerr.h | 6 | ||||
-rw-r--r-- | src/lib/log/log.c | 42 | ||||
-rw-r--r-- | src/lib/log/log.h | 1 | ||||
-rw-r--r-- | src/lib/log/util_bug.c | 11 | ||||
-rw-r--r-- | src/trunnel/trunnel-local.h | 1 |
7 files changed, 68 insertions, 11 deletions
diff --git a/src/lib/err/backtrace.c b/src/lib/err/backtrace.c index 1d1b3bcfa3..643fe862b0 100644 --- a/src/lib/err/backtrace.c +++ b/src/lib/err/backtrace.c @@ -172,7 +172,7 @@ crash_handler(int sig, siginfo_t *si, void *ctx_) for (i=0; i < n_fds; ++i) backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); - abort(); + tor_raw_abort_(); } /** Write a backtrace to all of the emergency-error fds. */ diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c index f460fd8379..21b28a5f69 100644 --- a/src/lib/err/torerr.c +++ b/src/lib/err/torerr.c @@ -208,6 +208,18 @@ tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr, dump_stack_symbols_to_error_fds(); } +/** + * Call the abort() function to kill the current process with a fatal + * error. But first, close the raw error file descriptors, so error messages + * are written before process termination. + **/ +void +tor_raw_abort_(void) +{ + tor_log_close_sigsafe_err_fds(); + abort(); +} + /* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument * in range 2..16 inclusive. */ static int @@ -242,7 +254,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len, unsigned digit = (unsigned) (x % radix); if (cp <= buf) { /* Not tor_assert(); see above. */ - abort(); + tor_raw_abort_(); } --cp; *cp = "0123456789ABCDEF"[digit]; @@ -251,7 +263,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len, /* NOT tor_assert; see above. */ if (cp != buf) { - abort(); // LCOV_EXCL_LINE + tor_raw_abort_(); // LCOV_EXCL_LINE } return len; diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h index 3b86d20394..a41109527e 100644 --- a/src/lib/err/torerr.h +++ b/src/lib/err/torerr.h @@ -20,13 +20,13 @@ #define raw_assert(expr) STMT_BEGIN \ if (!(expr)) { \ tor_raw_assertion_failed_msg_(__FILE__, __LINE__, #expr, NULL); \ - abort(); \ + tor_raw_abort_(); \ } \ STMT_END #define raw_assert_unreached(expr) raw_assert(0) #define raw_assert_unreached_msg(msg) STMT_BEGIN \ tor_raw_assertion_failed_msg_(__FILE__, __LINE__, "0", (msg)); \ - abort(); \ + tor_raw_abort_(); \ STMT_END void tor_raw_assertion_failed_msg_(const char *file, int line, @@ -43,6 +43,8 @@ void tor_log_reset_sigsafe_err_fds(void); void tor_log_close_sigsafe_err_fds(void); void tor_log_sigsafe_err_set_granularity(int ms); +void tor_raw_abort_(void) ATTR_NORETURN; + int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); diff --git a/src/lib/log/log.c b/src/lib/log/log.c index 2214d4b59d..4adcc5cf57 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -224,6 +224,7 @@ int log_global_min_severity_ = LOG_NOTICE; static void delete_log(logfile_t *victim); static void close_log(logfile_t *victim); +static void close_log_sigsafe(logfile_t *victim); static char *domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen); @@ -833,6 +834,30 @@ logs_free_all(void) * that happened between here and the end of execution. */ } +/** Close signal-safe log files. + * Closing the log files makes the process and OS flush log buffers. + * + * This function is safe to call from a signal handler. It should only be + * called when shutting down the log or err modules. It is currenly called + * by the err module, when terminating the process on an abnormal condition. + */ +void +logs_close_sigsafe(void) +{ + logfile_t *victim, *next; + /* We can't LOCK_LOGS() in a signal handler, because it may call + * signal-unsafe functions. And we can't deallocate memory, either. */ + next = logfiles; + logfiles = NULL; + while (next) { + victim = next; + next = next->next; + if (victim->needs_close) { + close_log_sigsafe(victim); + } + } +} + /** Remove and free the log entry <b>victim</b> from the linked-list * logfiles (it is probably present, but it might not be due to thread * racing issues). After this function is called, the caller shouldn't @@ -859,13 +884,26 @@ delete_log(logfile_t *victim) } /** Helper: release system resources (but not memory) held by a single - * logfile_t. */ + * signal-safe logfile_t. If the log's resources can not be released in + * a signal handler, does nothing. */ static void -close_log(logfile_t *victim) +close_log_sigsafe(logfile_t *victim) { if (victim->needs_close && victim->fd >= 0) { + /* We can't do anything useful here if close() fails: we're shutting + * down logging, and the err module only does fatal errors. */ close(victim->fd); victim->fd = -1; + } +} + +/** Helper: release system resources (but not memory) held by a single + * logfile_t. */ +static void +close_log(logfile_t *victim) +{ + if (victim->needs_close) { + close_log_sigsafe(victim); } else if (victim->is_syslog) { #ifdef HAVE_SYSLOG_H if (--syslog_count == 0) { diff --git a/src/lib/log/log.h b/src/lib/log/log.h index dbc1c47021..360951783e 100644 --- a/src/lib/log/log.h +++ b/src/lib/log/log.h @@ -170,6 +170,7 @@ void logs_set_domain_logging(int enabled); int get_min_log_level(void); void switch_logs_debug(void); void logs_free_all(void); +void logs_close_sigsafe(void); void add_temp_log(int min_severity); void close_temp_logs(void); void rollback_log_changes(void); diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index c65a91ae9e..3435108848 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -11,6 +11,7 @@ #include "lib/log/util_bug.h" #include "lib/log/log.h" #include "lib/err/backtrace.h" +#include "lib/err/torerr.h" #ifdef TOR_UNIT_TESTS #include "lib/smartlist_core/smartlist_core.h" #include "lib/smartlist_core/smartlist_foreach.h" @@ -122,16 +123,18 @@ tor_bug_occurred_(const char *fname, unsigned int line, } /** - * Call the abort() function to kill the current process with a fatal - * error. + * Call the tor_raw_abort_() function to close raw logs, then kill the current + * process with a fatal error. But first, close the file-based log file + * descriptors, so error messages are written before process termination. * * (This is a separate function so that we declare it in util_bug.h without - * including stdlib in all the users of util_bug.h) + * including torerr.h in all the users of util_bug.h) **/ void tor_abort_(void) { - abort(); + logs_close_sigsafe(); + tor_raw_abort_(); } #ifdef _WIN32 diff --git a/src/trunnel/trunnel-local.h b/src/trunnel/trunnel-local.h index c4118fce4c..80da371560 100644 --- a/src/trunnel/trunnel-local.h +++ b/src/trunnel/trunnel-local.h @@ -14,5 +14,6 @@ #define trunnel_reallocarray tor_reallocarray #define trunnel_assert tor_assert #define trunnel_memwipe(mem, len) memwipe((mem), 0, (len)) +#define trunnel_abort tor_abort_ #endif |