LCOV - code coverage report
Current view: top level - lib/err - torerr.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 78 93 83.9 %
Date: 2021-11-24 03:28:48 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /* Copyright (c) 2001, Matej Pfajfar.
       2             :  * Copyright (c) 2001-2004, Roger Dingledine.
       3             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       4             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       5             : /* See LICENSE for licensing information */
       6             : 
       7             : /**
       8             :  * \file torerr.c
       9             :  *
      10             :  * \brief Handling code for unrecoverable emergencies, at a lower level
      11             :  *   than the logging code.
      12             :  *
      13             :  * There are plenty of places that things can go wrong in Tor's backend
      14             :  * libraries: the allocator can fail, the locking subsystem can fail, and so
      15             :  * on.  But since these subsystems are used themselves by the logging module,
      16             :  * they can't use the logging code directly to report their errors.
      17             :  *
      18             :  * As a workaround, the logging code provides this module with a set of raw
      19             :  * fds to be used for reporting errors in the lowest-level Tor code.
      20             :  */
      21             : 
      22             : #include "orconfig.h"
      23             : #include <stdarg.h>
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : #include <stdio.h>
      27             : #ifdef HAVE_SYS_TIME_H
      28             : #include <sys/time.h>
      29             : #endif
      30             : #ifdef HAVE_TIME_H
      31             : #include <time.h>
      32             : #endif
      33             : #ifdef HAVE_UNISTD_H
      34             : #include <unistd.h>
      35             : #endif
      36             : #ifdef HAVE_SYS_TYPES_H
      37             : #include <sys/types.h>
      38             : #endif
      39             : 
      40             : #include "lib/err/torerr.h"
      41             : #include "lib/err/backtrace.h"
      42             : 
      43             : /** Array of fds to log crash-style warnings to. */
      44             : static int sigsafe_log_fds[TOR_SIGSAFE_LOG_MAX_FDS] = { STDERR_FILENO };
      45             : /** The number of elements used in sigsafe_log_fds */
      46             : static int n_sigsafe_log_fds = 1;
      47             : /** Log granularity in milliseconds. */
      48             : static int log_granularity = 1000;
      49             : 
      50             : /** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1
      51             :  * on failure. */
      52             : static int
      53          10 : tor_log_err_sigsafe_write(const char *s)
      54             : {
      55          10 :   int i;
      56          10 :   ssize_t r;
      57          10 :   size_t len = strlen(s);
      58          10 :   int err = 0;
      59          30 :   for (i=0; i < n_sigsafe_log_fds; ++i) {
      60          20 :     r = write(sigsafe_log_fds[i], s, len);
      61          20 :     err += (r != (ssize_t)len);
      62             :   }
      63          10 :   return err ? -1 : 0;
      64             : }
      65             : 
      66             : /** Given a list of string arguments ending with a NULL, writes them
      67             :  * to our logs and to stderr (if possible).  This function is safe to call
      68             :  * from within a signal handler. */
      69             : void
      70           2 : tor_log_err_sigsafe(const char *m, ...)
      71             : {
      72           2 :   va_list ap;
      73           2 :   const char *x;
      74           2 :   char timebuf[33];
      75           2 :   time_t now = time(NULL);
      76             : 
      77           2 :   if (!m)
      78           0 :     return;
      79           2 :   if (log_granularity >= 2000) {
      80           1 :     int g = log_granularity / 1000;
      81           1 :     now -= now % g;
      82             :   }
      83           2 :   timebuf[0] = now < 0 ? '-' : ' ';
      84           2 :   if (now < 0) now = -now;
      85           2 :   timebuf[1] = '\0';
      86           2 :   format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1);
      87           2 :   tor_log_err_sigsafe_write("\n=========================================="
      88             :                              "================== T=");
      89           2 :   tor_log_err_sigsafe_write(timebuf);
      90           2 :   tor_log_err_sigsafe_write("\n");
      91           2 :   tor_log_err_sigsafe_write(m);
      92           2 :   va_start(ap, m);
      93           4 :   while ((x = va_arg(ap, const char*))) {
      94           2 :     tor_log_err_sigsafe_write(x);
      95             :   }
      96           2 :   va_end(ap);
      97             : }
      98             : 
      99             : /** Set *<b>out</b> to a pointer to an array of the fds to log errors to from
     100             :  * inside a signal handler or other emergency condition. Return the number of
     101             :  * elements in the array. */
     102             : int
     103         240 : tor_log_get_sigsafe_err_fds(const int **out)
     104             : {
     105         240 :   *out = sigsafe_log_fds;
     106         240 :   return n_sigsafe_log_fds;
     107             : }
     108             : 
     109             : /**
     110             :  * Update the list of fds that get errors from inside a signal handler or
     111             :  * other emergency condition. Ignore any beyond the first
     112             :  * TOR_SIGSAFE_LOG_MAX_FDS.
     113             :  *
     114             :  * These fds must remain open even after the log module has shut down. (And
     115             :  * they should remain open even while logs are being reconfigured.) Therefore,
     116             :  * any fds closed by the log module should be dup()ed, and the duplicate fd
     117             :  * should be given to the err module in fds. In particular, the log module
     118             :  * closes the file log fds, but does not close the stdio log fds.
     119             :  *
     120             :  * If fds is NULL or n is 0, clears the list of error fds.
     121             :  */
     122             : void
     123        5566 : tor_log_set_sigsafe_err_fds(const int *fds, int n)
     124             : {
     125        5566 :   if (n > TOR_SIGSAFE_LOG_MAX_FDS) {
     126             :     n = TOR_SIGSAFE_LOG_MAX_FDS;
     127             :   }
     128             : 
     129             :   /* Clear the entire array. This code mitigates against some race conditions,
     130             :    * but there are still some races here:
     131             :    * - err logs are disabled while the array is cleared, and
     132             :    * - a thread can read the old value of n_sigsafe_log_fds, then read a
     133             :    *   partially written array.
     134             :    * We could fix these races using atomics, but atomics use the err module. */
     135        5566 :   n_sigsafe_log_fds = 0;
     136        5566 :   memset(sigsafe_log_fds, 0, sizeof(sigsafe_log_fds));
     137        5566 :   if (fds && n > 0) {
     138        5566 :     memcpy(sigsafe_log_fds, fds, n * sizeof(int));
     139        5566 :     n_sigsafe_log_fds = n;
     140             :   }
     141        5566 : }
     142             : 
     143             : /**
     144             :  * Reset the list of emergency error fds to its default.
     145             :  */
     146             : void
     147        5553 : tor_log_reset_sigsafe_err_fds(void)
     148             : {
     149        5553 :   int fds[] = { STDERR_FILENO };
     150        5553 :   tor_log_set_sigsafe_err_fds(fds, 1);
     151        5553 : }
     152             : 
     153             : /**
     154             :  * Flush the list of fds that get errors from inside a signal handler or
     155             :  * other emergency condition. These fds are shared with the logging code:
     156             :  * flushing them also flushes the log buffers.
     157             :  *
     158             :  * This function is safe to call during signal handlers.
     159             :  */
     160             : void
     161         235 : tor_log_flush_sigsafe_err_fds(void)
     162             : {
     163             :   /* If we don't have fsync() in unistd.h, we can't flush the logs. */
     164             : #ifdef HAVE_FSYNC
     165         235 :   int n_fds, i;
     166         235 :   const int *fds = NULL;
     167             : 
     168         235 :   n_fds = tor_log_get_sigsafe_err_fds(&fds);
     169         705 :   for (i = 0; i < n_fds; ++i) {
     170             :     /* This function is called on error and on shutdown, so we don't log, or
     171             :      * take any other action, if fsync() fails. */
     172         235 :     (void)fsync(fds[i]);
     173             :   }
     174             : #endif /* defined(HAVE_FSYNC) */
     175         235 : }
     176             : 
     177             : /**
     178             :  * Set the granularity (in ms) to use when reporting fatal errors outside
     179             :  * the logging system.
     180             :  */
     181             : void
     182          14 : tor_log_sigsafe_err_set_granularity(int ms)
     183             : {
     184          14 :   log_granularity = ms;
     185          14 : }
     186             : 
     187             : /**
     188             :  * Log an emergency assertion failure message.
     189             :  *
     190             :  * This kind of message is safe to send from within a log handler,
     191             :  * a signal handler, or other emergency situation.
     192             :  */
     193             : void
     194           0 : tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr,
     195             :                               const char *msg)
     196             : {
     197           0 :   char linebuf[16];
     198           0 :   format_dec_number_sigsafe(line, linebuf, sizeof(linebuf));
     199           0 :   tor_log_err_sigsafe("INTERNAL ERROR: Raw assertion failed in ",
     200             :                       get_tor_backtrace_version(), " at ",
     201             :                       file, ":", linebuf, ": ", expr, "\n", NULL);
     202           0 :   if (msg) {
     203           0 :     tor_log_err_sigsafe_write(msg);
     204           0 :     tor_log_err_sigsafe_write("\n");
     205             :   }
     206             : 
     207           0 :   dump_stack_symbols_to_error_fds();
     208             : 
     209             :   /* Some platforms (macOS, maybe others?) can swallow the last write before an
     210             :    * abort. This issue is probably caused by a race condition between write
     211             :    * buffer cache flushing, and process termination. So we write an extra
     212             :    * newline, to make sure that the message always gets through. */
     213           0 :   tor_log_err_sigsafe_write("\n");
     214           0 : }
     215             : 
     216             : /**
     217             :  * Call the abort() function to kill the current process with a fatal
     218             :  * error. But first, flush the raw error file descriptors, so error messages
     219             :  * are written before process termination.
     220             :  **/
     221             : void
     222           0 : tor_raw_abort_(void)
     223             : {
     224           0 :   tor_log_flush_sigsafe_err_fds();
     225           0 :   abort();
     226             : }
     227             : 
     228             : /* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument
     229             :  * in range 2..16 inclusive. */
     230             : static int
     231          31 : format_number_sigsafe(unsigned long x, char *buf, int buf_len,
     232             :                       unsigned int radix)
     233             : {
     234          31 :   unsigned long tmp;
     235          31 :   int len;
     236          31 :   char *cp;
     237             : 
     238             :   /* NOT tor_assert. This needs to be safe to run from within a signal
     239             :    * handler, and from within the 'tor_assert() has failed' code.  Not even
     240             :    * raw_assert(), since raw_assert() calls this function on failure. */
     241          31 :   if (radix < 2 || radix > 16)
     242             :     return 0;
     243             : 
     244             :   /* Count how many digits we need. */
     245             :   tmp = x;
     246             :   len = 1;
     247         163 :   while (tmp >= radix) {
     248         132 :     tmp /= radix;
     249         132 :     ++len;
     250             :   }
     251             : 
     252             :   /* Not long enough */
     253          31 :   if (!buf || len >= buf_len)
     254             :     return 0;
     255             : 
     256          27 :   cp = buf + len;
     257          27 :   *cp = '\0';
     258         153 :   do {
     259         153 :     unsigned digit = (unsigned) (x % radix);
     260         153 :     if (cp <= buf) {
     261             :       /* Not tor_assert(); see above. */
     262           0 :       tor_raw_abort_();
     263             :     }
     264         153 :     --cp;
     265         153 :     *cp = "0123456789ABCDEF"[digit];
     266         153 :     x /= radix;
     267         153 :   } while (x);
     268             : 
     269             :   /* NOT tor_assert; see above. */
     270          27 :   if (cp != buf) {
     271             :     tor_raw_abort_(); // LCOV_EXCL_LINE
     272             :   }
     273             : 
     274             :   return len;
     275             : }
     276             : 
     277             : /**
     278             :  * Helper function to output hex numbers from within a signal handler.
     279             :  *
     280             :  * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer
     281             :  * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits
     282             :  * written, not counting the terminal NUL.
     283             :  *
     284             :  * If there is insufficient space, write nothing and return 0.
     285             :  *
     286             :  * This accepts an unsigned int because format_helper_exit_status() needs to
     287             :  * call it with a signed int and an unsigned char, and since the C standard
     288             :  * does not guarantee that an int is wider than a char (an int must be at
     289             :  * least 16 bits but it is permitted for a char to be that wide as well), we
     290             :  * can't assume a signed int is sufficient to accommodate an unsigned char.
     291             :  * Thus, callers will still need to add any required '-' to the final string.
     292             :  *
     293             :  * For most purposes, you'd want to use tor_snprintf("%x") instead of this
     294             :  * function; it's designed to be used in code paths where you can't call
     295             :  * arbitrary C functions.
     296             :  */
     297             : int
     298          11 : format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len)
     299             : {
     300          11 :   return format_number_sigsafe(x, buf, buf_len, 16);
     301             : }
     302             : 
     303             : /** As format_hex_number_sigsafe, but format the number in base 10. */
     304             : int
     305          20 : format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len)
     306             : {
     307          20 :   return format_number_sigsafe(x, buf, buf_len, 10);
     308             : }

Generated by: LCOV version 1.14