Add support for Android's logging subsystem.

This patch adds support for Android's logging subsystem in Tor. When
debugging Android applications it is useful to be able to collect
information about the application running on the platform via the
various system services that is available on the platform.

This patch allows you to add "Log notice android" to your torrc and have
Tor send everything above and including the notice severity to Android's
ring buffer which can be inspected using the 'adb logcat' program.

See: https://bugs.torproject.org/24362
This commit is contained in:
Alexander Færøy 2017-12-11 13:12:25 +00:00
parent 78a582ed88
commit b0b8f7c30c
7 changed files with 122 additions and 5 deletions

2
changes/bug24362 Normal file
View File

@ -0,0 +1,2 @@
o Minor features (logging, android):
- Added support for the Android logging subsystem. Closes ticket 24362.

View File

@ -204,6 +204,20 @@ if test x$enable_event_tracing_debug = xyes; then
AC_DEFINE([TOR_EVENT_TRACING_ENABLED], [1], [Compile the event tracing instrumentation]) AC_DEFINE([TOR_EVENT_TRACING_ENABLED], [1], [Compile the event tracing instrumentation])
fi fi
dnl Enable Android only features.
AC_ARG_ENABLE(android,
AS_HELP_STRING(--enable-android, [build with Android features enabled]))
AM_CONDITIONAL([USE_ANDROID], [test "x$enable_android" = "xyes"])
if test "x$enable_android" = "xyes"; then
AC_DEFINE([USE_ANDROID], [1], [Compile with Android specific features enabled])
dnl Check if the Android log library is available.
AC_CHECK_HEADERS([android/log.h])
AC_SEARCH_LIBS(__android_log_write, [log])
fi
dnl check for the correct "ar" when cross-compiling. dnl check for the correct "ar" when cross-compiling.
dnl (AM_PROG_AR was new in automake 1.11.2, which we do not yet require, dnl (AM_PROG_AR was new in automake 1.11.2, which we do not yet require,
dnl so kludge up a replacement for the case where it isn't there yet.) dnl so kludge up a replacement for the case where it isn't there yet.)

View File

@ -727,6 +727,11 @@ GENERAL OPTIONS
log entries are marked with "Tor-__tag__". Can not be changed while tor is log entries are marked with "Tor-__tag__". Can not be changed while tor is
running. (Default: none) running. (Default: none)
[[AndroidIdentityTag]] **AndroidIdentityTag** __tag__::
When logging to Android's logging subsystem, adds a tag to the log identity
such that log entries are marked with "Tor-__tag__". Can not be changed while
tor is running. (Default: none)
[[SafeLogging]] **SafeLogging** **0**|**1**|**relay**:: [[SafeLogging]] **SafeLogging** **0**|**1**|**relay**::
Tor can scrub potentially sensitive strings from log messages (e.g. Tor can scrub potentially sensitive strings from log messages (e.g.
addresses) by replacing them with the string [scrubbed]. This way logs can addresses) by replacing them with the string [scrubbed]. This way logs can

View File

@ -35,6 +35,9 @@
#define LOG_PRIVATE #define LOG_PRIVATE
#include "torlog.h" #include "torlog.h"
#include "container.h" #include "container.h"
#ifdef HAVE_ANDROID_LOG_H
#include <android/log.h>
#endif // HAVE_ANDROID_LOG_H.
/** Given a severity, yields an index into log_severity_list_t.masks to use /** Given a severity, yields an index into log_severity_list_t.masks to use
* for that severity. */ * for that severity. */
@ -58,6 +61,8 @@ typedef struct logfile_t {
int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */ int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */
int is_temporary; /**< Boolean: close after initializing logging subsystem.*/ int is_temporary; /**< Boolean: close after initializing logging subsystem.*/
int is_syslog; /**< Boolean: send messages to syslog. */ int is_syslog; /**< Boolean: send messages to syslog. */
int is_android; /**< Boolean: send messages to Android's log subsystem. */
char *android_tag; /**< Identity Tag used in Android's log subsystem. */
log_callback callback; /**< If not NULL, send messages to this function. */ log_callback callback; /**< If not NULL, send messages to this function. */
log_severity_list_t *severities; /**< Which severity of messages should we log_severity_list_t *severities; /**< Which severity of messages should we
* log for each log domain? */ * log for each log domain? */
@ -103,6 +108,33 @@ should_log_function_name(log_domain_mask_t domain, int severity)
} }
} }
#ifdef HAVE_ANDROID_LOG_H
/** Helper function to convert Tor's log severity into the matching
* Android log priority.
*/
static int
severity_to_android_log_priority(int severity)
{
switch (severity) {
case LOG_DEBUG:
return ANDROID_LOG_VERBOSE;
case LOG_INFO:
return ANDROID_LOG_DEBUG;
case LOG_NOTICE:
return ANDROID_LOG_INFO;
case LOG_WARN:
return ANDROID_LOG_WARN;
case LOG_ERR:
return ANDROID_LOG_ERROR;
default:
// LCOV_EXCL_START
raw_assert(0);
return 0;
// LCOV_EXCL_STOP
}
}
#endif // HAVE_ANDROID_LOG_H.
/** A mutex to guard changes to logfiles and logging. */ /** A mutex to guard changes to logfiles and logging. */
static tor_mutex_t log_mutex; static tor_mutex_t log_mutex;
/** True iff we have initialized log_mutex */ /** True iff we have initialized log_mutex */
@ -411,7 +443,7 @@ logfile_wants_message(const logfile_t *lf, int severity,
if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
return 0; return 0;
} }
if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) { if (! (lf->fd >= 0 || lf->is_syslog || lf->is_android || lf->callback)) {
return 0; return 0;
} }
if (lf->seems_dead) { if (lf->seems_dead) {
@ -454,6 +486,11 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
syslog(severity, "%s", msg_after_prefix); syslog(severity, "%s", msg_after_prefix);
#endif /* defined(MAXLINE) */ #endif /* defined(MAXLINE) */
#endif /* defined(HAVE_SYSLOG_H) */ #endif /* defined(HAVE_SYSLOG_H) */
} else if (lf->is_android) {
#ifdef HAVE_ANDROID_LOG_H
int priority = severity_to_android_log_priority(severity);
__android_log_write(priority, lf->android_tag, msg_after_prefix);
#endif // HAVE_ANDROID_LOG_H.
} else if (lf->callback) { } else if (lf->callback) {
if (domain & LD_NOCB) { if (domain & LD_NOCB) {
if (!*callbacks_deferred && pending_cb_messages) { if (!*callbacks_deferred && pending_cb_messages) {
@ -646,7 +683,7 @@ tor_log_update_sigsafe_err_fds(void)
/* Don't try callback to the control port, or syslogs: We can't /* Don't try callback to the control port, or syslogs: We can't
* do them from a signal handler. Don't try stdout: we always do stderr. * do them from a signal handler. Don't try stdout: we always do stderr.
*/ */
if (lf->is_temporary || lf->is_syslog || if (lf->is_temporary || lf->is_syslog || lf->is_android ||
lf->callback || lf->seems_dead || lf->fd < 0) lf->callback || lf->seems_dead || lf->fd < 0)
continue; continue;
if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] & if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
@ -683,7 +720,7 @@ tor_log_get_logfile_names(smartlist_t *out)
LOCK_LOGS(); LOCK_LOGS();
for (lf = logfiles; lf; lf = lf->next) { for (lf = logfiles; lf; lf = lf->next) {
if (lf->is_temporary || lf->is_syslog || lf->callback) if (lf->is_temporary || lf->is_syslog || lf->is_android || lf->callback)
continue; continue;
if (lf->filename == NULL) if (lf->filename == NULL)
continue; continue;
@ -732,6 +769,7 @@ log_free_(logfile_t *victim)
return; return;
tor_free(victim->severities); tor_free(victim->severities);
tor_free(victim->filename); tor_free(victim->filename);
tor_free(victim->android_tag);
tor_free(victim); tor_free(victim);
} }
@ -1151,6 +1189,39 @@ add_syslog_log(const log_severity_list_t *severity,
} }
#endif /* defined(HAVE_SYSLOG_H) */ #endif /* defined(HAVE_SYSLOG_H) */
#ifdef HAVE_ANDROID_LOG_H
/**
* Add a log handler to send messages to the Android platform log facility.
*/
int
add_android_log(const log_severity_list_t *severity,
const char *android_tag)
{
logfile_t *lf = NULL;
lf = tor_malloc_zero(sizeof(logfile_t));
lf->fd = -1;
lf->severities = tor_memdup(severity, sizeof(log_severity_list_t));
lf->filename = tor_strdup("<android>");
lf->is_android = 1;
if (android_tag == NULL)
lf->android_tag = tor_strdup("Tor");
else {
char buf[256];
tor_snprintf(buf, sizeof(buf), "Tor-%s", android_tag);
lf->android_tag = tor_strdup(buf);
}
LOCK_LOGS();
lf->next = logfiles;
logfiles = lf;
log_global_min_severity_ = get_min_log_level();
UNLOCK_LOGS();
return 0;
}
#endif // HAVE_ANDROID_LOG_H.
/** If <b>level</b> is a valid log severity, return the corresponding /** If <b>level</b> is a valid log severity, return the corresponding
* numeric value. Otherwise, return -1. */ * numeric value. Otherwise, return -1. */
int int
@ -1318,7 +1389,8 @@ parse_log_severity_config(const char **cfg_ptr,
if (!strcasecmpstart(cfg, "file") || if (!strcasecmpstart(cfg, "file") ||
!strcasecmpstart(cfg, "stderr") || !strcasecmpstart(cfg, "stderr") ||
!strcasecmpstart(cfg, "stdout") || !strcasecmpstart(cfg, "stdout") ||
!strcasecmpstart(cfg, "syslog")) { !strcasecmpstart(cfg, "syslog") ||
!strcasecmpstart(cfg, "android")) {
goto done; goto done;
} }
if (got_an_unqualified_range > 1) if (got_an_unqualified_range > 1)

View File

@ -146,7 +146,11 @@ int add_file_log(const log_severity_list_t *severity, const char *filename,
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
int add_syslog_log(const log_severity_list_t *severity, int add_syslog_log(const log_severity_list_t *severity,
const char* syslog_identity_tag); const char* syslog_identity_tag);
#endif #endif // HAVE_SYSLOG_H.
#ifdef HAVE_ANDROID_LOG_H
int add_android_log(const log_severity_list_t *severity,
const char *android_identity_tag);
#endif // HAVE_ANDROID_LOG_H.
int add_callback_log(const log_severity_list_t *severity, log_callback cb); int add_callback_log(const log_severity_list_t *severity, log_callback cb);
void logs_set_domain_logging(int enabled); void logs_set_domain_logging(int enabled);
int get_min_log_level(void); int get_min_log_level(void);

View File

@ -403,6 +403,7 @@ static config_var_t option_vars_[] = {
V(LogTimeGranularity, MSEC_INTERVAL, "1 second"), V(LogTimeGranularity, MSEC_INTERVAL, "1 second"),
V(TruncateLogFile, BOOL, "0"), V(TruncateLogFile, BOOL, "0"),
V(SyslogIdentityTag, STRING, NULL), V(SyslogIdentityTag, STRING, NULL),
V(AndroidIdentityTag, STRING, NULL),
V(LongLivedPorts, CSV, V(LongLivedPorts, CSV,
"21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"), "21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL), VAR("MapAddress", LINELIST, AddressMap, NULL),
@ -4692,6 +4693,12 @@ options_transition_allowed(const or_options_t *old,
return -1; return -1;
} }
if (!opt_streq(old->AndroidIdentityTag, new_val->AndroidIdentityTag)) {
*msg = tor_strdup("While Tor is running, changing "
"AndroidIdentityTag is not allowed.");
return -1;
}
if ((old->HardwareAccel != new_val->HardwareAccel) if ((old->HardwareAccel != new_val->HardwareAccel)
|| !opt_streq(old->AccelName, new_val->AccelName) || !opt_streq(old->AccelName, new_val->AccelName)
|| !opt_streq(old->AccelDir, new_val->AccelDir)) { || !opt_streq(old->AccelDir, new_val->AccelDir)) {
@ -5743,6 +5750,18 @@ options_init_logs(const or_options_t *old_options, or_options_t *options,
#endif /* defined(HAVE_SYSLOG_H) */ #endif /* defined(HAVE_SYSLOG_H) */
goto cleanup; goto cleanup;
} }
if (!strcasecmp(smartlist_get(elts, 0), "android")) {
#ifdef HAVE_ANDROID_LOG_H
if (!validate_only) {
add_android_log(severity, options->AndroidIdentityTag);
}
#else
log_warn(LD_CONFIG, "Android logging is not supported"
" on this system. Sorry.");
#endif // HAVE_ANDROID_LOG_H.
goto cleanup;
}
} }
if (smartlist_len(elts) == 2 && if (smartlist_len(elts) == 2 &&

View File

@ -3639,6 +3639,7 @@ typedef struct {
int TruncateLogFile; /**< Boolean: Should we truncate the log file int TruncateLogFile; /**< Boolean: Should we truncate the log file
before we start writing? */ before we start writing? */
char *SyslogIdentityTag; /**< Identity tag to add for syslog logging. */ char *SyslogIdentityTag; /**< Identity tag to add for syslog logging. */
char *AndroidIdentityTag; /**< Identity tag to add for Android logging. */
char *DebugLogFile; /**< Where to send verbose log messages. */ char *DebugLogFile; /**< Where to send verbose log messages. */
char *DataDirectory_option; /**< Where to store long-term data, as char *DataDirectory_option; /**< Where to store long-term data, as