Merge remote-tracking branch 'tor-github/pr/239'

This commit is contained in:
Nick Mathewson 2018-08-10 12:35:06 -04:00
commit b7ed61167f
4 changed files with 54 additions and 2 deletions

5
changes/bug18642 Normal file
View File

@ -0,0 +1,5 @@
o Minor features (denial-of-service avoidance):
- Make our OOM handler aware of the DNS cache so that it doesn't fill up
the memory. This check is important for our DoS mitigation subsystem.
Closes ticket 18642. Patch by Neel Chauhan

View File

@ -64,6 +64,7 @@
#include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h" #include "lib/crypt_ops/crypto_util.h"
#include "feature/dircache/directory.h" #include "feature/dircache/directory.h"
#include "feature/relay/dns.h"
#include "feature/stats/geoip.h" #include "feature/stats/geoip.h"
#include "feature/hs/hs_cache.h" #include "feature/hs/hs_cache.h"
#include "core/mainloop/main.h" #include "core/mainloop/main.h"
@ -2538,6 +2539,8 @@ cell_queues_check_size(void)
const size_t geoip_client_cache_total = const size_t geoip_client_cache_total =
geoip_client_cache_total_allocation(); geoip_client_cache_total_allocation();
alloc += geoip_client_cache_total; alloc += geoip_client_cache_total;
const size_t dns_cache_total = dns_cache_total_allocation();
alloc += dns_cache_total;
if (alloc >= get_options()->MaxMemInQueues_low_threshold) { if (alloc >= get_options()->MaxMemInQueues_low_threshold) {
last_time_under_memory_pressure = approx_time(); last_time_under_memory_pressure = approx_time();
if (alloc >= get_options()->MaxMemInQueues) { if (alloc >= get_options()->MaxMemInQueues) {
@ -2555,6 +2558,11 @@ cell_queues_check_size(void)
(size_t)(get_options()->MaxMemInQueues / 10); (size_t)(get_options()->MaxMemInQueues / 10);
alloc -= geoip_client_cache_handle_oom(now, bytes_to_remove); alloc -= geoip_client_cache_handle_oom(now, bytes_to_remove);
} }
if (dns_cache_total > get_options()->MaxMemInQueues / 5) {
const size_t bytes_to_remove =
dns_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
alloc -= dns_cache_handle_oom(now, bytes_to_remove);
}
circuits_handle_oom(alloc); circuits_handle_oom(alloc);
return 1; return 1;
} }

View File

@ -2076,14 +2076,21 @@ dns_cache_entry_count(void)
return HT_SIZE(&cache_root); return HT_SIZE(&cache_root);
} }
/* Return the total size in bytes of the DNS cache. */
size_t
dns_cache_total_allocation(void)
{
return sizeof(struct cached_resolve_t) * dns_cache_entry_count() +
HT_MEM_USAGE(&cache_root);
}
/** Log memory information about our internal DNS cache at level 'severity'. */ /** Log memory information about our internal DNS cache at level 'severity'. */
void void
dump_dns_mem_usage(int severity) dump_dns_mem_usage(int severity)
{ {
/* This should never be larger than INT_MAX. */ /* This should never be larger than INT_MAX. */
int hash_count = dns_cache_entry_count(); int hash_count = dns_cache_entry_count();
size_t hash_mem = sizeof(struct cached_resolve_t) * hash_count; size_t hash_mem = dns_cache_total_allocation();
hash_mem += HT_MEM_USAGE(&cache_root);
/* Print out the count and estimated size of our &cache_root. It undercounts /* Print out the count and estimated size of our &cache_root. It undercounts
hostnames in cached reverse resolves. hostnames in cached reverse resolves.
@ -2093,6 +2100,36 @@ dump_dns_mem_usage(int severity)
(unsigned)hash_mem); (unsigned)hash_mem);
} }
/* Do a round of OOM cleanup on all DNS entries. Return the amount of removed
* bytes. It is possible that the returned value is lower than min_remove_bytes
* if the caches get emptied out so the caller should be aware of this. */
size_t
dns_cache_handle_oom(time_t now, size_t min_remove_bytes)
{
time_t time_inc = 0;
size_t total_bytes_removed = 0;
size_t current_size = dns_cache_total_allocation();
do {
/* If no DNS entries left, break loop. */
if (!dns_cache_entry_count())
break;
/* Get cutoff interval and remove entries. */
time_t cutoff = now + time_inc;
purge_expired_resolves(cutoff);
/* Update amount of bytes removed and array size. */
size_t bytes_removed = current_size - dns_cache_total_allocation();
current_size -= bytes_removed;
total_bytes_removed += bytes_removed;
time_inc += 3600; /* Increase time_inc by 1 hour. */
} while (total_bytes_removed < min_remove_bytes);
return total_bytes_removed;
}
#ifdef DEBUG_DNS_CACHE #ifdef DEBUG_DNS_CACHE
/** Exit with an assertion if the DNS cache is corrupt. */ /** Exit with an assertion if the DNS cache is corrupt. */
static void static void

View File

@ -38,7 +38,9 @@ void dns_launch_correctness_checks(void);
int dns_seems_to_be_broken(void); int dns_seems_to_be_broken(void);
int dns_seems_to_be_broken_for_ipv6(void); int dns_seems_to_be_broken_for_ipv6(void);
void dns_reset_correctness_checks(void); void dns_reset_correctness_checks(void);
size_t dns_cache_total_allocation(void);
void dump_dns_mem_usage(int severity); void dump_dns_mem_usage(int severity);
size_t dns_cache_handle_oom(time_t now, size_t min_remove_bytes);
#ifdef DNS_PRIVATE #ifdef DNS_PRIVATE
#include "feature/relay/dns_structs.h" #include "feature/relay/dns_structs.h"