log: Close log and err file descriptors before aborting

Part of 31594.
This commit is contained in:
teor 2019-09-04 17:16:49 +10:00
parent a22fbab986
commit 1609916c79
No known key found for this signature in database
GPG Key ID: 10FEAA0E7075672A
7 changed files with 69 additions and 12 deletions

View File

@ -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. */

View File

@ -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;

View File

@ -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);

View File

@ -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
@ -858,14 +883,27 @@ delete_log(logfile_t *victim)
log_free(victim);
}
/** Helper: release system resources (but not memory) held by a single
* signal-safe logfile_t. If the log's resources can not be released in
* a signal handler, does nothing. */
static void
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 && victim->fd >= 0) {
close(victim->fd);
victim->fd = -1;
if (victim->needs_close) {
close_log_sigsafe(victim);
} else if (victim->is_syslog) {
#ifdef HAVE_SYSLOG_H
if (--syslog_count == 0) {

View File

@ -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);

View File

@ -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

View File

@ -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