Commit 5777ee0e authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

Add some functions to escape values from the network before sending them to...

Add some functions to escape values from the network before sending them to the log.  Use them everywhere except for routerinfo->plaftorm, routerinfo->contact_info, and rend*.c.  (need sleep now)


svn:r6087
parent 6a4e304d
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -45,9 +45,13 @@ N - building on freebsd 6.0: (with multiple openssl installations)
    - authorities should *never* 503 a cache, but *should* 503 clients
      when they feel like it.
    - update dir-spec with what we decided for each of these
  - when logging unknown http headers, this could include bad escape codes?
    - more generally, attacker-controller log entries with newlines in them
  o when logging unknown http headers, this could include bad escape codes?
    more generally, attacker-controller log entries with newlines in them
    are dangerous for our users.
    o So... add functions to escape potentially malicious values before
      logging them, and test values more closely as they arrive...
    - But what to do about contact_info and platform?
    - (Didn't finish converting rend*.c)
  - Make "setconf" and "hup" behavior cleaner for LINELIST config
    options (e.g. Log). Bug 238.
R - Jan 26 10:25:04.832 [warn] add_an_entry_guard(): Tried finding a
@@ -56,11 +60,11 @@ R - streamline how we define a guard node as 'up'. document it
    somewhere.
R - reduce log severity for guard nodes.
R - make guard node timeout higher.
N . Clean and future-proof exit policy formats a bit.
  o Clean and future-proof exit policy formats a bit.
    o Likewise accept, but don't generate /bits formats (unless they're
      accepted in 0.0.9 and later).
    o Warn when we see a netmask that isn't a prefix.
    - Make clients understand "private:*" in exit policies, even though
    o Make clients understand "private:*" in exit policies, even though
      we don't generate it yet.

for 0.1.1.x-final:
+2 −1
Original line number Diff line number Diff line
@@ -672,7 +672,8 @@ tor_tls_get_peer_cert_nickname(tor_tls_t *tls, char *buf, size_t buflen)
    goto error;
  if (((int)strspn(buf, LEGAL_NICKNAME_CHARACTERS)) < lenout) {
    log_warn(LD_PROTOCOL,
             "Peer certificate nickname \"%s\" has illegal characters.", buf);
             "Peer certificate nickname %s has illegal characters.",
             escaped(buf));
    if (strchr(buf, '.'))
      log_warn(LD_PROTOCOL, "  (Maybe it is not really running Tor at its "
               "advertised OR port.)");
+131 −17
Original line number Diff line number Diff line
@@ -329,6 +329,16 @@ tor_strupper(char *s)
  }
}

int
tor_strisprint(const char *s)
{
  while (*s) {
    if (!TOR_ISPRINT(*s))
      return 0;
  }
  return 1;
}

/* Compares the first strlen(s2) characters of s1 with s2.  Returns as for
 * strcmp.
 */
@@ -564,6 +574,100 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen)
  return 0;
}

/** Allocate and return a new string representing the contents of <b>s</b>,
 * surrounded by quotes and using standard C escapes.
 *
 * Generally, we use this for logging values that come in over the network
 * to keep them from tricking users.
 *
 * We trust values from the resolver, OS, configuration file, and command line
 * to not be maliciously ill-formed.  We validate incoming routerdescs and
 * SOCKS requests and addresses from BEGIN cells as they're parsed;
 * afterwards, we trust them as non-malicious.
 */
char *
esc_for_log(const char *s)
{
  const char *cp;
  char *result, *outp;
  size_t len = 3;
  for (cp = s; *cp; ++cp) {
    switch (*cp) {
      case '\\':
      case '\"':
      case '\'':
        len += 2;
        break;
      default:
        if (TOR_ISPRINT(*cp))
          ++len;
        else
          len += 4;
        break;
    }
  }

  result = outp = tor_malloc(len);
  *outp++ = '\"';
  for (cp = s; *cp; ++cp) {
    switch (*cp) {
      case '\\':
      case '\"':
      case '\'':
        *outp++ = '\\';
        *outp++ = *cp;
        break;
      case '\n':
        *outp++ = '\\';
        *outp++ = 'n';
        break;
      case '\t':
        *outp++ = '\\';
        *outp++ = 't';
        break;
      case '\r':
        *outp++ = '\\';
        *outp++ = 'r';
        break;
      default:
        if (TOR_ISPRINT(*cp)) {
          *outp++ = *cp;
        } else {
          tor_snprintf(outp, 5, "\\%03o", (uint8_t) *cp);
          outp += 4;
        }
        break;
    }
  }

  *outp++ = '\"';
  *outp++ = 0;

  return result;
}

