Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
David Goulet
Tor
Commits
9769df89
Commit
9769df89
authored
Oct 22, 2019
by
Nick Mathewson
⛰
Browse files
Merge remote-tracking branch 'tor-github/pr/1303' into maint-0.4.1
parents
c1bf4260
ebce7059
Changes
9
Hide whitespace changes
Inline
Side-by-side
changes/bug31594
0 → 100644
View file @
9769df89
o Minor bugfixes (error handling):
- When tor aborts due to an error, close log file descriptors before
aborting. Closing the logs makes some OSes flush log file buffers,
rather than deleting buffered log lines. Fixes bug 31594;
bugfix on 0.2.5.2-alpha.
src/lib/err/backtrace.c
View file @
9769df89
...
...
@@ -173,7 +173,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. */
...
...
src/lib/err/torerr.c
View file @
9769df89
...
...
@@ -110,6 +110,14 @@ 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.
*
* 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.
*/
void
tor_log_set_sigsafe_err_fds
(
const
int
*
fds
,
int
n
)
...
...
@@ -118,8 +126,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 +150,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.
...
...
@@ -164,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
...
...
@@ -198,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
];
...
...
@@ -207,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
;
...
...
src/lib/err/torerr.h
View file @
9769df89
...
...
@@ -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
,
...
...
@@ -40,8 +40,11 @@ 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
);
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
);
...
...
src/lib/err/torerr_sys.c
View file @
9769df89
...
...
@@ -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
=
{
...
...
src/lib/log/log.c
View file @
9769df89
...
...
@@ -225,6 +225,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
);
...
...
@@ -665,13 +666,24 @@ tor_log_update_sigsafe_err_fds(void)
const
logfile_t
*
lf
;
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
;
LOCK_LOGS
();
/* Reserve the first one for stderr. This is safe because when we daemonize,
* we dup2 /dev/null to stderr, */
fds
[
0
]
=
STDERR_FILENO
;
* we dup2 /dev/null to stderr.
* For stderr, log_fds and err_fds are the same. */
log_fds
[
0
]
=
err_fds
[
0
]
=
STDERR_FILENO
;
n_fds
=
1
;
for
(
lf
=
logfiles
;
lf
;
lf
=
lf
->
next
)
{
...
...
@@ -685,25 +697,39 @@ tor_log_update_sigsafe_err_fds(void)
(
LD_BUG
|
LD_GENERAL
))
{
if
(
lf
->
fd
==
STDERR_FILENO
)
found_real_stderr
=
1
;
/* Avoid duplicates */
if
(
int_array_contains
(
fds
,
n_fds
,
lf
->
fd
))
/* Avoid duplicates
by checking the log module fd against log_fds
*/
if
(
int_array_contains
(
log_
fds
,
n_fds
,
lf
->
fd
))
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
)
break
;
}
}
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. */
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
();
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
...
...
@@ -812,6 +838,30 @@ logs_free_all(void)
* log mutex. */
}
/** 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
...
...
@@ -838,13 +888,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
)
{
...
...
src/lib/log/log.h
View file @
9769df89
...
...
@@ -173,6 +173,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
);
...
...
src/lib/log/util_bug.c
View file @
9769df89
...
...
@@ -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"
...
...
@@ -161,16 +162,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
...
...
src/trunnel/trunnel-local.h
View file @
9769df89
...
...
@@ -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
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment