From d02ced4cafaed5b11079585f03f47e73034dd980 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 4 Sep 2019 14:54:08 +1000 Subject: [PATCH] torerr: Close sigsafe fds on shutdown And clear the list of error fds. Part of 31594. --- src/lib/err/torerr.c | 42 ++++++++++++++++++++++++++++++++++++++-- src/lib/err/torerr.h | 1 + src/lib/err/torerr_sys.c | 5 ++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c index ecffb7f7bb..2c4a10a5bb 100644 --- a/src/lib/err/torerr.c +++ b/src/lib/err/torerr.c @@ -110,6 +110,8 @@ tor_log_get_sigsafe_err_fds(const int **out) * Update the list of fds that get errors from inside a signal handler or * other emergency condition. Ignore any beyond the first * TOR_SIGSAFE_LOG_MAX_FDS. + * + * If fds is NULL or n is 0, clears the list of error fds. */ void tor_log_set_sigsafe_err_fds(const int *fds, int n) @@ -118,8 +120,18 @@ tor_log_set_sigsafe_err_fds(const int *fds, int n) n = TOR_SIGSAFE_LOG_MAX_FDS; } - memcpy(sigsafe_log_fds, fds, n * sizeof(int)); - n_sigsafe_log_fds = n; + /* Clear the entire array. This code mitigates against some race conditions, + * but there are still some races here: + * - err logs are disabled while the array is cleared, and + * - a thread can read the old value of n_sigsafe_log_fds, then read a + * partially written array. + * We could fix these races using atomics, but atomics use the err module. */ + n_sigsafe_log_fds = 0; + memset(sigsafe_log_fds, 0, sizeof(sigsafe_log_fds)); + if (fds && n > 0) { + memcpy(sigsafe_log_fds, fds, n * sizeof(int)); + n_sigsafe_log_fds = n; + } } /** @@ -132,6 +144,32 @@ tor_log_reset_sigsafe_err_fds(void) tor_log_set_sigsafe_err_fds(fds, 1); } +/** + * Close the list of fds that get errors from inside a signal handler or + * other emergency condition. These fds are shared with the logging code: + * closing them flushes the log buffers, and prevents any further logging. + * + * This function closes stderr, so it should only be called immediately before + * process shutdown. + */ +void +tor_log_close_sigsafe_err_fds(void) +{ + int n_fds, i; + const int *fds = NULL; + + n_fds = tor_log_get_sigsafe_err_fds(&fds); + for (i = 0; i < n_fds; ++i) { + /* tor_log_close_sigsafe_err_fds_on_error() is called on error and on + * shutdown, so we can't log or take any useful action if close() + * fails. */ + (void)close(fds[i]); + } + + /* Don't even try logging, we've closed all the log fds. */ + tor_log_set_sigsafe_err_fds(NULL, 0); +} + /** * Set the granularity (in ms) to use when reporting fatal errors outside * the logging system. diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h index 0badaf7c6d..3b86d20394 100644 --- a/src/lib/err/torerr.h +++ b/src/lib/err/torerr.h @@ -40,6 +40,7 @@ void tor_log_err_sigsafe(const char *m, ...); int tor_log_get_sigsafe_err_fds(const int **out); void tor_log_set_sigsafe_err_fds(const int *fds, int n); 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); int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c index 3ab1b3c4e1..a14c46f945 100644 --- a/src/lib/err/torerr_sys.c +++ b/src/lib/err/torerr_sys.c @@ -27,8 +27,11 @@ subsys_torerr_initialize(void) static void subsys_torerr_shutdown(void) { - tor_log_reset_sigsafe_err_fds(); + /* Stop handling signals with backtraces, then close the logs. */ clean_up_backtrace_handler(); + /* We can't log any log messages after this point: we've closed all the log + * fds, including stdio. */ + tor_log_close_sigsafe_err_fds(); } const subsys_fns_t sys_torerr = {