Line data Source code
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 3657 : esc_for_log(const char *s) 31 : { 32 3657 : const char *cp; 33 3657 : char *result, *outp; 34 3657 : size_t len = 3; 35 3657 : if (!s) { 36 1 : return tor_strdup("(null)"); 37 : } 38 : 39 107843 : for (cp = s; *cp; ++cp) { 40 104187 : switch (*cp) { 41 1408 : case '\\': 42 : case '\"': 43 : case '\'': 44 : case '\r': 45 : case '\n': 46 : case '\t': 47 1408 : len += 2; 48 1408 : break; 49 102779 : default: 50 102779 : if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) 51 97158 : ++len; 52 : else 53 5621 : len += 4; 54 : break; 55 : } 56 : } 57 : 58 3656 : tor_assert(len <= SSIZE_MAX); 59 : 60 3656 : result = outp = tor_malloc(len); 61 3656 : *outp++ = '\"'; 62 107843 : 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 104187 : tor_assert((outp-result) < (ssize_t)len-2); 66 104187 : switch (*cp) { 67 714 : case '\\': 68 : case '\"': 69 : case '\'': 70 714 : *outp++ = '\\'; 71 714 : *outp++ = *cp; 72 714 : break; 73 266 : case '\n': 74 266 : *outp++ = '\\'; 75 266 : *outp++ = 'n'; 76 266 : break; 77 194 : case '\t': 78 194 : *outp++ = '\\'; 79 194 : *outp++ = 't'; 80 194 : break; 81 234 : case '\r': 82 234 : *outp++ = '\\'; 83 234 : *outp++ = 'r'; 84 234 : break; 85 102779 : default: 86 102779 : if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) { 87 97158 : *outp++ = *cp; 88 : } else { 89 5621 : tor_assert((outp-result) < (ssize_t)len-4); 90 5621 : tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp); 91 5621 : outp += 4; 92 : } 93 : break; 94 : } 95 : } 96 : 97 3656 : tor_assert((outp-result) <= (ssize_t)len-2); 98 3656 : *outp++ = '\"'; 99 3656 : *outp++ = 0; 100 : 101 3656 : 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 40 : esc_for_log_len(const char *chars, size_t n) 111 : { 112 40 : char *string = tor_strndup(chars, n); 113 40 : char *string_escaped = esc_for_log(string); 114 40 : tor_free(string); 115 40 : 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 7842 : escaped(const char *s) 127 : { 128 7842 : static char *escaped_val_ = NULL; 129 7842 : tor_free(escaped_val_); 130 : 131 7842 : if (s) 132 3369 : escaped_val_ = esc_for_log(s); 133 : else 134 : escaped_val_ = NULL; 135 : 136 7842 : return escaped_val_; 137 : }