escape.c 3.5 KB

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