router: Stop advertising incorrect auto IPv6 ORPorts

When IPv6 ORPorts are set to "auto", tor relays and bridges would
advertise an incorrect port in their descriptor.

This may be a low-severity memory safety issue, because the published
port number may be derived from uninitialised or out-of-bounds memory
reads.

Fixes bug 32588; bugfix on 0.2.3.9-alpha.
This commit is contained in:
teor 2019-12-20 14:30:51 +10:00
parent ee3d23c05a
commit 861337fd6d
No known key found for this signature in database
GPG Key ID: 10FEAA0E7075672A
3 changed files with 54 additions and 28 deletions

4
changes/bug32588 Normal file
View File

@ -0,0 +1,4 @@
o Minor bugfixes (relays):
- Stop advertising incorrect IPv6 ORPorts in relay and bridge descriptors,
when the IPv6 port was configured as "auto".
Fixes bug 32588; bugfix on 0.2.3.9-alpha

View File

@ -1433,6 +1433,49 @@ router_get_advertised_or_port_by_af(const or_options_t *options,
return port;
}
/** As router_get_advertised_or_port(), but returns the IPv6 address and
* port in ipv6_ap_out, which must not be NULL. Returns a null address and
* zero port, if no ORPort is found. */
void
router_get_advertised_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out)
{
/* Bug in calling function, we can't return a sensible result, and it
* shouldn't use the NULL pointer once we return. */
tor_assert(ipv6_ap_out);
/* If there is no valid IPv6 ORPort, return a null address and port. */
tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6);
ipv6_ap_out->port = 0;
const tor_addr_t *addr = get_first_advertised_addr_by_type_af(
CONN_TYPE_OR_LISTENER,
AF_INET6);
const uint16_t port = router_get_advertised_or_port_by_af(
options,
AF_INET6);
if (!addr || port == 0) {
log_info(LD_CONFIG, "There is no advertised IPv6 ORPort.");
return;
}
/* Like IPv4, if the relay is configured using the default
* authorities, disallow internal IPs. Otherwise, allow them. */
const int default_auth = using_default_dir_authorities(options);
if (! tor_addr_is_internal(addr, 0) || ! default_auth) {
tor_addr_copy(&ipv6_ap_out->addr, addr);
ipv6_ap_out->port = port;
} else {
char addrbuf[TOR_ADDR_BUF_LEN];
log_warn(LD_CONFIG,
"Unable to use configured IPv6 address \"%s\" in a "
"descriptor. Skipping it. "
"Try specifying a globally reachable address explicitly.",
tor_addr_to_str(addrbuf, addr, sizeof(addrbuf), 1));
}
}
/** Return the port that we should advertise as our DirPort;
* this is one of three possibilities:
* The one that is passed as <b>dirport</b> if the DirPort option is 0, or
@ -1848,34 +1891,11 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
sizeof(curve25519_public_key_t));
/* For now, at most one IPv6 or-address is being advertised. */
{
const port_cfg_t *ipv6_orport = NULL;
SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
if (p->type == CONN_TYPE_OR_LISTENER &&
! p->server_cfg.no_advertise &&
! p->server_cfg.bind_ipv4_only &&
tor_addr_family(&p->addr) == AF_INET6) {
/* Like IPv4, if the relay is configured using the default
* authorities, disallow internal IPs. Otherwise, allow them. */
const int default_auth = using_default_dir_authorities(options);
if (! tor_addr_is_internal(&p->addr, 0) || ! default_auth) {
ipv6_orport = p;
break;
} else {
char addrbuf[TOR_ADDR_BUF_LEN];
log_warn(LD_CONFIG,
"Unable to use configured IPv6 address \"%s\" in a "
"descriptor. Skipping it. "
"Try specifying a globally reachable address explicitly.",
tor_addr_to_str(addrbuf, &p->addr, sizeof(addrbuf), 1));
}
}
} SMARTLIST_FOREACH_END(p);
if (ipv6_orport) {
tor_addr_copy(&ri->ipv6_addr, &ipv6_orport->addr);
ri->ipv6_orport = ipv6_orport->port;
}
}
tor_addr_port_t ipv6_orport;
router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
/* If there is no valud IPv6 ORPort, the address and port are null. */
tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr);
ri->ipv6_orport = ipv6_orport.port;
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,

View File

@ -59,6 +59,8 @@ int init_keys_client(void);
uint16_t router_get_active_listener_port_by_type_af(int listener_type,
sa_family_t family);
uint16_t router_get_advertised_or_port(const or_options_t *options);
void router_get_advertised_ipv6_or_ap(const or_options_t *options,
tor_addr_port_t *ipv6_ap_out);
uint16_t router_get_advertised_or_port_by_af(const or_options_t *options,
sa_family_t family);
uint16_t router_get_advertised_dir_port(const or_options_t *options,