tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

escape.c (3569B)


      1 /* Copyright (c) 2003, Roger Dingledine
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file escape.c
      8 * \brief Escape untrusted strings before sending them to the log.
      9 **/
     10 
     11 #include "lib/log/escape.h"
     12 #include "lib/log/util_bug.h"
     13 #include "lib/string/compat_ctype.h"
     14 #include "lib/string/printf.h"
     15 #include "lib/malloc/malloc.h"
     16 
     17 /** Allocate and return a new string representing the contents of <b>s</b>,
     18 * surrounded by quotes and using standard C escapes.
     19 *
     20 * Generally, we use this for logging values that come in over the network to
     21 * keep them from tricking users, and for sending certain values to the
     22 * controller.
     23 *
     24 * We trust values from the resolver, OS, configuration file, and command line
     25 * to not be maliciously ill-formed.  We validate incoming routerdescs and
     26 * SOCKS requests and addresses from BEGIN cells as they're parsed;
     27 * afterwards, we trust them as non-malicious.
     28 */
     29 char *
     30 esc_for_log(const char *s)
     31 {
     32  const char *cp;
     33  char *result, *outp;
     34  size_t len = 3;
     35  if (!s) {
     36    return tor_strdup("(null)");
     37  }
     38 
     39  for (cp = s; *cp; ++cp) {
     40    switch (*cp) {
     41      case '\\':
     42      case '\"':
     43      case '\'':
     44      case '\r':
     45      case '\n':
     46      case '\t':
     47        len += 2;
     48        break;
     49      default:
     50        if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127)
     51          ++len;
     52        else
     53          len += 4;
     54        break;
     55    }
     56  }
     57 
     58  tor_assert(len <= SSIZE_MAX);
     59 
     60  result = outp = tor_malloc(len);
     61  *outp++ = '\"';
     62  for (cp = s; *cp; ++cp) {
     63    /* This assertion should always succeed, since we will write at least
     64     * one char here, and two chars for closing quote and nul later */
     65    tor_assert((outp-result) < (ssize_t)len-2);
     66    switch (*cp) {
     67      case '\\':
     68      case '\"':
     69      case '\'':
     70        *outp++ = '\\';
     71        *outp++ = *cp;
     72        break;
     73      case '\n':
     74        *outp++ = '\\';
     75        *outp++ = 'n';
     76        break;
     77      case '\t':
     78        *outp++ = '\\';
     79        *outp++ = 't';
     80        break;
     81      case '\r':
     82        *outp++ = '\\';
     83        *outp++ = 'r';
     84        break;
     85      default:
     86        if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
     87          *outp++ = *cp;
     88        } else {
     89          tor_assert((outp-result) < (ssize_t)len-4);
     90          tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
     91          outp += 4;
     92        }
     93        break;
     94    }
     95  }
     96 
     97  tor_assert((outp-result) <= (ssize_t)len-2);
     98  *outp++ = '\"';
     99  *outp++ = 0;
    100 
    101  return result;
    102 }
    103 
    104 /** Similar to esc_for_log. Allocate and return a new string representing
    105 * the first n characters in <b>chars</b>, surround by quotes and using
    106 * standard C escapes. If a NUL character is encountered in <b>chars</b>,
    107 * the resulting string will be terminated there.
    108 */
    109 char *
    110 esc_for_log_len(const char *chars, size_t n)
    111 {
    112  char *string = tor_strndup(chars, n);
    113  char *string_escaped = esc_for_log(string);
    114  tor_free(string);
    115  return string_escaped;
    116 }
    117 
    118 /** Allocate and return a new string representing the contents of <b>s</b>,
    119 * surrounded by quotes and using standard C escapes.
    120 *
    121 * THIS FUNCTION IS NOT REENTRANT.  Don't call it from outside the main
    122 * thread.  Also, each call invalidates the last-returned value, so don't
    123 * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
    124 */
    125 const char *
    126 escaped(const char *s)
    127 {
    128  static char *escaped_val_ = NULL;
    129  tor_free(escaped_val_);
    130 
    131  if (s)
    132    escaped_val_ = esc_for_log(s);
    133  else
    134    escaped_val_ = NULL;
    135 
    136  return escaped_val_;
    137 }