CVE-2017-0377 (C, published 2017-07-02T15:29Z)
Description: value: Tor 0.3.x before 0.3.0.9 has a guard-selection algorithm that only considers the exit relay (not the exit relay's family), which might allow remote attackers to defeat intended anonymity properties by leveraging the existence of large families.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-200 \u2014 Exposure of Sensitive Information to an Unauthorized Actor
The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
Repository: https://github.com/torproject/tor
Files changed:
changes/bug22753
src/or/entrynodes.c
src/or/entrynodes.h
src/or/nodelist.c
src/or/nodelist.h
Commit message: Consider the exit family when applying guard restrictions.

When the new path selection logic went into place, I accidentally
dropped the code that considered the _family_ of the exit node when
deciding if the guard was usable, and we didn't catch that during
code review.

This patch makes the guard_restriction_t code consider the exit
family as well, and adds some (hopefully redundant) checks for the
case where we lack a node_t for a guard but we have a bridge_info_t
for it.

Fixes bug 22753; bugfix on 0.3.0.1-alpha. Tracked as TROVE-2016-006
and CVE-2017-0377.


Vulnerable code:
  // Only one kind of restriction exists right now
 * Right now, we only use restrictions to block a single guard from being
 * selected; this mechanism is designed to be more extensible in the future,
 * however.
   * The guard's RSA identity digest must not equal this.
static inline int

Fixed code:
  o Major bugfixes (path selection, security):
    - When choosing which guard to use for a circuit, avoid the
      exit's family along with the exit itself. Previously, the new
      guard selection logic avoided the exit, but did not consider
      its family.  Fixes bug 22753; bugfix on 0.3.0.1-alpha. Tracked
      as TROVE-2016-006 and CVE-2017-0377.

/** Return true iff <b>guard</b> is in the same family as <b>node</b>.
 */
static int
guard_in_node_family(const entry_guard_t *guard, const node_t *node)
{
  const node_t *guard_node = node_get_by_id(guard->identity);
  if (guard_node) {
    return nodes_in_same_family(guard_node, node);
  } else {
    /* If we don't have a node_t for the guard node, we might have
     * a bridge_info_t for it. So let's check to see whether the bridge
     * address matches has any family issues.
     *
     * (Strictly speaking, I believe this check is unnecessary, since we only
     * use it to avoid the exit's family when building circuits, and we don't
     * build multihop circuits until we have a routerinfo_t for the
     * bridge... at which point, we'll also have a node_t for the
     * bridge. Nonetheless, it seems wise to include it, in case our
     * assumptions change down the road.  -nickm.)
     */
    if (get_options()->EnforceDistinctSubnets && guard->bridge_addr) {
      tor_addr_t node_addr;
      node_get_addr(node, &node_addr);
      if (addrs_in_same_network_family(&node_addr,
                                       &guard->bridge_addr->addr)) {
        return 1;
      }
    }
    return 0;
  }
}

  // Only one kind of restriction exists right now: excluding an exit
  // ID and all of its family.
  const node_t *node = node_get_by_id((const char*)rst->exclude_id);
  if (node && guard_in_node_family(guard, node))
    return 0;

 * Right now, we only use restrictions to block a single guard and its family
 * from being selected; this mechanism is designed to be more extensible in
 * the future, however.
   * The guard's RSA identity digest must not equal this; and it must not
   * be in the same family as any node with this digest.
int
int addrs_in_same_network_family(const tor_addr_t *a1,
                                 const tor_addr_t *a2);