Merge remote-tracking branch 'origin/maint-0.2.3' into release-0.2.3

This commit is contained in:
Nick Mathewson 2014-10-19 14:35:29 -04:00
commit 43836f6f0a
58 changed files with 31431 additions and 103986 deletions

6
changes/bug10849_023 Normal file
View File

@ -0,0 +1,6 @@
o Major bugfixes:
- When running a hidden service, do not allow TunneledDirConns 0;
this will keep the hidden service from running, and also
make it publish its descriptors directly over HTTP. Fixes bug 10849;
bugfix on 0.2.1.1-alpha.

5
changes/bug11464_023 Normal file
View File

@ -0,0 +1,5 @@
o Major features (security):
- Block authority signing keys that were used on an authorities
vulnerable to the "heartbleed" bug in openssl (CVE-2014-0160).
(We don't have any evidence that these keys _were_ compromised;
we're doing this to be prudent.) Resolves ticket 11464.

3
changes/bug11519 Normal file
View File

@ -0,0 +1,3 @@
o Minor bugfixes:
- Avoid sending an garbage value to the controller when a circuit is
cannibalized. Fixes bug 11519; bugfix on 0.2.3.11-alpha.

3
changes/bug13100 Normal file
View File

@ -0,0 +1,3 @@
o Directory authority changes:
- Change IP address for gabelmoo (v3 directory authority).

5
changes/bug5650 Normal file
View File

@ -0,0 +1,5 @@
o Major bugfixes:
- Avoid a bug where our response to TLS renegotation under certain
network conditions could lead to a busy-loop, with 100% CPU
consumption. Fixes bug 5650; bugfix on 0.2.0.16-alpha.

4
changes/bug6979 Normal file
View File

@ -0,0 +1,4 @@
o Minor bugfixes:
- Fix an assertion failure that would occur when disabling the
ORPort setting on a running Tor process while accounting was
enabled. Fixes bug 6979; bugfix on 0.2.2.18-alpha.

View File

@ -0,0 +1,6 @@
o Minor bugfixes:
- Downgrade the warning severity for the the "md was still referenced 1
node(s)" warning. Tor 0.2.5.4-alpha has better code for trying to
diagnose this bug, and the current warning in earlier versions of
tor achieves nothing useful. Addresses warning from bug 7164.

6
changes/bug8844 Normal file
View File

@ -0,0 +1,6 @@
o Major bugfixes:
- Prevent the get_freelists() function from running off the end of
the list of freelists if it somehow gets an unrecognized
allocation. Fixes bug 8844; bugfix on 0.2.0.16-alpha. Reported by
eugenis.

4
changes/bug9002 Normal file
View File

@ -0,0 +1,4 @@
o Major bugfixes:
- Limit hidden service descriptors to at most ten introduction
points, to slow one kind of guard enumeration. Fixes bug 9002;
bugfix on 0.1.1.11-alpha.

6
changes/bug9017 Normal file
View File

@ -0,0 +1,6 @@
o Major bugfixes:
- Avoid an assertion failure on OpenBSD (and perhaps other BSDs)
when an exit connection with optimistic data succeeds immediately
rather than returning EINPROGRESS. Fixes bug 9017; bugfix on
0.2.3.1-alpha.

3
changes/bug9063 Normal file
View File

@ -0,0 +1,3 @@
o Normal bugfixes:
- Close any circuit that has more cells queued than the spec permits.
Fixes bug #9063; bugfix on 0.2.3.25.

15
changes/bug9063_redux Normal file
View File

@ -0,0 +1,15 @@
o Major bugfixes:
- When we have too much memory queued in circuits (according to a new
MaxMemInCellQueues option), close the circuits consuming the most
memory. This prevents us from running out of memory as a relay if
circuits fill up faster than they can be drained. Fixes
bug 9063; bugfix on the 54th commit of Tor. This bug is a further
fix beyond bug 6252, whose fix was merged into 0.2.3.21-rc.
Also fixes an earlier approach taken in 0.2.4.13-alpha, where we
tried to solve this issue simply by imposing an upper limit on the
number of queued cells for a single circuit. That approach proved to
be problematic, since there are ways to provoke clients to send a
number of cells in excess of any such reasonable limit.
Fixes bug 9072; bugfix on 0.2.4.13-alpha.

3
changes/bug9072 Normal file
View File

@ -0,0 +1,3 @@
o Critical bugfixes:
- Disable middle relay queue overfill detection code due to possible
guard discovery attack, pending further analysis. Fixes bug #9072.

7
changes/bug9093 Normal file
View File

@ -0,0 +1,7 @@
o Minor features:
- Improve the circuit queue out-of-memory handler. Previously, when
we ran low on memory, we'd close whichever circuits had the most
queued cells. Now, we close those that have the *oldest* queued
cells, on the theory that those are most responsible for us
running low on memory. Based on analysis from a forthcoming paper
by Jansen, Tschorsch, Johnson, and Scheuermann. Fixes bug 9093.

11
changes/bug9546 Normal file
View File

@ -0,0 +1,11 @@
o Major bugfixes:
- When a relay is extending a circuit to a bridge, it needs to send a
NETINFO cell, even when the bridge hasn't sent an AUTH_CHALLENGE
cell. Fixes bug 9546; bugfix on 0.2.3.6-alpha.
- Bridges send AUTH_CHALLENGE cells during their handshakes; previously
they did not, which prevented relays from successfully connecting
to a bridge for self-test or bandwidth testing. Fixes bug 9546;
bugfix on 0.2.3.6-alpha.

5
changes/bug9564 Normal file
View File

@ -0,0 +1,5 @@
o Minor bugfixes:
- If the time to download the next old-style networkstatus is in
the future, do not decline to consider whether to download the
next microdescriptor networkstatus. Fixes bug 9564. Bugfix on
0.2.3.14-alpha.

5
changes/bug9671_023 Normal file
View File

@ -0,0 +1,5 @@
o Major bugfixes:
- If the circuit build timeout logic is disabled (via the consensus,
or because we are an authority), then don't build testing circuits.
Fixes bug 9657; bugfix on 0.2.2.14-alpha.

6
changes/bug9928 Normal file
View File

@ -0,0 +1,6 @@
o Minor bugfixes:
- Avoid an off-by-one error when checking buffer boundaries when
formatting the exit status of a pluggable transport helper.
This is probably not an exploitable bug, but better safe than
sorry. Fixes bug 9928; bugfix on 0.2.3.18-rc. Bug found by
Pedro Ribeiro.

4
changes/disable_sslv3 Normal file
View File

@ -0,0 +1,4 @@
o Major security fixes:
- Disable support for SSLv3. All versions of OpenSSL in use with
Tor today support TLS 1.0 or later, so we can safely turn off
support for this old (and insecure) protocol. Fixes bug 13426.

3
changes/geoip-august2013 Normal file
View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the August 7 2013 Maxmind GeoLite Country database.

3
changes/geoip-august2014 Normal file
View File

@ -0,0 +1,3 @@
o Minor features:
- Update geoip to the August 7 2014 Maxmind GeoLite2 Country database.

View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the February 7 2014 Maxmind GeoLite2 Country database.

View File

@ -0,0 +1,3 @@
o Minor features:
- Fix our version of the February 7 2014 Maxmind GeoLite2 Country database.

3
changes/geoip-july2013 Normal file
View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the July 3 2013 Maxmind GeoLite Country database.

3
changes/geoip-july2014 Normal file
View File

@ -0,0 +1,3 @@
o Minor features:
- Update geoip to the July 10 2014 Maxmind GeoLite2 Country database.

3
changes/geoip-june2013 Normal file
View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the June 5 2013 Maxmind GeoLite Country database.

3
changes/geoip-may2013 Normal file
View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the May 9 2013 Maxmind GeoLite Country database.

View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the October 2 2013 Maxmind GeoLite Country database.

View File

@ -0,0 +1,3 @@
o Minor features:
- Update to the September 4 2013 Maxmind GeoLite Country database.

5
changes/md_leak_bug Normal file
View File

@ -0,0 +1,5 @@
o Major bugfixes (security, OOM)
- Fix a memory leak that could occur if a microdescriptor parse
fails during the tokenizing step. This could enable a memory
exhaustion attack by directory servers. Fixes bug #11649; bugfix
on 0.2.2.6-alpha.

View File

@ -1475,6 +1475,15 @@ is non-zero):
localhost, RFC1918 addresses, and so on. This can create security issues;
you should probably leave it off. (Default: 0)
**MaxMemInCellQueues** __N__ **bytes**|**KB**|**MB**|**GB**::
This option configures a threshold above which Tor will assume that it
needs to stop queueing cells because it's about to run out of memory.
If it hits this threshold, it will begin killing circuits until it
has recovered at least 10% of this memory. Do not set this option too
low, or your relay may be unreliable under load. This option only
effects circuit queues, so the actual process size will be larger than
this. (Default: 8GB)
DIRECTORY SERVER OPTIONS
------------------------