/** Allocate and return a new string representing the contents of <b>s</b>,
 * surrounded by quotes and using standard C escapes.
 *
 * THIS FUNCTION IS NOT REENTRANT.  Don't call it from outside the main
 * thread.  Also, each call invalidates the last-returned value, so don't
 * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b));
 */
const char *
escaped(const char *s)
{
  static char *_escaped_val = NULL;
  if (_escaped_val)
    tor_free(_escaped_val);

  if (s)
    _escaped_val = esc_for_log(s);
  else
    _escaped_val = NULL;

  return _escaped_val;
}

/* =====
 * Time
 * ===== */
@@ -700,7 +804,9 @@ parse_rfc1123_time(const char *buf, time_t *t)
  if (sscanf(buf, "%3s, %d %3s %d %d:%d:%d GMT", weekday,
             &tm.tm_mday, month, &tm.tm_year, &tm.tm_hour,
             &tm.tm_min, &tm.tm_sec) < 7) {
    log_warn(LD_GENERAL, "Got invalid RFC1123 time \"%s\"", buf);
    char *esc = esc_for_log(buf);
    log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc);
    tor_free(esc);
    return -1;
  }

@@ -712,14 +818,18 @@ parse_rfc1123_time(const char *buf, time_t *t)
    }
  }
  if (m<0) {
    log_warn(LD_GENERAL, "Got invalid RFC1123 time \"%s\"", buf);
    char *esc = esc_for_log(buf);
    log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc);
    tor_free(esc);
    return -1;
  }
  tm.tm_mon = m;

  if (tm.tm_year < 1970) {
    char *esc = esc_for_log(buf);
    log_warn(LD_GENERAL,
             "Got invalid RFC1123 time \"%s\". (Before 1970)", buf);
             "Got invalid RFC1123 time %s. (Before 1970)", esc);
    tor_free(esc);
    return -1;
  }
  tm.tm_year -= 1900;
@@ -768,7 +878,9 @@ parse_iso_time(const char *cp, time_t *t)
  st_tm.tm_sec = second;
#endif
  if (st_tm.tm_year < 70) {
    log_warn(LD_GENERAL, "Got invalid ISO time \"%s\". (Before 1970)", cp);
    char *esc = esc_for_log(cp);
    log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc);
    tor_free(esc);
    return -1;
  }
  *t = tor_timegm(&st_tm);
@@ -1222,7 +1334,7 @@ expand_filename(const char *filename)
      home = getenv("HOME");
      if (!home) {
        log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while "
                 "expanding %s", filename);
                 "expanding \"%s\"", filename);
        return NULL;
      }
      home = tor_strdup(home);
