log: Don't close file log fds that are being used by the err module

Instead, dup() file log fds, before passing them to the err module.

Closes 31613, part of 31594.
This commit is contained in:
teor 2019-09-04 15:38:58 +10:00
parent d02ced4caf
commit a22fbab986
No known key found for this signature in database
GPG Key ID: 10FEAA0E7075672A
2 changed files with 40 additions and 9 deletions

View File

@ -111,6 +111,12 @@ tor_log_get_sigsafe_err_fds(const int **out)
* other emergency condition. Ignore any beyond the first * other emergency condition. Ignore any beyond the first
* TOR_SIGSAFE_LOG_MAX_FDS. * TOR_SIGSAFE_LOG_MAX_FDS.
* *
* These fds must remain open even after the log module has shut down. (And
* they should remain open even while logs are being reconfigured.) Therefore,
* any fds closed by the log module should be dup()ed, and the duplicate fd
* should be given to the err module in fds. In particular, the log module
* closes the file log fds, but does not close the stdio log fds.
*
* If fds is NULL or n is 0, clears the list of error fds. * If fds is NULL or n is 0, clears the list of error fds.
*/ */
void void

View File

@ -664,13 +664,24 @@ tor_log_update_sigsafe_err_fds(void)
const logfile_t *lf; const logfile_t *lf;
int found_real_stderr = 0; int found_real_stderr = 0;
int fds[TOR_SIGSAFE_LOG_MAX_FDS]; /* log_fds and err_fds contain matching entries: log_fds are the fds used by
* the log module, and err_fds are the fds used by the err module.
* For stdio logs, the log_fd and err_fd values are identical,
* and the err module closes the fd on shutdown.
* For file logs, the err_fd is a dup() of the log_fd,
* and the log and err modules both close their respective fds on shutdown.
* (Once all fds representing a file are closed, the underlying file is
* closed.)
*/
int log_fds[TOR_SIGSAFE_LOG_MAX_FDS];
int err_fds[TOR_SIGSAFE_LOG_MAX_FDS];
int n_fds; int n_fds;
LOCK_LOGS(); LOCK_LOGS();
/* Reserve the first one for stderr. This is safe because when we daemonize, /* Reserve the first one for stderr. This is safe because when we daemonize,
* we dup2 /dev/null to stderr, */ * we dup2 /dev/null to stderr.
fds[0] = STDERR_FILENO; * For stderr, log_fds and err_fds are the same. */
log_fds[0] = err_fds[0] = STDERR_FILENO;
n_fds = 1; n_fds = 1;
for (lf = logfiles; lf; lf = lf->next) { for (lf = logfiles; lf; lf = lf->next) {
@ -684,25 +695,39 @@ tor_log_update_sigsafe_err_fds(void)
(LD_BUG|LD_GENERAL)) { (LD_BUG|LD_GENERAL)) {
if (lf->fd == STDERR_FILENO) if (lf->fd == STDERR_FILENO)
found_real_stderr = 1; found_real_stderr = 1;
/* Avoid duplicates */ /* Avoid duplicates by checking the log module fd against log_fds */
if (int_array_contains(fds, n_fds, lf->fd)) if (int_array_contains(log_fds, n_fds, lf->fd))
continue; continue;
fds[n_fds++] = lf->fd; /* Update log_fds using the log module's fd */
log_fds[n_fds] = lf->fd;
if (lf->needs_close) {
/* File log fds are duplicated, because close_log() closes the log
* module's fd, and tor_log_close_sigsafe_err_fds() closes the err
* module's fd. Both refer to the same file. */
err_fds[n_fds] = dup(lf->fd);
} else {
/* stdio log fds are not closed by the log module.
* tor_log_close_sigsafe_err_fds() closes stdio logs. */
err_fds[n_fds] = lf->fd;
}
n_fds++;
if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS) if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
break; break;
} }
} }
if (!found_real_stderr && if (!found_real_stderr &&
int_array_contains(fds, n_fds, STDOUT_FILENO)) { int_array_contains(log_fds, n_fds, STDOUT_FILENO)) {
/* Don't use a virtual stderr when we're also logging to stdout. */ /* Don't use a virtual stderr when we're also logging to stdout. */
raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */ raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
fds[0] = fds[--n_fds]; --n_fds;
log_fds[0] = log_fds[n_fds];
err_fds[0] = err_fds[n_fds];
} }
UNLOCK_LOGS(); UNLOCK_LOGS();
tor_log_set_sigsafe_err_fds(fds, n_fds); tor_log_set_sigsafe_err_fds(err_fds, n_fds);
} }
/** Add to <b>out</b> a copy of every currently configured log file name. Used /** Add to <b>out</b> a copy of every currently configured log file name. Used