View File

@ -22,6 +22,8 @@ void mp_pool_destroy(mp_pool_t *pool);
void mp_pool_assert_ok(mp_pool_t *pool);
void mp_pool_log_status(mp_pool_t *pool, int severity);
#define MP_POOL_ITEM_OVERHEAD (sizeof(void*))
#define MEMPOOL_STATS
#ifdef MEMPOOL_PRIVATE

View File

@ -1176,10 +1176,11 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
goto error;
#endif
/* Tell OpenSSL to use SSL3 or TLS1 but not SSL2. */
/* Tell OpenSSL to use TLS 1.0 or later but not SSL2 or SSL3. */
if (!(result->ctx = SSL_CTX_new(SSLv23_method())))
goto error;
SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(result->ctx, SSL_OP_NO_SSLv3);
/* Disable TLS1.1 and TLS1.2 if they exist. We need to do this to
* workaround a bug present in all OpenSSL 1.0.1 versions (as of 1
@ -1204,6 +1205,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
SSL_CTX_set_options(result->ctx, SSL_OP_NO_TICKET);
#endif
/* XXX This block is now obsolete. */
if (
#ifdef DISABLE_SSL3_HANDSHAKE
1 ||

View File

@ -3256,10 +3256,10 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
* <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
* safe.
*
* <b>hex_errno</b> must have at least HEX_ERRNO_SIZE bytes available.
* <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available.
*
* The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded
* with spaces. Note that there is no trailing \0. CHILD_STATE indicates where
* with spaces. CHILD_STATE indicates where
* in the processs of starting the child process did the failure occur (see
* CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of
* errno when the failure occurred.
@ -3294,7 +3294,7 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
* Count how many chars of space we have left, and keep a pointer into the
* current point in the buffer.
*/
left = HEX_ERRNO_SIZE;
left = HEX_ERRNO_SIZE+1;
cur = hex_errno;
/* Emit child_state */
@ -3338,8 +3338,8 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
left -= written;
cur += written;
/* Check that we have enough space left for a newline */
if (left <= 0)
/* Check that we have enough space left for a newline and a NUL */
if (left <= 1)
goto err;
/* Emit the newline and NUL */
@ -3594,7 +3594,7 @@ tor_spawn_background(const char *const filename, const char **argv,
this is used for printing out the error message */
unsigned char child_state = CHILD_STATE_INIT;
char hex_errno[HEX_ERRNO_SIZE];
char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */
static int max_fd = -1;

File diff suppressed because it is too large Load Diff

View File

@ -147,7 +147,8 @@ static INLINE chunk_freelist_t *
get_freelist(size_t alloc)
{
int i;
for (i=0; freelists[i].alloc_size <= alloc; ++i) {
for (i=0; (freelists[i].alloc_size <= alloc &&
freelists[i].alloc_size); ++i ) {
if (freelists[i].alloc_size == alloc) {
return &freelists[i];
}

View File

@ -147,7 +147,7 @@ static void pathbias_count_success(origin_circuit_t *circ);
* 3. If we are a directory authority
* 4. If we fail to write circuit build time history to our state file.
*/
static int
int
circuit_build_times_disabled(void)
{
if (unit_tests) {

View File

@ -32,6 +32,7 @@ char *circuit_list_path_for_controller(origin_circuit_t *circ);
void circuit_log_path(int severity, unsigned int domain,
origin_circuit_t *circ);
void circuit_rep_hist_note_result(origin_circuit_t *circ);
int circuit_build_times_disabled(void);
origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,

View File

@ -1359,6 +1359,144 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line,
}
}
/** Given a marked circuit <b>circ</b>, aggressively free its cell queues to
* recover memory. */
static void
marked_circuit_free_cells(circuit_t *circ)
{
if (!circ->marked_for_close) {
log_warn(LD_BUG, "Called on non-marked circuit");
return;
}
cell_queue_clear(&circ->n_conn_cells);
if (! CIRCUIT_IS_ORIGIN(circ))
cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_conn_cells);
}
/** Return the number of cells used by the circuit <b>c</b>'s cell queues. */
static size_t
n_cells_in_circ_queues(const circuit_t *c)
{
size_t n = c->n_conn_cells.n;
if (! CIRCUIT_IS_ORIGIN(c))
n += TO_OR_CIRCUIT((circuit_t*)c)->p_conn_cells.n;
return n;
}
/**
* Return the age of the oldest cell queued on <b>c</b>, in milliseconds.
* Return 0 if there are no cells queued on c. Requires that <b>now</b> be
* the current time in milliseconds since the epoch, truncated.
*
* This function will return incorrect results if the oldest cell queued on
* the circuit is older than 2**32 msec (about 49 days) old.
*/
static uint32_t
circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
{
uint32_t age = 0;
if (c->n_conn_cells.head)
age = now - c->n_conn_cells.head->inserted_time;
if (! CIRCUIT_IS_ORIGIN(c)) {
const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c);
if (orcirc->p_conn_cells.head) {
uint32_t age2 = now - orcirc->p_conn_cells.head->inserted_time;
if (age2 > age)
return age2;
}
}
return age;
}
/** Temporary variable for circuits_compare_by_oldest_queued_cell_ This is a
* kludge to work around the fact that qsort doesn't provide a way for
* comparison functions to take an extra argument. */
static uint32_t circcomp_now_tmp;
/** Helper to sort a list of circuit_t by age of oldest cell, in descending
* order. Requires that circcomp_now_tmp is set correctly. */
static int
circuits_compare_by_oldest_queued_cell_(const void **a_, const void **b_)
{
const circuit_t *a = *a_;
const circuit_t *b = *b_;
uint32_t age_a = circuit_max_queued_cell_age(a, circcomp_now_tmp);
uint32_t age_b = circuit_max_queued_cell_age(b, circcomp_now_tmp);
if (age_a < age_b)
return 1;
else if (age_a == age_b)
return 0;
else
return -1;
}
#define FRACTION_OF_CELLS_TO_RETAIN_ON_OOM 0.90
/** We're out of memory for cells, having allocated <b>current_allocation</b>
* bytes' worth. Kill the 'worst' circuits until we're under
* FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM of our maximum usage. */
void
circuits_handle_oom(size_t current_allocation)
{
/* Let's hope there's enough slack space for this allocation here... */
smartlist_t *circlist = smartlist_new();
circuit_t *circ;
size_t n_cells_removed=0, n_cells_to_remove;
int n_circuits_killed=0;
struct timeval now;
log_notice(LD_GENERAL, "We're low on memory. Killing circuits with "
"over-long queues. (This behavior is controlled by "
"MaxMemInCellQueues.)");
{
size_t mem_target = (size_t)(get_options()->MaxMemInCellQueues *
FRACTION_OF_CELLS_TO_RETAIN_ON_OOM);
size_t mem_to_recover;
if (current_allocation <= mem_target)
return;
mem_to_recover = current_allocation - mem_target;
n_cells_to_remove = CEIL_DIV(mem_to_recover, packed_cell_mem_cost());
}
/* This algorithm itself assumes that you've got enough memory slack
* to actually run it. */
for (circ = global_circuitlist; circ; circ = circ->next)
smartlist_add(circlist, circ);
/* Set circcomp_now_tmp so that the sort can work. */
tor_gettimeofday_cached(&now);
circcomp_now_tmp = (uint32_t)tv_to_msec(&now);
/* This is O(n log n); there are faster algorithms we could use instead.
* Let's hope this doesn't happen enough to be in the critical path. */
smartlist_sort(circlist, circuits_compare_by_oldest_queued_cell_);
/* Okay, now the worst circuits are at the front of the list. Let's mark
* them, and reclaim their storage aggressively. */
SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
size_t n = n_cells_in_circ_queues(circ);
if (! circ->marked_for_close) {
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
}
marked_circuit_free_cells(circ);
++n_circuits_killed;
n_cells_removed += n;
if (n_cells_removed >= n_cells_to_remove)
break;
} SMARTLIST_FOREACH_END(circ);
clean_cell_pool(); /* In case this helps. */
log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits.",
U64_PRINTF_ARG(n_cells_removed * packed_cell_mem_cost()),
n_circuits_killed);
smartlist_free(circlist);
}
/** Verify that cpath layer <b>cp</b> has all of its invariants
* correct. Trigger an assert if anything is invalid.
*/

View File

@ -57,6 +57,7 @@ int circuit_count_pending_on_or_conn(or_connection_t *or_conn);
void assert_cpath_layer_ok(const crypt_path_t *cp);
void assert_circuit_ok(const circuit_t *c);
void circuit_free_all(void);
void circuits_handle_oom(size_t current_allocation);
#endif

View File

@ -746,7 +746,7 @@ circuit_predict_and_launch_new(void)
* want, don't do another -- we want to leave a few slots open so
* we can still build circuits preemptively as needed. */
if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
get_options()->LearnCircuitBuildTimeout &&
! circuit_build_times_disabled() &&
circuit_build_times_needs_circuits_now(&circ_times)) {
flags = CIRCLAUNCH_NEED_CAPACITY;
log_info(LD_CIRC,
@ -882,7 +882,7 @@ circuit_expire_old_circuits_clientside(void)
tor_gettimeofday(&now);
cutoff = now;
if (get_options()->LearnCircuitBuildTimeout &&
if (! circuit_build_times_disabled() &&
circuit_build_times_needs_circuits(&circ_times)) {
/* Circuits should be shorter lived if we need more of them
* for learning a good build timeout */
@ -1310,7 +1310,7 @@ circuit_launch_by_extend_info(uint8_t purpose,
circ = circuit_find_to_cannibalize(purpose, extend_info, flags);
if (circ) {
uint8_t old_purpose = circ->_base.purpose;
struct timeval old_timestamp_created;
struct timeval old_timestamp_created = circ->_base.timestamp_created;
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d (%s)",
build_state_get_exit_nickname(circ->build_state), purpose,

View File

@ -755,8 +755,8 @@ command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
const int send_versions = !started_here;
/* If we want to authenticate, send a CERTS cell */
const int send_certs = !started_here || public_server_mode(get_options());
/* If we're a relay that got a connection, ask for authentication. */
const int send_chall = !started_here && public_server_mode(get_options());
/* If we're a host that got a connection, ask for authentication. */
const int send_chall = !started_here;
/* If our certs cell will authenticate us, we can send a netinfo cell
* right now. */
const int send_netinfo = !started_here;
@ -941,6 +941,16 @@ command_process_netinfo_cell(cell_t *cell, or_connection_t *conn)
* trustworthy. */
(void)my_apparent_addr;
if (! conn->handshake_state->sent_netinfo) {
/* If we were prepared to authenticate, but we never got an AUTH_CHALLENGE
* cell, then we would not previously have sent a NETINFO cell. Do so
* now. */
if (connection_or_send_netinfo(conn) < 0) {
connection_mark_for_close(TO_CONN(conn));
return;
}
}
if (connection_or_set_state_open(conn)<0) {
log_fn(LOG_PROTOCOL_WARN, LD_OR, "Got good NETINFO cell from %s:%d; but "
"was unable to make the OR connection become open.",

View File

@ -343,6 +343,7 @@ static config_var_t _option_vars[] = {
V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"),
V(MaxCircuitDirtiness, INTERVAL, "10 minutes"),
V(MaxClientCircuitsPending, UINT, "32"),
V(MaxMemInCellQueues, MEMUNIT, "8 GB"),
V(MaxOnionsPending, UINT, "100"),
OBSOLETE("MonthlyAccountingStart"),
V(MyFamily, STRING, NULL),
@ -960,7 +961,7 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
"76.73.17.194:9030 F397 038A DC51 3361 35E7 B80B D99C A384 4360 292B",
"gabelmoo orport=443 no-v2 "
"v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
"212.112.245.170:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
"131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
"dannenberg orport=443 no-v2 "
"v3ident=585769C78764D58426B8B52B6651A5A71137189A "
"193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
@ -3668,6 +3669,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
log_warn(LD_CONFIG, "EntryNodes is set, but UseEntryGuards is disabled. "
"EntryNodes will be ignored.");
if (options->MaxMemInCellQueues < (500 << 20)) {
log_warn(LD_CONFIG, "MaxMemInCellQueues must be at least 500 MB for now. "
"Ideally, have it as large as you can afford.");
options->MaxMemInCellQueues = (500 << 20);
}
options->_AllowInvalid = 0;
if (options->AllowInvalidNodes) {
SMARTLIST_FOREACH_BEGIN(options->AllowInvalidNodes, const char *, cp) {
@ -4042,6 +4049,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("If you set UseBridges, you must specify at least one bridge.");
if (options->UseBridges && !options->TunnelDirConns)
REJECT("If you set UseBridges, you must set TunnelDirConns.");
if (options->RendConfigLines &&
(!options->TunnelDirConns || !options->PreferTunneledDirConns))
REJECT("If you are running a hidden service, you must set TunnelDirConns "
"and PreferTunneledDirConns");
for (cl = options->Bridges; cl; cl = cl->next) {
if (parse_bridge_line(cl->value, 1)<0)

View File

@ -2825,7 +2825,20 @@ connection_read_to_buf(connection_t *conn, ssize_t *max_to_read,
case TOR_TLS_WANTWRITE:
connection_start_writing(conn);
return 0;
case TOR_TLS_WANTREAD: /* we're already reading */
case TOR_TLS_WANTREAD:
if (conn->in_connection_handle_write) {
/* We've been invoked from connection_handle_write, because we're
* waiting for a TLS renegotiation, the renegotiation started, and
* SSL_read returned WANTWRITE. But now SSL_read is saying WANTREAD
* again. Stop waiting for write events now, or else we'll
* busy-loop until data arrives for us to read. */
connection_stop_writing(conn);
if (!connection_is_reading(conn))
connection_start_reading(conn);
}
/* we're already reading, one hopes */
result = 0;
break;
case TOR_TLS_DONE: /* no data read, so nothing to process */
result = 0;
break; /* so we call bucket_decrement below */
@ -3337,7 +3350,9 @@ connection_handle_write(connection_t *conn, int force)
{
int res;
tor_gettimeofday_cache_clear();
conn->in_connection_handle_write = 1;
res = connection_handle_write_impl(conn, force);
conn->in_connection_handle_write = 0;
return res;
}

View File

@ -3302,12 +3302,13 @@ connection_exit_connect(edge_connection_t *edge_conn)
conn->state = EXIT_CONN_STATE_OPEN;
if (connection_get_outbuf_len(conn)) {
/* in case there are any queued data cells */
log_warn(LD_BUG,"newly connected conn had data waiting!");
// connection_start_writing(conn);
/* in case there are any queued data cells, from e.g. optimistic data */
IF_HAS_NO_BUFFEREVENT(conn)
connection_watch_events(conn, READ_EVENT|WRITE_EVENT);
} else {
IF_HAS_NO_BUFFEREVENT(conn)
connection_watch_events(conn, READ_EVENT);
}
IF_HAS_NO_BUFFEREVENT(conn)
connection_watch_events(conn, READ_EVENT);
/* also, deliver a 'connected' cell back through the circuit. */
if (connection_edge_is_rendezvous_stream(edge_conn)) {

View File

@ -1975,6 +1975,12 @@ connection_or_send_netinfo(or_connection_t *conn)
tor_assert(conn->handshake_state);
if (conn->handshake_state->sent_netinfo) {
log_warn(LD_BUG, "Attempted to send an extra netinfo cell on a connection "
"where we already sent one.");
return 0;
}
memset(&cell, 0, sizeof(cell_t));
cell.command = CELL_NETINFO;
@ -2009,6 +2015,7 @@ connection_or_send_netinfo(or_connection_t *conn)
}
conn->handshake_state->digest_sent_data = 0;
conn->handshake_state->sent_netinfo = 1;
connection_or_write_cell_to_buf(&cell, conn);
return 0;
@ -2137,7 +2144,7 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
const tor_cert_t *id_cert=NULL, *link_cert=NULL;
const digests_t *my_digests, *their_digests;
const uint8_t *my_id, *their_id, *client_id, *server_id;
if (tor_tls_get_my_certs(0, &link_cert, &id_cert))
if (tor_tls_get_my_certs(server, &link_cert, &id_cert))
return -1;
my_digests = tor_cert_get_id_digests(id_cert);
their_digests = tor_cert_get_id_digests(conn->handshake_state->id_cert);

View File

@ -561,7 +561,7 @@ microdesc_free(microdesc_t *md)
}
});
if (found) {
log_warn(LD_BUG, "microdesc_free() called, but md was still referenced "
log_info(LD_BUG, "microdesc_free() called, but md was still referenced "
"%d node(s); held_by_nodes == %u", found, md->held_by_nodes);
} else {
log_warn(LD_BUG, "microdesc_free() called with held_by_nodes set to %u, "

View File

@ -453,6 +453,17 @@ networkstatus_check_document_signature(const networkstatus_t *consensus,
DIGEST_LEN))
return -1;
if (authority_cert_is_blacklisted(cert)) {
/* We implement blacklisting for authority signing keys by treating
* all their signatures as always bad. That way we don't get into
* crazy loops of dropping and re-fetching signatures. */
log_warn(LD_DIR, "Ignoring a consensus signature made with deprecated"
" signing key %s",
hex_str(cert->signing_key_digest, DIGEST_LEN));
sig->bad_signature = 1;
return 0;
}
signed_digest_len = crypto_pk_keysize(cert->signing_key);
signed_digest = tor_malloc(signed_digest_len);
if (crypto_pk_public_checksig(cert->signing_key,
@ -1239,7 +1250,7 @@ update_consensus_networkstatus_downloads(time_t now)
}
if (time_to_download_next_consensus[i] > now)
return; /* Wait until the current consensus is older. */
continue; /* Wait until the current consensus is older. */
resource = networkstatus_get_flavor_name(i);

View File

@ -539,6 +539,8 @@ typedef enum {
#define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \
((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \
(p) == CIRCUIT_PURPOSE_S_REND_JOINED)
/** True iff the circuit_t c is actually an or_circuit_t */
#define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC)
/** How many circuits do we want simultaneously in-progress to handle
* a given stream? */
@ -814,6 +816,13 @@ typedef enum {
/** Amount to increment a stream window when we get a stream SENDME. */
#define STREAMWINDOW_INCREMENT 50
/** Maximum number of queued cells on a circuit for which we are the
* midpoint before we give up and kill it. This must be >= circwindow
* to avoid killing innocent circuits, and >= circwindow*2 to give
* leaky-pipe a chance for being useful someday.
*/
#define ORCIRC_MAX_MIDDLE_CELLS (21*(CIRCWINDOW_START_MAX)/10)
/* Cell commands. These values are defined in tor-spec.txt. */
#define CELL_PADDING 0
#define CELL_CREATE 1
@ -903,8 +912,13 @@ typedef struct var_cell_t {
typedef struct packed_cell_t {
struct packed_cell_t *next; /**< Next cell queued on this circuit. */
char body[CELL_NETWORK_SIZE]; /**< Cell as packed for network. */
uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high
* bits truncated) when this cell was inserted. */
} packed_cell_t;
/* XXXX This next structure may be obsoleted by inserted_time in
* packed_cell_t */
/** Number of cells added to a circuit queue including their insertion
* time on 10 millisecond detail; used for buffer statistics. */
typedef struct insertion_time_elem_t {
@ -998,6 +1012,9 @@ typedef struct connection_t {
/** Set to 1 when we're inside connection_flushed_some to keep us from
* calling connection_handle_write() recursively. */
unsigned int in_flushed_some:1;
/** True if connection_handle_write is currently running on this connection.
*/
unsigned int in_connection_handle_write:1;
/* For linked connections:
*/
@ -1149,6 +1166,9 @@ typedef struct or_handshake_state_t {
/* True iff we've received valid authentication to some identity. */
unsigned int authenticated : 1;
/* True iff we have sent a netinfo cell */
unsigned int sent_netinfo : 1;
/** True iff we should feed outgoing cells into digest_sent and
* digest_received respectively.
*
@ -3052,6 +3072,10 @@ typedef struct {
config_line_t *DirPort_lines;
config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */
uint64_t MaxMemInCellQueues; /**< If we have more memory than this allocated
* for circuit cell queues, run the OOM handler
*/
/** @name port booleans
*
* Derived booleans: True iff there is a non-listener port on an AF_INET or

View File

@ -1799,7 +1799,7 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
#endif
/** The total number of cells we have allocated from the memory pool. */
static int total_cells_allocated = 0;
static size_t total_cells_allocated = 0;
/** A memory pool to allocate packed_cell_t objects. */
static mp_pool_t *cell_pool = NULL;
@ -1871,7 +1871,7 @@ dump_cell_pool_usage(int severity)
++n_circs;
}
log(severity, LD_MM, "%d cells allocated on %d circuits. %d cells leaked.",
n_cells, n_circs, total_cells_allocated - n_cells);
n_cells, n_circs, (int)total_cells_allocated - n_cells);
mp_pool_log_status(cell_pool, severity);
}
@ -1904,15 +1904,19 @@ cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
void
cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell)
{
struct timeval now;
packed_cell_t *copy = packed_cell_copy(cell);
tor_gettimeofday_cached(&now);
copy->inserted_time = (uint32_t)tv_to_msec(&now);
/* Remember the time when this cell was put in the queue. */
/*XXXX This may be obsoleted by inserted_time */
if (get_options()->CellStatistics) {
struct timeval now;
uint32_t added;
insertion_time_queue_t *it_queue = queue->insertion_times;
if (!it_pool)
it_pool = mp_pool_new(sizeof(insertion_time_elem_t), 1024);
tor_gettimeofday_cached(&now);
#define SECONDS_IN_A_DAY 86400L
added = (uint32_t)(((now.tv_sec % SECONDS_IN_A_DAY) * 100L)
+ ((uint32_t)now.tv_usec / (uint32_t)10000L));
@ -1978,6 +1982,29 @@ cell_queue_pop(cell_queue_t *queue)
return cell;
}
/** Return the total number of bytes used for each packed_cell in a queue.
* Approximate. */
size_t
packed_cell_mem_cost(void)
{
return sizeof(packed_cell_t) + MP_POOL_ITEM_OVERHEAD +
get_options()->CellStatistics ?
(sizeof(insertion_time_elem_t)+MP_POOL_ITEM_OVERHEAD) : 0;
}
/** Check whether we've got too much space used for cells. If so,
* call the OOM handler and return 1. Otherwise, return 0. */
static int
cell_queues_check_size(void)
{
size_t alloc = total_cells_allocated * packed_cell_mem_cost();
if (alloc >= get_options()->MaxMemInCellQueues) {
circuits_handle_oom(alloc);
return 1;
}
return 0;
}
/** Return a pointer to the "next_active_on_{n,p}_conn" pointer of <b>circ</b>,
* depending on whether <b>conn</b> matches n_conn or p_conn. */
static INLINE circuit_t **
@ -2532,8 +2559,10 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream)
{
or_circuit_t *orcirc = NULL;
cell_queue_t *queue;
int streams_blocked;
if (circ->marked_for_close)
return;
@ -2541,13 +2570,43 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn,
queue = &circ->n_conn_cells;
streams_blocked = circ->streams_blocked_on_n_conn;
} else {
or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
orcirc = TO_OR_CIRCUIT(circ);
queue = &orcirc->p_conn_cells;
streams_blocked = circ->streams_blocked_on_p_conn;
}
/*
* Disabling this for now because of a possible guard discovery attack
*/
#if 0
/* Are we a middle circuit about to exceed ORCIRC_MAX_MIDDLE_CELLS? */
if ((circ->n_conn != NULL) && CIRCUIT_IS_ORCIRC(circ)) {
orcirc = TO_OR_CIRCUIT(circ);
if (orcirc->p_conn) {
if (queue->n + 1 >= ORCIRC_MAX_MIDDLE_CELLS) {
/* Queueing this cell would put queue over the cap */
log_warn(LD_CIRC,
"Got a cell exceeding the cap of %u in the %s direction "
"on middle circ ID %u; killing the circuit.",
ORCIRC_MAX_MIDDLE_CELLS,
(direction == CELL_DIRECTION_OUT) ? "n" : "p",
(direction == CELL_DIRECTION_OUT) ?
circ->n_circ_id : orcirc->p_circ_id);
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
return;
}
}
}
#endif
cell_queue_append_packed_copy(queue, cell);
if (PREDICT_UNLIKELY(cell_queues_check_size())) {
/* We ran the OOM handler */
if (circ->marked_for_close)
return;
}
/* If we have too many cells on the circuit, we should stop reading from
* the edge streams for a while. */
if (!streams_blocked && queue->n >= CELL_QUEUE_HIGHWATER_SIZE)

View File

@ -40,6 +40,7 @@ void init_cell_pool(void);
void free_cell_pool(void);
void clean_cell_pool(void);
void dump_cell_pool_usage(int severity);
size_t packed_cell_mem_cost(void);
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);

View File

@ -1002,6 +1002,10 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
return 0;
}
/* Do not allow more than this many introduction points in a hidden service
* descriptor */
#define MAX_INTRO_POINTS 10
/** Parse *desc, calculate its service id, and store it in the cache.
* If we have a newer v0 descriptor with the same ID, ignore this one.
* If we have an older descriptor with the same ID, replace it.
@ -1070,6 +1074,16 @@ rend_cache_store(const char *desc, size_t desc_len, int published,
rend_service_descriptor_free(parsed);
return -1;
}
if (parsed->intro_nodes &&
smartlist_len(parsed->intro_nodes) > MAX_INTRO_POINTS) {
log_warn(LD_REND, "Found too many introduction points on a hidden "
"service descriptor for %s. This is probably a (misguided) "
"attempt to improve reliability, but it could also be an "
"attempt to do a guard enumeration attack. Rejecting.",
safe_str_client(query));
rend_service_descriptor_free(parsed);
return -2;
}
tor_snprintf(key, sizeof(key), "0%s", query);
e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
if (e && e->parsed->timestamp > parsed->timestamp) {
@ -1288,6 +1302,7 @@ rend_cache_store_v2_desc_as_client(const char *desc,
}
/* Decode/decrypt introduction points. */
if (intro_content) {
int n_intro_points;
if (rend_query->auth_type != REND_NO_AUTH &&
!tor_mem_is_zero(rend_query->descriptor_cookie,
sizeof(rend_query->descriptor_cookie))) {
@ -1308,13 +1323,22 @@ rend_cache_store_v2_desc_as_client(const char *desc,
intro_size = ipos_decrypted_size;
}
}
if (rend_parse_introduction_points(parsed, intro_content,
intro_size) <= 0) {
n_intro_points = rend_parse_introduction_points(parsed, intro_content,
intro_size);
if (n_intro_points <= 0) {
log_warn(LD_REND, "Failed to parse introduction points. Either the "
"service has published a corrupt descriptor or you have "
"provided invalid authorization data.");
retval = -2;
goto err;
} else if (n_intro_points > MAX_INTRO_POINTS) {
log_warn(LD_REND, "Found too many introduction points on a hidden "
"service descriptor for %s. This is probably a (misguided) "
"attempt to improve reliability, but it could also be an "
"attempt to do a guard enumeration attack. Rejecting.",
safe_str_client(rend_query->onion_address));
retval = -2;
goto err;
}
} else {
log_info(LD_REND, "Descriptor does not contain any introduction points.");

View File

@ -177,7 +177,7 @@ get_server_identity_key(void)
int
server_identity_key_is_set(void)
{
return server_identitykey != NULL;
return server_mode(get_options()) && server_identitykey != NULL;
}
/** Set the current client identity key to <b>k</b>.

View File

@ -458,6 +458,37 @@ authority_cert_dl_failed(const char *id_digest, int status)
download_status_failed(&cl->dl_status, status);
}
static const char *BAD_SIGNING_KEYS[] = {
"09CD84F751FD6E955E0F8ADB497D5401470D697E", // Expires 2015-01-11 16:26:31
"0E7E9C07F0969D0468AD741E172A6109DC289F3C", // Expires 2014-08-12 10:18:26
"57B85409891D3FB32137F642FDEDF8B7F8CDFDCD", // Expires 2015-02-11 17:19:09
"87326329007AF781F587AF5B594E540B2B6C7630", // Expires 2014-07-17 11:10:09
"98CC82342DE8D298CF99D3F1A396475901E0D38E", // Expires 2014-11-10 13:18:56
"9904B52336713A5ADCB13E4FB14DC919E0D45571", // Expires 2014-04-20 20:01:01
"9DCD8E3F1DD1597E2AD476BBA28A1A89F3095227", // Expires 2015-01-16 03:52:30
"A61682F34B9BB9694AC98491FE1ABBFE61923941", // Expires 2014-06-11 09:25:09
"B59F6E99C575113650C99F1C425BA7B20A8C071D", // Expires 2014-07-31 13:22:10
"D27178388FA75B96D37FA36E0B015227DDDBDA51", // Expires 2014-08-04 04:01:57
NULL,
};
/** DOCDOC */
int
authority_cert_is_blacklisted(const authority_cert_t *cert)
{
char hex_digest[HEX_DIGEST_LEN+1];
int i;
base16_encode(hex_digest, sizeof(hex_digest),
cert->signing_key_digest, sizeof(cert->signing_key_digest));
for (i = 0; BAD_SIGNING_KEYS[i]; ++i) {
if (!strcasecmp(hex_digest, BAD_SIGNING_KEYS[i])) {
return 1;
}
}
return 0;
}
/** Return true iff when we've been getting enough failures when trying to
* download the certificate with ID digest <b>id_digest</b> that we're willing
* to start bugging the user about it. */

View File

@ -25,6 +25,7 @@ void authority_cert_dl_failed(const char *id_digest, int status);
void authority_certs_fetch_missing(networkstatus_t *status, time_t now);
int router_reload_router_list(void);
int authority_cert_dl_looks_uncertain(const char *id_digest);
int authority_cert_is_blacklisted(const authority_cert_t *cert);
smartlist_t *router_get_trusted_dir_servers(void);
const routerstatus_t *router_pick_directory_server(dirinfo_type_t type,

View File

@ -3053,6 +3053,14 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
log_warn(LD_DIR,"Mismatch between identities in certificate and vote");
goto err;
}
if (ns->type != NS_TYPE_CONSENSUS) {
if (authority_cert_is_blacklisted(ns->cert)) {
log_warn(LD_DIR, "Rejecting vote signature made with blacklisted "
"signing key %s",
hex_str(ns->cert->signing_key_digest, DIGEST_LEN));
goto err;
}
}
voter->address = tor_strdup(tok->args[2]);
if (!tor_inet_aton(tok->args[3], &in)) {
log_warn(LD_DIR, "Error decoding IP address %s in network-status.",
@ -4447,11 +4455,13 @@ microdescs_parse_from_string(const char *s, const char *eos,
microdesc_free(md);
md = NULL;
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
memarea_clear(area);
smartlist_clear(tokens);
s = start_of_next_microdesc;
}
SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
memarea_drop_all(area);
smartlist_free(tokens);

View File

@ -802,6 +802,18 @@ test_buffers(void)
buf_free(buf);
buf = NULL;
/* Try adding a string too long for any freelist. */
{
char *cp = tor_malloc_zero(65536);
buf = buf_new();
write_to_buf(cp, 65536, buf);
tor_free(cp);
tt_int_op(buf_datalen(buf), ==, 65536);
buf_free(buf);
buf = NULL;
}
done:
if (buf)
buf_free(buf);

View File

@ -2169,6 +2169,7 @@ test_util_exit_status(void *ptr)
n = format_helper_exit_status(0xFF, -0x80000000, hex_errno);
test_streq("FF/-80000000\n", hex_errno);
test_eq(n, strlen(hex_errno));
test_eq(n, HEX_ERRNO_SIZE);
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0x7F, 0, hex_errno);