@@ -1385,13 +1497,15 @@ parse_addr_port(const char *addrport, char **address, uint32_t *addr,
    _address = tor_strndup(addrport, colon-addrport);
    _port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
    if (!_port) {
      log_warn(LD_GENERAL, "Port '%s' out of range", colon+1);
      log_warn(LD_GENERAL, "Port %s out of range", escaped(colon+1));
      ok = 0;
    }
    if (!port_out) {
      char *esc_addrport = esc_for_log(addrport);
      log_warn(LD_GENERAL,
               "Port '%s' given on '%s' when not required",
               colon+1, addrport);
               "Port %s given on %s when not required",
               escaped(colon+1), esc_addrport);
      tor_free(esc_addrport);
      ok = 0;
    }
  } else {
@@ -1402,7 +1516,7 @@ parse_addr_port(const char *addrport, char **address, uint32_t *addr,
  if (addr) {
    /* There's an addr pointer, so we need to resolve the hostname. */
    if (tor_lookup_hostname(_address,addr)) {
      log_warn(LD_NET, "Couldn't look up '%s'", _address);
      log_warn(LD_NET, "Couldn't look up %s", escaped(_address));
      ok = 0;
      *addr = 0;
    }
@@ -1464,13 +1578,13 @@ parse_port_range(const char *port, uint16_t *port_min_out,
                                                &endptr);
      if (*endptr || !*port_max_out) {
        log_warn(LD_GENERAL,
                 "Malformed port \"%s\" on address range rejecting.",
                 port);
                 "Malformed port %s on address range rejecting.",
                 escaped(port));
      }
    } else if (*endptr || !*port_min_out) {
      log_warn(LD_GENERAL,
               "Malformed port \"%s\" on address range; rejecting.",
               port);
               "Malformed port %s on address range; rejecting.",
               escaped(port));
      return -1;
    } else {
      *port_max_out = *port_min_out;
@@ -1523,8 +1637,8 @@ parse_addr_and_port_range(const char *s, uint32_t *addr_out,
  } else if (tor_inet_aton(address, &in) != 0) {
    *addr_out = ntohl(in.s_addr);
  } else {
    log_warn(LD_GENERAL, "Malformed IP \"%s\" in address pattern; rejecting.",
             address);
    log_warn(LD_GENERAL, "Malformed IP %s in address pattern; rejecting.",
             escaped(address));
    goto err;
  }

@@ -1548,8 +1662,8 @@ parse_addr_and_port_range(const char *s, uint32_t *addr_out,
      *mask_out = ntohl(in.s_addr);
    } else {
      log_warn(LD_GENERAL,
               "Malformed mask \"%s\" on address range; rejecting.",
               mask);
               "Malformed mask %s on address range; rejecting.",
               escaped(mask));
      goto err;
    }
  }
+3 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
#define HEX_CHARACTERS "0123456789ABCDEFabcdef"
void tor_strlower(char *s);
void tor_strupper(char *s);
int tor_strisprint(const char *s);
int strcmpstart(const char *s1, const char *s2);
int strcasecmpstart(const char *s1, const char *s2);
int strcmpend(const char *s1, const char *s2);
@@ -112,6 +113,8 @@ const char *eat_whitespace(const char *s);
const char *eat_whitespace_no_nl(const char *s);
const char *find_whitespace(const char *s);
int tor_digest_is_zero(const char *digest);
char *esc_for_log(const char *string);
const char *escaped(const char *string);

void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
+17 −1
Original line number Diff line number Diff line
@@ -1004,6 +1004,14 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, int log_sockstype)
          req->address[len] = 0;
          req->port = ntohs(get_uint16(buf->cur+5+len));
          buf_remove_from_front(buf, 5+len+2);
          if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
            log_warn(LD_PROTOCOL,
                     "Your application (using socks5 on port %d) gave Tor "
                     "a malformed hostname: %s. Rejecting the connection.",
                     req->port, escaped(req->address));
            return -1;
          }

          if (log_sockstype)
            log_notice(LD_APP,
                  "Your application (using socks5 on port %d) gave "
@@ -1088,6 +1096,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, int log_sockstype)
          return -1;
        }
        tor_assert(next < buf->cur+buf->datalen);

        if (log_sockstype)
          log_notice(LD_APP,
                     "Your application (using socks4a on port %d) gave "
@@ -1097,6 +1106,13 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, int log_sockstype)
      log_debug(LD_APP,"socks4: Everything is here. Success.");
      strlcpy(req->address, startaddr ? startaddr : tmpbuf,
              sizeof(req->address));
      if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
        log_warn(LD_PROTOCOL,
                 "Your application (using socks4 on port %d) gave Tor "
                 "a malformed hostname: %s. Rejecting the connection.",
                 req->port, escaped(req->address));
        return -1;
      }
      /* next points to the final \0 on inbuf */
      buf_remove_from_front(buf, next-buf->cur+1);
      return 1;
Loading