diff options
Diffstat (limited to 'src/common')
52 files changed, 3209 insertions, 1262 deletions
diff --git a/src/common/address.c b/src/common/address.c index 793a40effc..773e688554 100644 --- a/src/common/address.c +++ b/src/common/address.c @@ -131,7 +131,8 @@ tor_addr_to_sockaddr(const tor_addr_t *a, #endif sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(port); - memcpy(&sin6->sin6_addr, tor_addr_to_in6(a), sizeof(struct in6_addr)); + memcpy(&sin6->sin6_addr, tor_addr_to_in6_assert(a), + sizeof(struct in6_addr)); return sizeof(struct sockaddr_in6); } else { return 0; @@ -334,7 +335,7 @@ tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr) } else if (ent->h_addrtype == AF_INET6) { tor_addr_from_in6(addr, (struct in6_addr*) ent->h_addr); } else { - tor_assert(0); /* gethostbyname() returned a bizarre addrtype */ + tor_assert(0); // LCOV_EXCL_LINE: gethostbyname() returned bizarre type } return 0; } @@ -905,8 +906,10 @@ tor_addr_is_loopback(const tor_addr_t *addr) case AF_UNSPEC: return 0; default: + /* LCOV_EXCL_START */ tor_fragile_assert(); return 0; + /* LCOV_EXCL_STOP */ } } @@ -1027,7 +1030,7 @@ tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src) case AF_UNSPEC: break; default: - tor_fragile_assert(); + tor_fragile_assert(); // LCOV_EXCL_LINE } } @@ -1038,6 +1041,10 @@ tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src) * Different address families (IPv4 vs IPv6) are always considered unequal if * <b>how</b> is CMP_EXACT; otherwise, IPv6-mapped IPv4 addresses are * considered equivalent to their IPv4 equivalents. + * + * As a special case, all pointer-wise distinct AF_UNIX addresses are always + * considered unequal since tor_addr_t currently does not contain the + * information required to make the comparison. */ int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, @@ -1096,6 +1103,7 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, case AF_INET6: { if (mbits > 128) mbits = 128; + const uint8_t *a1 = tor_addr_to_in6_addr8(addr1); const uint8_t *a2 = tor_addr_to_in6_addr8(addr2); const int bytes = mbits >> 3; @@ -1110,9 +1118,29 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2, return 0; } } + case AF_UNIX: + /* HACKHACKHACKHACKHACK: + * tor_addr_t doesn't contain a copy of sun_path, so it's not + * possible to comapre this at all. + * + * Since the only time we currently actually should be comparing + * 2 AF_UNIX addresses is when dealing with ISO_CLIENTADDR (which + * is disabled for AF_UNIX SocksPorts anyway), this just does + * a pointer comparison. + * + * See: #20261. + */ + if (addr1 < addr2) + return -1; + else if (addr1 == addr2) + return 0; + else + return 1; default: + /* LCOV_EXCL_START */ tor_fragile_assert(); return 0; + /* LCOV_EXCL_STOP */ } } else if (how == CMP_EXACT) { /* Unequal families and an exact comparison? Stop now! */ @@ -1165,14 +1193,16 @@ tor_addr_hash(const tor_addr_t *addr) case AF_INET6: return siphash24g(&addr->addr.in6_addr.s6_addr, 16); default: + /* LCOV_EXCL_START */ tor_fragile_assert(); return 0; + /* LCOV_EXCL_END */ } } /** Return a newly allocated string with a representation of <b>addr</b>. */ char * -tor_dup_addr(const tor_addr_t *addr) +tor_addr_to_str_dup(const tor_addr_t *addr) { char buf[TOR_ADDR_BUF_LEN]; if (tor_addr_to_str(buf, addr, sizeof(buf), 0)) { @@ -1595,6 +1625,7 @@ get_interface_addresses_raw,(int severity, sa_family_t family)) return result; #endif (void) severity; + (void) result; return NULL; } @@ -1761,13 +1792,13 @@ MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity, { if (tor_addr_is_loopback(a) || tor_addr_is_multicast(a)) { - SMARTLIST_DEL_CURRENT(addrs, a); + SMARTLIST_DEL_CURRENT_KEEPORDER(addrs, a); tor_free(a); continue; } if (!include_internal && tor_addr_is_internal(a, 0)) { - SMARTLIST_DEL_CURRENT(addrs, a); + SMARTLIST_DEL_CURRENT_KEEPORDER(addrs, a); tor_free(a); continue; } @@ -1809,7 +1840,7 @@ MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity, /* ====== * IPv4 helpers - * XXXX024 IPv6 deprecate some of these. + * XXXX IPv6 deprecate some of these. */ /** Given an address of the form "ip:port", try to divide it into its diff --git a/src/common/address.h b/src/common/address.h index 53712bde02..51db42c315 100644 --- a/src/common/address.h +++ b/src/common/address.h @@ -74,6 +74,8 @@ typedef struct tor_addr_port_t #define TOR_ADDR_NULL {AF_UNSPEC, {0}} static inline const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); +static inline const struct in6_addr *tor_addr_to_in6_assert( + const tor_addr_t *a); static inline uint32_t tor_addr_to_ipv4n(const tor_addr_t *a); static inline uint32_t tor_addr_to_ipv4h(const tor_addr_t *a); static inline uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a); @@ -97,21 +99,31 @@ tor_addr_to_in6(const tor_addr_t *a) return a->family == AF_INET6 ? &a->addr.in6_addr : NULL; } +/** As tor_addr_to_in6, but assert that the address truly is an IPv6 + * address. */ +static inline const struct in6_addr * +tor_addr_to_in6_assert(const tor_addr_t *a) +{ + tor_assert(a->family == AF_INET6); + return &a->addr.in6_addr; +} + /** Given an IPv6 address <b>x</b>, yield it as an array of uint8_t. * * Requires that <b>x</b> is actually an IPv6 address. */ -#define tor_addr_to_in6_addr8(x) tor_addr_to_in6(x)->s6_addr +#define tor_addr_to_in6_addr8(x) tor_addr_to_in6_assert(x)->s6_addr + /** Given an IPv6 address <b>x</b>, yield it as an array of uint16_t. * * Requires that <b>x</b> is actually an IPv6 address. */ -#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6(x)) +#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6_assert(x)) /** Given an IPv6 address <b>x</b>, yield it as an array of uint32_t. * * Requires that <b>x</b> is actually an IPv6 address. */ -#define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6(x)) +#define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6_assert(x)) /** Return an IPv4 address in network order for <b>a</b>, or 0 if * <b>a</b> is not an IPv4 address. */ @@ -179,7 +191,7 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u) #define TOR_ADDR_BUF_LEN 48 int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out); -char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC; +char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC; /** Wrapper function of fmt_addr_impl(). It does not decorate IPv6 * addresses. */ diff --git a/src/common/aes.c b/src/common/aes.c index 8edfc5d334..35c2d1e3a5 100644 --- a/src/common/aes.c +++ b/src/common/aes.c @@ -23,18 +23,7 @@ #error "We require OpenSSL >= 1.0.0" #endif -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#endif - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic push -#endif -/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in - * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ -#pragma GCC diagnostic ignored "-Wredundant-decls" -#endif +DISABLE_GCC_WARNING(redundant-decls) #include <assert.h> #include <stdlib.h> @@ -44,13 +33,7 @@ #include <openssl/engine.h> #include <openssl/modes.h> -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif +ENABLE_GCC_WARNING(redundant-decls) #include "compat.h" #include "aes.h" @@ -65,7 +48,7 @@ /* We have five strategies for implementing AES counter mode. * - * Best with x86 and x86_64: Use EVP_aes_ctr128() and EVP_EncryptUpdate(). + * Best with x86 and x86_64: Use EVP_aes_*_ctr() and EVP_EncryptUpdate(). * This is possible with OpenSSL 1.0.1, where the counter-mode implementation * can use bit-sliced or vectorized AES or AESNI as appropriate. * @@ -113,11 +96,17 @@ /* We don't actually define the struct here. */ aes_cnt_cipher_t * -aes_new_cipher(const char *key, const char *iv) +aes_new_cipher(const uint8_t *key, const uint8_t *iv, int key_bits) { EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new(); - EVP_EncryptInit(cipher, EVP_aes_128_ctr(), - (const unsigned char*)key, (const unsigned char *)iv); + const EVP_CIPHER *c; + switch (key_bits) { + case 128: c = EVP_aes_128_ctr(); break; + case 192: c = EVP_aes_192_ctr(); break; + case 256: c = EVP_aes_256_ctr(); break; + default: tor_assert(0); // LCOV_EXCL_LINE + } + EVP_EncryptInit(cipher, c, key, iv); return (aes_cnt_cipher_t *) cipher; } void @@ -262,9 +251,11 @@ evaluate_ctr_for_aes(void) if (fast_memneq(output, encrypt_zero, 16)) { /* Counter mode is buggy */ + /* LCOV_EXCL_START */ log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " "quitting tor."); exit(1); + /* LCOV_EXCL_STOP */ } return 0; } @@ -275,20 +266,20 @@ evaluate_ctr_for_aes(void) #define COUNTER(c, n) ((c)->counter ## n) #endif -static void aes_set_key(aes_cnt_cipher_t *cipher, const char *key, +static void aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits); -static void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv); +static void aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv); /** * Return a newly allocated counter-mode AES128 cipher implementation, * using the 128-bit key <b>key</b> and the 128-bit IV <b>iv</b>. */ aes_cnt_cipher_t* -aes_new_cipher(const char *key, const char *iv) +aes_new_cipher(const uint8_t *key, const uint8_t *iv, int bits) { aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t)); - aes_set_key(result, key, 128); + aes_set_key(result, key, bits); aes_set_iv(result, iv); return result; @@ -299,7 +290,7 @@ aes_new_cipher(const char *key, const char *iv) * the counter to 0. */ static void -aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits) +aes_set_key(aes_cnt_cipher_t *cipher, const uint8_t *key, int key_bits) { if (should_use_EVP) { const EVP_CIPHER *c = 0; @@ -307,12 +298,12 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits) case 128: c = EVP_aes_128_ecb(); break; case 192: c = EVP_aes_192_ecb(); break; case 256: c = EVP_aes_256_ecb(); break; - default: tor_assert(0); + default: tor_assert(0); // LCOV_EXCL_LINE } - EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL); + EVP_EncryptInit(&cipher->key.evp, c, key, NULL); cipher->using_evp = 1; } else { - AES_set_encrypt_key((const unsigned char *)key, key_bits,&cipher->key.aes); + AES_set_encrypt_key(key, key_bits,&cipher->key.aes); cipher->using_evp = 0; } @@ -370,6 +361,8 @@ evp_block128_fn(const uint8_t in[16], void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) { + /* Note that the "128" below refers to the length of the counter, + * not the length of the AES key. */ if (cipher->using_evp) { /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If * it weren't disabled, it might be better just to use that. @@ -396,7 +389,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len) /** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value * in <b>iv</b>. */ static void -aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv) +aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) { #ifdef USING_COUNTER_VARS cipher->counter3 = ntohl(get_uint32(iv)); diff --git a/src/common/aes.h b/src/common/aes.h index 821fb742be..1cda53f2fa 100644 --- a/src/common/aes.h +++ b/src/common/aes.h @@ -15,7 +15,8 @@ typedef struct aes_cnt_cipher aes_cnt_cipher_t; -aes_cnt_cipher_t* aes_new_cipher(const char *key, const char *iv); +aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv, + int key_bits); void aes_cipher_free(aes_cnt_cipher_t *cipher); void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len); diff --git a/src/common/backtrace.c b/src/common/backtrace.c index 3b762b68e3..81e04e94eb 100644 --- a/src/common/backtrace.c +++ b/src/common/backtrace.c @@ -13,9 +13,6 @@ * detect crashes. */ -#define __USE_GNU -#define _GNU_SOURCE 1 - #include "orconfig.h" #include "compat.h" #include "util.h" @@ -112,13 +109,15 @@ log_backtrace(int severity, int domain, const char *msg) tor_log(severity, domain, "%s. Stack trace:", msg); if (!symbols) { + /* LCOV_EXCL_START -- we can't provoke this. */ tor_log(severity, domain, " Unable to generate backtrace."); goto done; + /* LCOV_EXCL_STOP */ } for (i=0; i < depth; ++i) { tor_log(severity, domain, " %s", symbols[i]); } - free(symbols); + raw_free(symbols); done: tor_mutex_release(&cb_buf_mutex); @@ -176,8 +175,10 @@ install_bt_handler(void) for (i = 0; trap_signals[i] >= 0; ++i) { if (sigaction(trap_signals[i], &sa, NULL) == -1) { + /* LCOV_EXCL_START */ log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno)); rv = -1; + /* LCOV_EXCL_STOP */ } } @@ -189,7 +190,7 @@ install_bt_handler(void) size_t depth = backtrace(cb_buf, MAX_DEPTH); symbols = backtrace_symbols(cb_buf, (int) depth); if (symbols) - free(symbols); + raw_free(symbols); } return rv; diff --git a/src/common/compat.c b/src/common/compat.c index 23eaa134cf..8d6a491c42 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -12,17 +12,6 @@ * the platform. **/ -/* This is required on rh7 to make strptime not complain. - * We also need it to make memmem get defined (where available) - */ -/* XXXX024 We should just use AC_USE_SYSTEM_EXTENSIONS in our autoconf, - * and get this (and other important stuff!) automatically. Once we do that, - * make sure to also change the extern char **environ detection in - * configure.ac, because whether that is declared or not depends on whether - * we have _GNU_SOURCE defined! Maybe that means that once we take this out, - * we can also take out the configure check. */ -#define _GNU_SOURCE - #define COMPAT_PRIVATE #include "compat.h" @@ -44,6 +33,12 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif +#ifdef HAVE_SYS_UTIME_H +#include <sys/utime.h> +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -100,12 +95,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt) #include "tor_readpassphrase.h" #endif -#ifndef HAVE_GETTIMEOFDAY -#ifdef HAVE_FTIME -#include <sys/timeb.h> -#endif -#endif - /* Includes for the process attaching prevention */ #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) /* Only use the linux prctl; the IRIX prctl is totally different */ @@ -127,12 +116,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt) #ifdef HAVE_SIGNAL_H #include <signal.h> #endif -#ifdef HAVE_UTIME_H -#include <utime.h> -#endif -#ifdef HAVE_SYS_UTIME_H -#include <sys/utime.h> -#endif #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> #endif @@ -142,12 +125,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt) #ifdef HAVE_SYS_FILE_H #include <sys/file.h> #endif -#ifdef TOR_UNIT_TESTS -#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H) -/* as fallback implementation for tor_sleep_msec */ -#include <sys/select.h> -#endif -#endif #include "torlog.h" #include "util.h" @@ -525,8 +502,10 @@ tor_asprintf(char **strp, const char *fmt, ...) r = tor_vasprintf(strp, fmt, args); va_end(args); if (!*strp || r < 0) { + /* LCOV_EXCL_START */ log_err(LD_BUG, "Internal error in asprintf"); tor_assert(0); + /* LCOV_EXCL_STOP */ } return r; } @@ -553,7 +532,10 @@ tor_vasprintf(char **strp, const char *fmt, va_list args) /* On Windows, _vsnprintf won't tell us the length of the string if it * overflows, so we need to use _vcsprintf to tell how much to allocate */ int len, r; - len = _vscprintf(fmt, args); + va_list tmp_args; + va_copy(tmp_args, args); + len = _vscprintf(fmt, tmp_args); + va_end(tmp_args); if (len < 0) { *strp = NULL; return -1; @@ -666,7 +648,7 @@ const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; /** Upper-casing and lowercasing tables to map characters to upper/lowercase * equivalents. Used by tor_toupper() and tor_tolower(). */ /**@{*/ -const char TOR_TOUPPER_TABLE[256] = { +const uint8_t TOR_TOUPPER_TABLE[256] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, @@ -684,7 +666,7 @@ const char TOR_TOUPPER_TABLE[256] = { 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, }; -const char TOR_TOLOWER_TABLE[256] = { +const uint8_t TOR_TOLOWER_TABLE[256] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, @@ -1131,8 +1113,8 @@ tor_close_socket_simple(tor_socket_t s) /** As tor_close_socket_simple(), but keeps track of the number * of open sockets. Returns 0 on success, -1 on failure. */ -int -tor_close_socket(tor_socket_t s) +MOCK_IMPL(int, +tor_close_socket,(tor_socket_t s)) { int r = tor_close_socket_simple(s); @@ -1154,14 +1136,12 @@ tor_close_socket(tor_socket_t s) --n_sockets_open; #else if (r != EBADF) - --n_sockets_open; + --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force. #endif r = -1; } - if (n_sockets_open < 0) - log_warn(LD_BUG, "Our socket count is below zero: %d. Please submit a " - "bug report.", n_sockets_open); + tor_assert_nonfatal(n_sockets_open >= 0); socket_accounting_unlock(); return r; } @@ -1204,10 +1184,10 @@ tor_open_socket,(int domain, int type, int protocol)) /** Mockable wrapper for connect(). */ MOCK_IMPL(tor_socket_t, -tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address, +tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address, socklen_t address_len)) { - return connect(socket,address,address_len); + return connect(sock,address,address_len); } /** As socket(), but creates a nonblocking socket and @@ -1382,31 +1362,31 @@ get_n_open_sockets(void) /** Mockable wrapper for getsockname(). */ MOCK_IMPL(int, -tor_getsockname,(tor_socket_t socket, struct sockaddr *address, +tor_getsockname,(tor_socket_t sock, struct sockaddr *address, socklen_t *address_len)) { - return getsockname(socket, address, address_len); + return getsockname(sock, address, address_len); } /** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1 * on failure. */ int -set_socket_nonblocking(tor_socket_t socket) +set_socket_nonblocking(tor_socket_t sock) { #if defined(_WIN32) unsigned long nonblocking = 1; - ioctlsocket(socket, FIONBIO, (unsigned long*) &nonblocking); + ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking); #else int flags; - flags = fcntl(socket, F_GETFL, 0); + flags = fcntl(sock, F_GETFL, 0); if (flags == -1) { log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); return -1; } flags |= O_NONBLOCK; - if (fcntl(socket, F_SETFL, flags) == -1) { + if (fcntl(sock, F_SETFL, flags) == -1) { log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); return -1; } @@ -1941,7 +1921,7 @@ tor_getpwnam(const char *username) return NULL; if (! strcmp(username, passwd_cached->pw_name)) - return passwd_cached; + return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky return NULL; } @@ -1967,7 +1947,7 @@ tor_getpwuid(uid_t uid) return NULL; if (uid == passwd_cached->pw_uid) - return passwd_cached; + return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky return NULL; } @@ -2350,28 +2330,15 @@ get_parent_directory(char *fname) static char * alloc_getcwd(void) { - int saved_errno = errno; -/* We use this as a starting path length. Not too large seems sane. */ -#define START_PATH_LENGTH 128 -/* Nobody has a maxpath longer than this, as far as I know. And if they - * do, they shouldn't. */ -#define MAX_SANE_PATH_LENGTH 4096 - size_t path_length = START_PATH_LENGTH; - char *path = tor_malloc(path_length); - - errno = 0; - while (getcwd(path, path_length) == NULL) { - if (errno == ERANGE && path_length < MAX_SANE_PATH_LENGTH) { - path_length*=2; - path = tor_realloc(path, path_length); - } else { - tor_free(path); - path = NULL; - break; - } - } - errno = saved_errno; - return path; +#ifdef PATH_MAX +#define MAX_CWD PATH_MAX +#else +#define MAX_CWD 4096 +#endif + + char path_buf[MAX_CWD]; + char *path = getcwd(path_buf, sizeof(path_buf)); + return path ? tor_strdup(path) : NULL; } #endif @@ -2386,7 +2353,7 @@ make_path_absolute(char *fname) /* We don't want to assume that tor_free can free a string allocated * with malloc. On failure, return fname (it's better than nothing). */ char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); - if (absfname_malloced) free(absfname_malloced); + if (absfname_malloced) raw_free(absfname_malloced); return absfname; #else @@ -2402,11 +2369,13 @@ make_path_absolute(char *fname) tor_asprintf(&absfname, "%s/%s", path, fname); tor_free(path); } else { + /* LCOV_EXCL_START Can't make getcwd fail. */ /* If getcwd failed, the best we can do here is keep using the * relative path. (Perhaps / isn't readable by this UID/GID.) */ log_warn(LD_GENERAL, "Unable to find current working directory: %s", strerror(errno)); absfname = tor_strdup(fname); + /* LCOV_EXCL_STOP */ } } return absfname; @@ -2770,7 +2739,9 @@ MOCK_IMPL(const char *, get_uname, (void)) } #endif #else + /* LCOV_EXCL_START -- can't provoke uname failure */ strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); + /* LCOV_EXCL_STOP */ #endif } uname_result_is_set = 1; @@ -2844,59 +2815,19 @@ compute_num_cpus(void) if (num_cpus == -2) { num_cpus = compute_num_cpus_impl(); tor_assert(num_cpus != -2); - if (num_cpus > MAX_DETECTABLE_CPUS) + if (num_cpus > MAX_DETECTABLE_CPUS) { + /* LCOV_EXCL_START */ log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " "will not autodetect any more than %d, though. If you " "want to configure more, set NumCPUs in your torrc", num_cpus, MAX_DETECTABLE_CPUS); + num_cpus = MAX_DETECTABLE_CPUS; + /* LCOV_EXCL_STOP */ + } } return num_cpus; } -/** Set *timeval to the current time of day. On error, log and terminate. - * (Same as gettimeofday(timeval,NULL), but never returns -1.) - */ -void -tor_gettimeofday(struct timeval *timeval) -{ -#ifdef _WIN32 - /* Epoch bias copied from perl: number of units between windows epoch and - * Unix epoch. */ -#define EPOCH_BIAS U64_LITERAL(116444736000000000) -#define UNITS_PER_SEC U64_LITERAL(10000000) -#define USEC_PER_SEC U64_LITERAL(1000000) -#define UNITS_PER_USEC U64_LITERAL(10) - union { - uint64_t ft_64; - FILETIME ft_ft; - } ft; - /* number of 100-nsec units since Jan 1, 1601 */ - GetSystemTimeAsFileTime(&ft.ft_ft); - if (ft.ft_64 < EPOCH_BIAS) { - log_err(LD_GENERAL,"System time is before 1970; failing."); - exit(1); - } - ft.ft_64 -= EPOCH_BIAS; - timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); - timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); -#elif defined(HAVE_GETTIMEOFDAY) - if (gettimeofday(timeval, NULL)) { - log_err(LD_GENERAL,"gettimeofday failed."); - /* If gettimeofday dies, we have either given a bad timezone (we didn't), - or segfaulted.*/ - exit(1); - } -#elif defined(HAVE_FTIME) - struct timeb tb; - ftime(&tb); - timeval->tv_sec = tb.time; - timeval->tv_usec = tb.millitm * 1000; -#else -#error "No way to get time." -#endif - return; -} - #if !defined(_WIN32) /** Defined iff we need to add locks when defining fake versions of reentrant * versions of time-related functions. */ @@ -2975,11 +2906,12 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, /* If we get here, then gmtime/localtime failed without getting an extreme * value for *timep */ - + /* LCOV_EXCL_START */ tor_fragile_assert(); r = resultbuf; memset(resultbuf, 0, sizeof(struct tm)); outcome="can't recover"; + /* LCOV_EXCL_STOP */ done: log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s", islocal?"localtime":"gmtime", @@ -3373,9 +3305,11 @@ get_total_system_memory_impl(void) return result * 1024; err: + /* LCOV_EXCL_START Can't reach this unless proc is broken. */ tor_free(s); close(fd); return 0; + /* LCOV_EXCL_STOP */ #elif defined (_WIN32) /* Windows has MEMORYSTATUSEX; pretty straightforward. */ MEMORYSTATUSEX ms; @@ -3424,6 +3358,7 @@ get_total_system_memory(size_t *mem_out) static size_t mem_cached=0; uint64_t m = get_total_system_memory_impl(); if (0 == m) { + /* LCOV_EXCL_START -- can't make this happen without mocking. */ /* We couldn't find our memory total */ if (0 == mem_cached) { /* We have no cached value either */ @@ -3433,6 +3368,7 @@ get_total_system_memory(size_t *mem_out) *mem_out = mem_cached; return 0; + /* LCOV_EXCL_STOP */ } #if SIZE_MAX != UINT64_MAX @@ -3449,26 +3385,6 @@ get_total_system_memory(size_t *mem_out) return 0; } -#ifdef TOR_UNIT_TESTS -/** Delay for <b>msec</b> milliseconds. Only used in tests. */ -void -tor_sleep_msec(int msec) -{ -#ifdef _WIN32 - Sleep(msec); -#elif defined(HAVE_USLEEP) - sleep(msec / 1000); - /* Some usleep()s hate sleeping more than 1 sec */ - usleep((msec % 1000) * 1000); -#elif defined(HAVE_SYS_SELECT_H) - struct timeval tv = { msec / 1000, (msec % 1000) * 1000}; - select(0, NULL, NULL, NULL, &tv); -#else - sleep(CEIL_DIV(msec, 1000)); -#endif -} -#endif - /** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> * bytes of passphrase into <b>output</b>. Return the number of bytes in * the passphrase, excluding terminating NUL. diff --git a/src/common/compat.h b/src/common/compat.h index 8cf84580c6..ee1c9454de 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -42,6 +42,8 @@ #include <netinet6/in6.h> #endif +#include "compat_time.h" + #if defined(__has_feature) # if __has_feature(address_sanitizer) /* Some of the fancy glibc strcmp() macros include references to memory that @@ -82,6 +84,44 @@ #define CHECK_SCANF(formatIdx, firstArg) #endif +/* What GCC do we have? */ +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +#define GCC_VERSION 0 +#endif + +/* Temporarily enable and disable warnings. */ +#ifdef __GNUC__ +# define PRAGMA_STRINGIFY_(s) #s +# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b) +/* Support for macro-generated pragmas (c99) */ +# define PRAGMA_(x) _Pragma (#x) +# ifdef __clang__ +# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(clang diagnostic x) +# else +# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(GCC diagnostic x) +# endif +# if defined(__clang__) || GCC_VERSION >= 406 +/* we have push/pop support */ +# define DISABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(push) \ + PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# define ENABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(pop) +# else +/* older version of gcc: no push/pop support. */ +# define DISABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# define ENABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# endif +#else /* ifdef __GNUC__ */ +/* not gcc at all */ +# define DISABLE_GCC_WARNING(warning) +# define ENABLE_GCC_WARNING(warning) +#endif + /* inline is __inline on windows. */ #ifdef _WIN32 #define inline __inline @@ -320,8 +360,8 @@ DECLARE_CTYPE_FN(ISXDIGIT) DECLARE_CTYPE_FN(ISPRINT) DECLARE_CTYPE_FN(ISLOWER) DECLARE_CTYPE_FN(ISUPPER) -extern const char TOR_TOUPPER_TABLE[]; -extern const char TOR_TOLOWER_TABLE[]; +extern const uint8_t TOR_TOUPPER_TABLE[]; +extern const uint8_t TOR_TOLOWER_TABLE[]; #define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c]) #define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c]) @@ -341,15 +381,6 @@ const char *tor_fix_source_file(const char *fname); #endif /* ===== Time compatibility */ -#if !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) -/** Implementation of timeval for platforms that don't have it. */ -struct timeval { - time_t tv_sec; - unsigned int tv_usec; -}; -#endif - -void tor_gettimeofday(struct timeval *timeval); struct tm *tor_localtime_r(const time_t *timep, struct tm *result); struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); @@ -430,7 +461,7 @@ typedef int socklen_t; #ifdef _WIN32 /* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that - * any inadvertant checks for the socket being <= 0 or > 0 will probably + * any inadvertent checks for the socket being <= 0 or > 0 will probably * still work. */ #define tor_socket_t intptr_t #define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT @@ -447,7 +478,7 @@ typedef int socklen_t; #endif int tor_close_socket_simple(tor_socket_t s); -int tor_close_socket(tor_socket_t s); +MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); tor_socket_t tor_open_socket_with_extensions( int domain, int type, int protocol, int cloexec, int nonblock); @@ -699,10 +730,6 @@ char *format_win32_error(DWORD err); #endif -#ifdef TOR_UNIT_TESTS -void tor_sleep_msec(int msec); -#endif - #ifdef COMPAT_PRIVATE #if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS) #define NEED_ERSATZ_SOCKETPAIR diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c index cc58883750..4a3b1af922 100644 --- a/src/common/compat_libevent.c +++ b/src/common/compat_libevent.c @@ -3,11 +3,8 @@ /** * \file compat_libevent.c - * \brief Wrappers to handle porting between different versions of libevent. - * - * In an ideal world, we'd just use Libevent 2.0 from now on. But as of June - * 2012, Libevent 1.4 is still all over, and some poor souls are stuck on - * Libevent 1.3e. */ + * \brief Wrappers and utility functions for Libevent. + */ #include "orconfig.h" #include "compat.h" @@ -19,15 +16,8 @@ #include "util.h" #include "torlog.h" -#ifdef HAVE_EVENT2_EVENT_H #include <event2/event.h> #include <event2/thread.h> -#ifdef USE_BUFFEREVENTS -#include <event2/bufferevent.h> -#endif -#else -#include <event.h> -#endif /** A string which, if it appears in a libevent log, should be ignored. */ static const char *suppress_msg = NULL; @@ -69,6 +59,7 @@ configure_libevent_logging(void) { event_set_log_callback(libevent_logging_callback); } + /** Ignore any libevent log message that contains <b>msg</b>. */ void suppress_libevent_log_msg(const char *msg) @@ -76,44 +67,6 @@ suppress_libevent_log_msg(const char *msg) suppress_msg = msg; } -#ifndef HAVE_EVENT2_EVENT_H -/** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */ -struct event * -tor_event_new(struct event_base *base, int sock, short what, - void (*cb)(int, short, void *), void *arg) -{ - struct event *e = tor_malloc_zero(sizeof(struct event)); - event_set(e, sock, what, cb, arg); - if (! base) - base = tor_libevent_get_base(); - event_base_set(base, e); - return e; -} -/** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */ -struct event * -tor_evtimer_new(struct event_base *base, - void (*cb)(int, short, void *), void *arg) -{ - return tor_event_new(base, -1, 0, cb, arg); -} -/** Work-alike replacement for evsignal_new() on pre-Libevent-2.0 systems. */ -struct event * -tor_evsignal_new(struct event_base * base, int sig, - void (*cb)(int, short, void *), void *arg) -{ - return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg); -} -/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems, - * except tolerate tor_event_free(NULL). */ -void -tor_event_free(struct event *ev) -{ - if (ev == NULL) - return; - event_del(ev); - tor_free(ev); -} -#else /* Wrapper for event_free() that tolerates tor_event_free(NULL) */ void tor_event_free(struct event *ev) @@ -122,10 +75,9 @@ tor_event_free(struct event *ev) return; event_free(ev); } -#endif /** Global event base for use by the main thread. */ -struct event_base *the_event_base = NULL; +static struct event_base *the_event_base = NULL; /* This is what passes for version detection on OSX. We set * MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before @@ -139,17 +91,6 @@ struct event_base *the_event_base = NULL; #endif #endif -#ifdef USE_BUFFEREVENTS -static int using_iocp_bufferevents = 0; -static void tor_libevent_set_tick_timeout(int msec_per_tick); - -int -tor_libevent_using_iocp_bufferevents(void) -{ - return using_iocp_bufferevents; -} -#endif - /** Initialize the Libevent library and set up the event base. */ void tor_libevent_initialize(tor_libevent_cfg *torcfg) @@ -158,89 +99,40 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg) /* some paths below don't use torcfg, so avoid unused variable warnings */ (void)torcfg; -#ifdef HAVE_EVENT2_EVENT_H { int attempts = 0; - int using_threads; struct event_config *cfg; - retry: ++attempts; - using_threads = 0; cfg = event_config_new(); tor_assert(cfg); -#if defined(_WIN32) && defined(USE_BUFFEREVENTS) - if (! torcfg->disable_iocp) { - evthread_use_windows_threads(); - event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP); - using_iocp_bufferevents = 1; - using_threads = 1; - } else { - using_iocp_bufferevents = 0; - } -#elif defined(__COVERITY__) - /* Avoid a 'dead code' warning below. */ - using_threads = ! torcfg->disable_iocp; -#endif + /* Telling Libevent not to try to turn locking on can avoid a needless + * socketpair() attempt. */ + event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK); - if (!using_threads) { - /* Telling Libevent not to try to turn locking on can avoid a needless - * socketpair() attempt. */ - event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK); - } - -#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7) if (torcfg->num_cpus > 0) event_config_set_num_cpus_hint(cfg, torcfg->num_cpus); -#endif -#if LIBEVENT_VERSION_NUMBER >= V(2,0,9) /* We can enable changelist support with epoll, since we don't give * Libevent any dup'd fds. This lets us avoid some syscalls. */ event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST); -#endif the_event_base = event_base_new_with_config(cfg); event_config_free(cfg); - - if (using_threads && the_event_base == NULL && attempts < 2) { - /* This could be a socketpair() failure, which can happen sometimes on - * windows boxes with obnoxious firewall rules. Downgrade and try - * again. */ -#if defined(_WIN32) && defined(USE_BUFFEREVENTS) - if (torcfg->disable_iocp == 0) { - log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again " - "with IOCP disabled."); - } else -#endif - { - log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again."); - } - - torcfg->disable_iocp = 1; - goto retry; - } } -#else - the_event_base = event_init(); -#endif if (!the_event_base) { + /* LCOV_EXCL_START */ log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue."); exit(1); + /* LCOV_EXCL_STOP */ } - /* Making this a NOTICE for now so we can link bugs to a libevent versions - * or methods better. */ log_info(LD_GENERAL, "Initialized libevent version %s using method %s. Good.", event_get_version(), tor_libevent_get_method()); - -#ifdef USE_BUFFEREVENTS - tor_libevent_set_tick_timeout(torcfg->msec_per_tick); -#endif } /** Return the current Libevent event base that we're set up to use. */ @@ -255,62 +147,7 @@ tor_libevent_get_base, (void)) const char * tor_libevent_get_method(void) { -#ifdef HAVE_EVENT2_EVENT_H return event_base_get_method(the_event_base); -#else - return event_get_method(); -#endif -} - -/** Return the le_version_t for the version of libevent specified in the - * string <b>v</b>. If the version is very new or uses an unrecognized - * version, format, return LE_OTHER. */ -STATIC le_version_t -tor_decode_libevent_version(const char *v) -{ - unsigned major, minor, patchlevel; - char c, e, extra; - int fields; - - /* Try the new preferred "1.4.11-stable" format. - * Also accept "1.4.14b-stable". */ - fields = tor_sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e); - if (fields == 3 || - ((fields == 4 || fields == 5 ) && (c == '-' || c == '_')) || - (fields == 5 && TOR_ISALPHA(c) && (e == '-' || e == '_'))) { - return V(major,minor,patchlevel); - } - - /* Try the old "1.3e" format. */ - fields = tor_sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra); - if (fields == 3 && TOR_ISALPHA(c)) { - return V_OLD(major, minor, c); - } else if (fields == 2) { - return V(major, minor, 0); - } - - return LE_OTHER; -} - -/** Return an integer representing the binary interface of a Libevent library. - * Two different versions with different numbers are sure not to be binary - * compatible. Two different versions with the same numbers have a decent - * chance of binary compatibility.*/ -STATIC int -le_versions_compatibility(le_version_t v) -{ - if (v == LE_OTHER) - return 0; - if (v < V_OLD(1,0,'c')) - return 1; - else if (v < V(1,4,0)) - return 2; - else if (v < V(1,4,99)) - return 3; - else if (v < V(2,0,1)) - return 4; - else /* Everything 2.0 and later should be compatible. */ - return 5; } /** Return a string representation of the version of the currently running @@ -321,101 +158,14 @@ tor_libevent_get_version_str(void) return event_get_version(); } -#if defined(LIBEVENT_VERSION) -#define HEADER_VERSION LIBEVENT_VERSION -#elif defined(_EVENT_VERSION) -#define HEADER_VERSION _EVENT_VERSION -#endif - /** Return a string representation of the version of Libevent that was used * at compilation time. */ const char * tor_libevent_get_header_version_str(void) { - return HEADER_VERSION; -} - -/** See whether the headers we were built against differ from the library we - * linked against so much that we're likely to crash. If so, warn the - * user. */ -void -tor_check_libevent_header_compatibility(void) -{ - (void) le_versions_compatibility; - (void) tor_decode_libevent_version; - - /* In libevent versions before 2.0, it's hard to keep binary compatibility - * between upgrades, and unpleasant to detect when the version we compiled - * against is unlike the version we have linked against. Here's how. */ -#if defined(HEADER_VERSION) - /* We have a header-file version and a function-call version. Easy. */ - if (strcmp(HEADER_VERSION, event_get_version())) { - le_version_t v1, v2; - int compat1 = -1, compat2 = -1; - int verybad; - v1 = tor_decode_libevent_version(HEADER_VERSION); - v2 = tor_decode_libevent_version(event_get_version()); - compat1 = le_versions_compatibility(v1); - compat2 = le_versions_compatibility(v2); - - verybad = compat1 != compat2; - - tor_log(verybad ? LOG_WARN : LOG_NOTICE, - LD_GENERAL, "We were compiled with headers from version %s " - "of Libevent, but we're using a Libevent library that says it's " - "version %s.", HEADER_VERSION, event_get_version()); - if (verybad) - log_warn(LD_GENERAL, "This will almost certainly make Tor crash."); - else - log_info(LD_GENERAL, "I think these versions are binary-compatible."); - } -#else - /* event_get_version but no _EVENT_VERSION. We might be in 1.4.0-beta or - earlier, where that's normal. To see whether we were compiled with an - earlier version, let's see whether the struct event defines MIN_HEAP_IDX. - */ -#ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX - /* The header files are 1.4.0-beta or later. If the version is not - * 1.4.0-beta, we are incompatible. */ - { - if (strcmp(event_get_version(), "1.4.0-beta")) { - log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have " - "Libevent 1.4.0-beta header files, whereas you have linked " - "against Libevent %s. This will probably make Tor crash.", - event_get_version()); - } - } -#else - /* Our headers are 1.3e or earlier. If the library version is not 1.4.x or - later, we're probably fine. */ - { - const char *v = event_get_version(); - if ((v[0] == '1' && v[2] == '.' && v[3] > '3') || v[0] > '1') { - log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have " - "Libevent header file from 1.3e or earlier, whereas you have " - "linked against Libevent %s. This will probably make Tor " - "crash.", event_get_version()); - } - } -#endif - - /* Your libevent is ancient. */ -#endif + return LIBEVENT_VERSION; } -/* - If possible, we're going to try to use Libevent's periodic timer support, - since it does a pretty good job of making sure that periodic events get - called exactly M seconds apart, rather than starting each one exactly M - seconds after the time that the last one was run. - */ -#ifdef HAVE_EVENT2_EVENT_H -#define HAVE_PERIODIC -#define PERIODIC_FLAGS EV_PERSIST -#else -#define PERIODIC_FLAGS 0 -#endif - /** Represents a timer that's run every N microseconds by Libevent. */ struct periodic_timer_t { /** Underlying event used to implement this periodic event. */ @@ -424,11 +174,6 @@ struct periodic_timer_t { void (*cb)(struct periodic_timer_t *, void *); /** User-supplied data for the callback */ void *data; -#ifndef HAVE_PERIODIC - /** If Libevent doesn't know how to invoke events every N microseconds, - * we'll need to remember the timeout interval here. */ - struct timeval tv; -#endif }; /** Libevent callback to implement a periodic event. */ @@ -438,10 +183,6 @@ periodic_timer_cb(evutil_socket_t fd, short what, void *arg) periodic_timer_t *timer = arg; (void) what; (void) fd; -#ifndef HAVE_PERIODIC - /** reschedule the event as needed. */ - event_add(timer->ev, &timer->tv); -#endif timer->cb(timer, timer->data); } @@ -459,16 +200,13 @@ periodic_timer_new(struct event_base *base, tor_assert(tv); tor_assert(cb); timer = tor_malloc_zero(sizeof(periodic_timer_t)); - if (!(timer->ev = tor_event_new(base, -1, PERIODIC_FLAGS, + if (!(timer->ev = tor_event_new(base, -1, EV_PERSIST, periodic_timer_cb, timer))) { tor_free(timer); return NULL; } timer->cb = cb; timer->data = data; -#ifndef HAVE_PERIODIC - memcpy(&timer->tv, tv, sizeof(struct timeval)); -#endif event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/ return timer; } @@ -483,72 +221,19 @@ periodic_timer_free(periodic_timer_t *timer) tor_free(timer); } -#ifdef USE_BUFFEREVENTS -static const struct timeval *one_tick = NULL; -/** - * Return a special timeout to be passed whenever libevent's O(1) timeout - * implementation should be used. Only use this when the timer is supposed - * to fire after msec_per_tick ticks have elapsed. -*/ -const struct timeval * -tor_libevent_get_one_tick_timeout(void) -{ - tor_assert(one_tick); - return one_tick; -} - -/** Initialize the common timeout that we'll use to refill the buckets every - * time a tick elapses. */ -static void -tor_libevent_set_tick_timeout(int msec_per_tick) -{ - struct event_base *base = tor_libevent_get_base(); - struct timeval tv; - - tor_assert(! one_tick); - tv.tv_sec = msec_per_tick / 1000; - tv.tv_usec = (msec_per_tick % 1000) * 1000; - one_tick = event_base_init_common_timeout(base, &tv); -} - -static struct bufferevent * -tor_get_root_bufferevent(struct bufferevent *bev) -{ - struct bufferevent *u; - while ((u = bufferevent_get_underlying(bev)) != NULL) - bev = u; - return bev; -} - -int -tor_set_bufferevent_rate_limit(struct bufferevent *bev, - struct ev_token_bucket_cfg *cfg) -{ - return bufferevent_set_rate_limit(tor_get_root_bufferevent(bev), cfg); -} - -int -tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev, - struct bufferevent_rate_limit_group *g) -{ - return bufferevent_add_to_rate_limit_group(tor_get_root_bufferevent(bev), g); -} -#endif - int tor_init_libevent_rng(void) { int rv = 0; -#ifdef HAVE_EVUTIL_SECURE_RNG_INIT char buf[256]; if (evutil_secure_rng_init() < 0) { rv = -1; } - /* Older libevent -- manually initialize the RNG */ crypto_rand(buf, 32); +#ifdef HAVE_EVUTIL_SECURE_RNG_ADD_BYTES evutil_secure_rng_add_bytes(buf, 32); - evutil_secure_rng_get_bytes(buf, sizeof(buf)); #endif + evutil_secure_rng_get_bytes(buf, sizeof(buf)); return rv; } @@ -598,33 +283,3 @@ tor_gettimeofday_cache_set(const struct timeval *tv) #endif #endif -/** - * As tor_gettimeofday_cached, but can never move backwards in time. - * - * The returned value may diverge from wall-clock time, since wall-clock time - * can trivially be adjusted backwards, and this can't. Don't mix wall-clock - * time with these values in the same calculation. - * - * Depending on implementation, this function may or may not "smooth out" huge - * jumps forward in wall-clock time. It may or may not keep its results - * advancing forward (as opposed to stalling) if the wall-clock time goes - * backwards. The current implementation does neither of of these. - * - * This function is not thread-safe; do not call it outside the main thread. - * - * In future versions of Tor, this may return a time does not have its - * origin at the Unix epoch. - */ -void -tor_gettimeofday_cached_monotonic(struct timeval *tv) -{ - struct timeval last_tv = { 0, 0 }; - - tor_gettimeofday_cached(tv); - if (timercmp(tv, &last_tv, OP_LT)) { - memcpy(tv, &last_tv, sizeof(struct timeval)); - } else { - memcpy(&last_tv, tv, sizeof(struct timeval)); - } -} - diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h index 4b8b300112..c2e34764e4 100644 --- a/src/common/compat_libevent.h +++ b/src/common/compat_libevent.h @@ -7,40 +7,17 @@ #include "orconfig.h" #include "testsupport.h" -struct event; -struct event_base; -#ifdef USE_BUFFEREVENTS -struct bufferevent; -struct ev_token_bucket_cfg; -struct bufferevent_rate_limit_group; -#endif - -#ifdef HAVE_EVENT2_EVENT_H -#include <event2/util.h> -#elif !defined(EVUTIL_SOCKET_DEFINED) -#define EVUTIL_SOCKET_DEFINED -#define evutil_socket_t int -#endif +#include <event2/event.h> void configure_libevent_logging(void); void suppress_libevent_log_msg(const char *msg); -#ifdef HAVE_EVENT2_EVENT_H #define tor_event_new event_new #define tor_evtimer_new evtimer_new #define tor_evsignal_new evsignal_new #define tor_evdns_add_server_port(sock, tcp, cb, data) \ evdns_add_server_port_with_base(tor_libevent_get_base(), \ (sock),(tcp),(cb),(data)); -#else -struct event *tor_event_new(struct event_base * base, evutil_socket_t sock, - short what, void (*cb)(evutil_socket_t, short, void *), void *arg); -struct event *tor_evtimer_new(struct event_base * base, - void (*cb)(evutil_socket_t, short, void *), void *arg); -struct event *tor_evsignal_new(struct event_base * base, int sig, - void (*cb)(evutil_socket_t, short, void *), void *arg); -#define tor_evdns_add_server_port evdns_add_server_port -#endif void tor_event_free(struct event *ev); @@ -57,12 +34,10 @@ void periodic_timer_free(periodic_timer_t *); /** Defines a configuration for using libevent with Tor: passed as an argument * to tor_libevent_initialize() to describe how we want to set up. */ typedef struct tor_libevent_cfg { - /** Flag: if true, disable IOCP (assuming that it could be enabled). */ - int disable_iocp; - /** How many CPUs should we use (relevant only with IOCP). */ + /** How many CPUs should we use (not currently useful). */ int num_cpus; /** How many milliseconds should we allow between updating bandwidth limits? - * (relevant only with bufferevents). */ + * (Not currently useful). */ int msec_per_tick; } tor_libevent_cfg; @@ -73,15 +48,6 @@ void tor_check_libevent_header_compatibility(void); const char *tor_libevent_get_version_str(void); const char *tor_libevent_get_header_version_str(void); -#ifdef USE_BUFFEREVENTS -const struct timeval *tor_libevent_get_one_tick_timeout(void); -int tor_libevent_using_iocp_bufferevents(void); -int tor_set_bufferevent_rate_limit(struct bufferevent *bev, - struct ev_token_bucket_cfg *cfg); -int tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev, - struct bufferevent_rate_limit_group *g); -#endif - int tor_init_libevent_rng(void); void tor_gettimeofday_cached(struct timeval *tv); @@ -89,43 +55,20 @@ void tor_gettimeofday_cache_clear(void); #ifdef TOR_UNIT_TESTS void tor_gettimeofday_cache_set(const struct timeval *tv); #endif -void tor_gettimeofday_cached_monotonic(struct timeval *tv); #ifdef COMPAT_LIBEVENT_PRIVATE -/** A number representing a version of Libevent. - This is a 4-byte number, with the first three bytes representing the - major, minor, and patchlevel respectively of the library. The fourth - byte is unused. +/** Macro: returns the number of a Libevent version as a 4-byte number, + with the first three bytes representing the major, minor, and patchlevel + respectively of the library. The fourth byte is unused. This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent - 2.0.1 or later. For versions of Libevent before 1.4.0, which followed the - format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a - to be equivalent to 1.0.1, and so on. -*/ -typedef uint32_t le_version_t; - -/** @{ */ -/** Macros: returns the number of a libevent version as a le_version_t */ + 2.0.1 or later. */ #define V(major, minor, patch) \ (((major) << 24) | ((minor) << 16) | ((patch) << 8)) -#define V_OLD(major, minor, patch) \ - V((major), (minor), (patch)-'a'+1) -/** @} */ - -/** Represetns a version of libevent so old we can't figure out what version - * it is. */ -#define LE_OLD V(0,0,0) -/** Represents a version of libevent so weird we can't figure out what version - * it is. */ -#define LE_OTHER V(0,0,99) STATIC void libevent_logging_callback(int severity, const char *msg); -STATIC le_version_t -tor_decode_libevent_version(const char *v); -STATIC int -le_versions_compatibility(le_version_t v); #endif #endif diff --git a/src/common/compat_openssl.h b/src/common/compat_openssl.h index a7bdb0a224..1bfe188075 100644 --- a/src/common/compat_openssl.h +++ b/src/common/compat_openssl.h @@ -15,8 +15,9 @@ * \brief compatability definitions for working with different openssl forks **/ -#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) -#error "We require OpenSSL >= 1.0.0" +#if !defined(LIBRESSL_VERSION_NUMBER) && \ + OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1) +#error "We require OpenSSL >= 1.0.1" #endif #if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && \ diff --git a/src/common/compat_pthreads.c b/src/common/compat_pthreads.c index 962b5fc0e4..c1ae66c1d2 100644 --- a/src/common/compat_pthreads.c +++ b/src/common/compat_pthreads.c @@ -10,8 +10,6 @@ * functions. */ -#define _GNU_SOURCE - #include "orconfig.h" #include <pthread.h> #include <signal.h> @@ -21,11 +19,6 @@ #include "torlog.h" #include "util.h" -#ifdef __APPLE__ -#undef CLOCK_MONOTONIC -#undef HAVE_CLOCK_GETTIME -#endif - /** Wraps a void (*)(void*) function and its argument so we can * invoke them in a way pthreads would expect. */ @@ -109,11 +102,13 @@ void tor_mutex_init(tor_mutex_t *mutex) { if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); + tor_threads_init(); // LCOV_EXCL_LINE const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_fragile_assert(); + tor_assert_unreached(); + // LCOV_EXCL_STOP } } @@ -123,12 +118,14 @@ void tor_mutex_init_nonrecursive(tor_mutex_t *mutex) { int err; - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); + if (!threads_initialized) + tor_threads_init(); // LCOV_EXCL_LINE err = pthread_mutex_init(&mutex->mutex, NULL); if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_fragile_assert(); + tor_assert_unreached(); + // LCOV_EXCL_STOP } } @@ -140,8 +137,10 @@ tor_mutex_acquire(tor_mutex_t *m) tor_assert(m); err = pthread_mutex_lock(&m->mutex); if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START log_err(LD_GENERAL, "Error %d locking a mutex.", err); - tor_fragile_assert(); + tor_assert_unreached(); + // LCOV_EXCL_STOP } } /** Release the lock <b>m</b> so another thread can have it. */ @@ -152,8 +151,10 @@ tor_mutex_release(tor_mutex_t *m) tor_assert(m); err = pthread_mutex_unlock(&m->mutex); if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START log_err(LD_GENERAL, "Error %d unlocking a mutex.", err); - tor_fragile_assert(); + tor_assert_unreached(); + // LCOV_EXCL_STOP } } /** Clean up the mutex <b>m</b> so that it no longer uses any system @@ -166,8 +167,10 @@ tor_mutex_uninit(tor_mutex_t *m) tor_assert(m); err = pthread_mutex_destroy(&m->mutex); if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START log_err(LD_GENERAL, "Error %d destroying a mutex.", err); - tor_fragile_assert(); + tor_assert_unreached(); + // LCOV_EXCL_STOP } } /** Return an integer representing this thread. */ @@ -197,14 +200,21 @@ tor_cond_init(tor_cond_t *cond) return -1; } -#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) \ - && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) +#if defined(HAVE_CLOCK_GETTIME) +#if defined(CLOCK_MONOTONIC) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) /* Use monotonic time so when we timedwait() on it, any clock adjustment * won't affect the timeout value. */ if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) { return -1; } -#endif +#define USE_COND_CLOCK CLOCK_MONOTONIC +#else /* !defined HAVE_PTHREAD_CONDATTR_SETCLOCK */ + /* On OSX Sierra, there is no pthread_condattr_setclock, so we are stuck + * with the realtime clock. + */ +#define USE_COND_CLOCK CLOCK_REALTIME +#endif /* which clock to use */ +#endif /* HAVE_CLOCK_GETTIME */ if (pthread_cond_init(&cond->cond, &condattr)) { return -1; } @@ -217,8 +227,10 @@ void tor_cond_uninit(tor_cond_t *cond) { if (pthread_cond_destroy(&cond->cond)) { + // LCOV_EXCL_START log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno)); return; + // LCOV_EXCL_STOP } } /** Wait until one of the tor_cond_signal functions is called on <b>cond</b>. @@ -239,7 +251,7 @@ tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv) /* EINTR should be impossible according to POSIX, but POSIX, like the * Pirate's Code, is apparently treated "more like what you'd call * guidelines than actual rules." */ - continue; + continue; // LCOV_EXCL_LINE } return r ? -1 : 0; } @@ -247,12 +259,12 @@ tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv) struct timeval tvnow, tvsum; struct timespec ts; while (1) { -#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) - if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { +#if defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK) + if (clock_gettime(USE_COND_CLOCK, &ts) < 0) { return -1; } tvnow.tv_sec = ts.tv_sec; - tvnow.tv_usec = ts.tv_nsec / 1000; + tvnow.tv_usec = (int)(ts.tv_nsec / 1000); timeradd(tv, &tvnow, &tvsum); #else if (gettimeofday(&tvnow, NULL) < 0) diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c index 8f9001258a..f4809060d6 100644 --- a/src/common/compat_threads.c +++ b/src/common/compat_threads.c @@ -11,8 +11,6 @@ * modules.) */ -#define _GNU_SOURCE - #include "orconfig.h" #include <stdlib.h> #include "compat.h" @@ -63,8 +61,8 @@ tor_cond_t * tor_cond_new(void) { tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t)); - if (tor_cond_init(cond)<0) - tor_free(cond); + if (BUG(tor_cond_init(cond)<0)) + tor_free(cond); // LCOV_EXCL_LINE return cond; } @@ -242,8 +240,11 @@ alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags) if (socks[0] >= 0) { if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 || set_socket_nonblocking(socks[0]) < 0) { + // LCOV_EXCL_START -- if eventfd succeeds, fcntl will. + tor_assert_nonfatal_unreached(); close(socks[0]); return -1; + // LCOV_EXCL_STOP } } } @@ -277,9 +278,12 @@ alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags) fcntl(socks[1], F_SETFD, FD_CLOEXEC) < 0 || set_socket_nonblocking(socks[0]) < 0 || set_socket_nonblocking(socks[1]) < 0) { + // LCOV_EXCL_START -- if pipe succeeds, you can fcntl the output + tor_assert_nonfatal_unreached(); close(socks[0]); close(socks[1]); return -1; + // LCOV_EXCL_STOP } socks_out->read_fd = socks[0]; socks_out->write_fd = socks[1]; @@ -294,9 +298,12 @@ alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags) tor_socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == 0) { if (set_socket_nonblocking(socks[0]) < 0 || set_socket_nonblocking(socks[1])) { + // LCOV_EXCL_START -- if socketpair worked, you can make it nonblocking. + tor_assert_nonfatal_unreached(); tor_close_socket(socks[0]); tor_close_socket(socks[1]); return -1; + // LCOV_EXCL_STOP } socks_out->read_fd = socks[0]; socks_out->write_fd = socks[1]; diff --git a/src/common/compat_time.c b/src/common/compat_time.c new file mode 100644 index 0000000000..d044bbe1d7 --- /dev/null +++ b/src/common/compat_time.c @@ -0,0 +1,657 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.c + * \brief Portable wrappers for finding out the current time, running + * timers, etc. + **/ + +#define COMPAT_TIME_PRIVATE +#include "compat.h" + +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef TOR_UNIT_TESTS +#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H) +/* as fallback implementation for tor_sleep_msec */ +#include <sys/select.h> +#endif +#endif + +#ifdef __APPLE__ +#include <mach/mach_time.h> +#endif + +#include "torlog.h" +#include "util.h" +#include "container.h" + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_FTIME +#include <sys/timeb.h> +#endif +#endif + +#ifdef _WIN32 +#undef HAVE_CLOCK_GETTIME +#endif + +#ifdef TOR_UNIT_TESTS +/** Delay for <b>msec</b> milliseconds. Only used in tests. */ +void +tor_sleep_msec(int msec) +{ +#ifdef _WIN32 + Sleep(msec); +#elif defined(HAVE_USLEEP) + sleep(msec / 1000); + /* Some usleep()s hate sleeping more than 1 sec */ + usleep((msec % 1000) * 1000); +#elif defined(HAVE_SYS_SELECT_H) + struct timeval tv = { msec / 1000, (msec % 1000) * 1000}; + select(0, NULL, NULL, NULL, &tv); +#else + sleep(CEIL_DIV(msec, 1000)); +#endif +} +#endif + +/** Set *timeval to the current time of day. On error, log and terminate. + * (Same as gettimeofday(timeval,NULL), but never returns -1.) + */ +void +tor_gettimeofday(struct timeval *timeval) +{ +#ifdef _WIN32 + /* Epoch bias copied from perl: number of units between windows epoch and + * Unix epoch. */ +#define EPOCH_BIAS U64_LITERAL(116444736000000000) +#define UNITS_PER_SEC U64_LITERAL(10000000) +#define USEC_PER_SEC U64_LITERAL(1000000) +#define UNITS_PER_USEC U64_LITERAL(10) + union { + uint64_t ft_64; + FILETIME ft_ft; + } ft; + /* number of 100-nsec units since Jan 1, 1601 */ + GetSystemTimeAsFileTime(&ft.ft_ft); + if (ft.ft_64 < EPOCH_BIAS) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"System time is before 1970; failing."); + exit(1); + /* LCOV_EXCL_STOP */ + } + ft.ft_64 -= EPOCH_BIAS; + timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); + timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); +#elif defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(timeval, NULL)) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"gettimeofday failed."); + /* If gettimeofday dies, we have either given a bad timezone (we didn't), + or segfaulted.*/ + exit(1); + /* LCOV_EXCL_STOP */ + } +#elif defined(HAVE_FTIME) + struct timeb tb; + ftime(&tb); + timeval->tv_sec = tb.time; + timeval->tv_usec = tb.millitm * 1000; +#else +#error "No way to get time." +#endif + return; +} + +#define ONE_MILLION ((int64_t) (1000 * 1000)) +#define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) + +/** True iff monotime_init has been called. */ +static int monotime_initialized = 0; + +static monotime_t initialized_at; +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +static monotime_coarse_t initialized_at_coarse; +#endif + +#ifdef TOR_UNIT_TESTS +/** True if we are running unit tests and overriding the current monotonic + * time. Note that mocked monotonic time might not be monotonic. + */ +static int monotime_mocking_enabled = 0; +static monotime_t initialized_at_saved; + +static int64_t mock_time_nsec = 0; +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +static int64_t mock_time_nsec_coarse = 0; +static monotime_coarse_t initialized_at_coarse_saved; +#endif + +void +monotime_enable_test_mocking(void) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + tor_assert_nonfatal(monotime_mocking_enabled == 0); + monotime_mocking_enabled = 1; + memcpy(&initialized_at_saved, + &initialized_at, sizeof(monotime_t)); + memset(&initialized_at, 0, sizeof(monotime_t)); +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT + memcpy(&initialized_at_coarse_saved, + &initialized_at_coarse, sizeof(monotime_coarse_t)); + memset(&initialized_at_coarse, 0, sizeof(monotime_coarse_t)); +#endif +} + +void +monotime_disable_test_mocking(void) +{ + tor_assert_nonfatal(monotime_mocking_enabled == 1); + monotime_mocking_enabled = 0; + + memcpy(&initialized_at, + &initialized_at_saved, sizeof(monotime_t)); +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT + memcpy(&initialized_at_coarse, + &initialized_at_coarse_saved, sizeof(monotime_coarse_t)); +#endif +} + +void +monotime_set_mock_time_nsec(int64_t nsec) +{ + tor_assert_nonfatal(monotime_mocking_enabled == 1); + mock_time_nsec = nsec; +} + +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +void +monotime_coarse_set_mock_time_nsec(int64_t nsec) +{ + tor_assert_nonfatal(monotime_mocking_enabled == 1); + mock_time_nsec_coarse = nsec; +} +#endif +#endif + +/* "ratchet" functions for monotonic time. */ + +#if defined(_WIN32) || defined(TOR_UNIT_TESTS) + +/** Protected by lock: last value returned by monotime_get(). */ +static int64_t last_pctr = 0; +/** Protected by lock: offset we must add to monotonic time values. */ +static int64_t pctr_offset = 0; +/* If we are using GetTickCount(), how many times has it rolled over? */ +static uint32_t rollover_count = 0; +/* If we are using GetTickCount(), what's the last value it returned? */ +static int64_t last_tick_count = 0; + +/** Helper for windows: Called with a sequence of times that are supposed + * to be monotonic; increments them as appropriate so that they actually + * _are_ monotonic. + * + * Caller must hold lock. */ +STATIC int64_t +ratchet_performance_counter(int64_t count_raw) +{ + /* must hold lock */ + const int64_t count_adjusted = count_raw + pctr_offset; + + if (PREDICT_UNLIKELY(count_adjusted < last_pctr)) { + /* Monotonicity failed! Pretend no time elapsed. */ + pctr_offset = last_pctr - count_raw; + return last_pctr; + } else { + last_pctr = count_adjusted; + return count_adjusted; + } +} + +STATIC int64_t +ratchet_coarse_performance_counter(const int64_t count_raw) +{ + int64_t count = count_raw + (((int64_t)rollover_count) << 32); + while (PREDICT_UNLIKELY(count < last_tick_count)) { + ++rollover_count; + count = count_raw + (((int64_t)rollover_count) << 32); + } + last_tick_count = count; + return count; +} +#endif + +#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) +static struct timeval last_timeofday = { 0, 0 }; +static struct timeval timeofday_offset = { 0, 0 }; + +/** Helper for gettimeofday(): Called with a sequence of times that are + * supposed to be monotonic; increments them as appropriate so that they + * actually _are_ monotonic. + * + * Caller must hold lock. */ +STATIC void +ratchet_timeval(const struct timeval *timeval_raw, struct timeval *out) +{ + /* must hold lock */ + timeradd(timeval_raw, &timeofday_offset, out); + if (PREDICT_UNLIKELY(timercmp(out, &last_timeofday, <))) { + /* time ran backwards. Instead, declare that no time occurred. */ + timersub(&last_timeofday, timeval_raw, &timeofday_offset); + memcpy(out, &last_timeofday, sizeof(struct timeval)); + } else { + memcpy(&last_timeofday, out, sizeof(struct timeval)); + } +} +#endif + +#ifdef TOR_UNIT_TESTS +/** For testing: reset all the ratchets */ +void +monotime_reset_ratchets_for_testing(void) +{ + last_pctr = pctr_offset = last_tick_count = 0; + rollover_count = 0; + memset(&last_timeofday, 0, sizeof(struct timeval)); + memset(&timeofday_offset, 0, sizeof(struct timeval)); +} +#endif + +#ifdef __APPLE__ + +/** Initialized on startup: tells is how to convert from ticks to + * nanoseconds. + */ +static struct mach_timebase_info mach_time_info; + +static void +monotime_init_internal(void) +{ + tor_assert(!monotime_initialized); + int r = mach_timebase_info(&mach_time_info); + tor_assert(r == 0); + tor_assert(mach_time_info.denom != 0); +} + +/** + * Set "out" to the most recent monotonic time value + */ +void +monotime_get(monotime_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->abstime_ = (mock_time_nsec * mach_time_info.denom) + / mach_time_info.numer; + return; + } +#endif + out->abstime_ = mach_absolute_time(); +} + +/** + * Return the number of nanoseconds between <b>start</b> and <b>end</b>. + */ +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + if (BUG(mach_time_info.denom == 0)) { + monotime_init(); + } + const int64_t diff_ticks = end->abstime_ - start->abstime_; + const int64_t diff_nsec = + (diff_ticks * mach_time_info.numer) / mach_time_info.denom; + return diff_nsec; +} + +/* end of "__APPLE__" */ +#elif defined(HAVE_CLOCK_GETTIME) + +#ifdef CLOCK_MONOTONIC_COARSE +/** + * Which clock should we use for coarse-grained monotonic time? By default + * this is CLOCK_MONOTONIC_COARSE, but it might not work -- for example, + * if we're compiled with newer Linux headers and then we try to run on + * an old Linux kernel. In that case, we will fall back to CLOCK_MONOTONIC. + */ +static int clock_monotonic_coarse = CLOCK_MONOTONIC_COARSE; +#endif + +static void +monotime_init_internal(void) +{ +#ifdef CLOCK_MONOTONIC_COARSE + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) < 0) { + log_info(LD_GENERAL, "CLOCK_MONOTONIC_COARSE isn't working (%s); " + "falling back to CLOCK_MONOTONIC.", strerror(errno)); + clock_monotonic_coarse = CLOCK_MONOTONIC; + } +#endif +} + +void +monotime_get(monotime_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->ts_.tv_sec = (time_t) (mock_time_nsec / ONE_BILLION); + out->ts_.tv_nsec = (int) (mock_time_nsec % ONE_BILLION); + return; + } +#endif + int r = clock_gettime(CLOCK_MONOTONIC, &out->ts_); + tor_assert(r == 0); +} + +#ifdef CLOCK_MONOTONIC_COARSE +void +monotime_coarse_get(monotime_coarse_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->ts_.tv_sec = (time_t) (mock_time_nsec_coarse / ONE_BILLION); + out->ts_.tv_nsec = (int) (mock_time_nsec_coarse % ONE_BILLION); + return; + } +#endif + int r = clock_gettime(clock_monotonic_coarse, &out->ts_); + if (PREDICT_UNLIKELY(r < 0) && + errno == EINVAL && + clock_monotonic_coarse == CLOCK_MONOTONIC_COARSE) { + /* We should have caught this at startup in monotime_init_internal! + */ + log_warn(LD_BUG, "Falling back to non-coarse monotonic time %s initial " + "system start?", monotime_initialized?"after":"without"); + clock_monotonic_coarse = CLOCK_MONOTONIC; + r = clock_gettime(clock_monotonic_coarse, &out->ts_); + } + + tor_assert(r == 0); +} +#endif + +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + const int64_t diff_sec = end->ts_.tv_sec - start->ts_.tv_sec; + const int64_t diff_nsec = diff_sec * ONE_BILLION + + (end->ts_.tv_nsec - start->ts_.tv_nsec); + + return diff_nsec; +} + +/* end of "HAVE_CLOCK_GETTIME" */ +#elif defined (_WIN32) + +/** Result of QueryPerformanceFrequency, in terms needed to + * convert ticks to nanoseconds. */ +static int64_t nsec_per_tick_numer = 1; +static int64_t nsec_per_tick_denom = 1; + +/** Lock to protect last_pctr and pctr_offset */ +static CRITICAL_SECTION monotime_lock; +/** Lock to protect rollover_count and last_tick_count */ +static CRITICAL_SECTION monotime_coarse_lock; + +typedef ULONGLONG (WINAPI *GetTickCount64_fn_t)(void); +static GetTickCount64_fn_t GetTickCount64_fn = NULL; + +static void +monotime_init_internal(void) +{ + tor_assert(!monotime_initialized); + BOOL ok = InitializeCriticalSectionAndSpinCount(&monotime_lock, 200); + tor_assert(ok); + ok = InitializeCriticalSectionAndSpinCount(&monotime_coarse_lock, 200); + tor_assert(ok); + LARGE_INTEGER li; + ok = QueryPerformanceFrequency(&li); + tor_assert(ok); + tor_assert(li.QuadPart); + + uint64_t n = ONE_BILLION; + uint64_t d = li.QuadPart; + /* We need to simplify this or we'll probably overflow the int64. */ + simplify_fraction64(&n, &d); + tor_assert(n <= INT64_MAX); + tor_assert(d <= INT64_MAX); + + nsec_per_tick_numer = (int64_t) n; + nsec_per_tick_denom = (int64_t) d; + + last_pctr = 0; + pctr_offset = 0; + + HANDLE h = load_windows_system_library(TEXT("kernel32.dll")); + if (h) { + GetTickCount64_fn = (GetTickCount64_fn_t) + GetProcAddress(h, "GetTickCount64"); + } + // FreeLibrary(h) ? +} + +void +monotime_get(monotime_t *out) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->pcount_ = (mock_time_nsec * nsec_per_tick_denom) + / nsec_per_tick_numer; + return; + } +#endif + + /* Alas, QueryPerformanceCounter is not always monotonic: see bug list at + + https://www.python.org/dev/peps/pep-0418/#windows-queryperformancecounter + */ + + EnterCriticalSection(&monotime_lock); + LARGE_INTEGER res; + BOOL ok = QueryPerformanceCounter(&res); + tor_assert(ok); + const int64_t count_raw = res.QuadPart; + out->pcount_ = ratchet_performance_counter(count_raw); + LeaveCriticalSection(&monotime_lock); +} + +void +monotime_coarse_get(monotime_coarse_t *out) +{ +#ifdef TOR_UNIT_TESTS + if (monotime_mocking_enabled) { + out->tick_count_ = mock_time_nsec_coarse / ONE_MILLION; + return; + } +#endif + + if (GetTickCount64_fn) { + out->tick_count_ = (int64_t)GetTickCount64_fn(); + } else { + EnterCriticalSection(&monotime_coarse_lock); + DWORD tick = GetTickCount(); + out->tick_count_ = ratchet_coarse_performance_counter(tick); + LeaveCriticalSection(&monotime_coarse_lock); + } +} + +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + const int64_t diff_ticks = end->pcount_ - start->pcount_; + return (diff_ticks * nsec_per_tick_numer) / nsec_per_tick_denom; +} + +int64_t +monotime_coarse_diff_msec(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + const int64_t diff_ticks = end->tick_count_ - start->tick_count_; + return diff_ticks; +} + +int64_t +monotime_coarse_diff_usec(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + return monotime_coarse_diff_msec(start, end) * 1000; +} + +int64_t +monotime_coarse_diff_nsec(const monotime_coarse_t *start, + const monotime_coarse_t *end) +{ + return monotime_coarse_diff_msec(start, end) * ONE_MILLION; +} + +/* end of "_WIN32" */ +#elif defined(MONOTIME_USING_GETTIMEOFDAY) + +static tor_mutex_t monotime_lock; + +/** Initialize the monotonic timer subsystem. */ +static void +monotime_init_internal(void) +{ + tor_assert(!monotime_initialized); + tor_mutex_init(&monotime_lock); +} + +void +monotime_get(monotime_t *out) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + tor_mutex_acquire(&monotime_lock); + struct timeval timeval_raw; + tor_gettimeofday(&timeval_raw); + ratchet_timeval(&timeval_raw, &out->tv_); + tor_mutex_release(&monotime_lock); +} + +int64_t +monotime_diff_nsec(const monotime_t *start, + const monotime_t *end) +{ + struct timeval diff; + timersub(&end->tv_, &start->tv_, &diff); + return (diff.tv_sec * ONE_BILLION + diff.tv_usec * 1000); +} + +/* end of "MONOTIME_USING_GETTIMEOFDAY" */ +#else +#error "No way to implement monotonic timers." +#endif + +/** + * Initialize the monotonic timer subsystem. Must be called before any + * monotonic timer functions. This function is idempotent. + */ +void +monotime_init(void) +{ + if (!monotime_initialized) { + monotime_init_internal(); + monotime_initialized = 1; + monotime_get(&initialized_at); +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT + monotime_coarse_get(&initialized_at_coarse); +#endif + } +} + +int64_t +monotime_diff_usec(const monotime_t *start, + const monotime_t *end) +{ + const int64_t nsec = monotime_diff_nsec(start, end); + return CEIL_DIV(nsec, 1000); +} + +int64_t +monotime_diff_msec(const monotime_t *start, + const monotime_t *end) +{ + const int64_t nsec = monotime_diff_nsec(start, end); + return CEIL_DIV(nsec, ONE_MILLION); +} + +uint64_t +monotime_absolute_nsec(void) +{ + monotime_t now; + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + monotime_get(&now); + return monotime_diff_nsec(&initialized_at, &now); +} + +uint64_t +monotime_absolute_usec(void) +{ + return monotime_absolute_nsec() / 1000; +} + +uint64_t +monotime_absolute_msec(void) +{ + return monotime_absolute_nsec() / ONE_MILLION; +} + +#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT +uint64_t +monotime_coarse_absolute_nsec(void) +{ + if (BUG(monotime_initialized == 0)) { + monotime_init(); + } + + monotime_coarse_t now; + monotime_coarse_get(&now); + return monotime_coarse_diff_nsec(&initialized_at_coarse, &now); +} + +uint64_t +monotime_coarse_absolute_usec(void) +{ + return monotime_coarse_absolute_nsec() / 1000; +} + +uint64_t +monotime_coarse_absolute_msec(void) +{ + return monotime_coarse_absolute_nsec() / ONE_MILLION; +} +#endif + diff --git a/src/common/compat_time.h b/src/common/compat_time.h new file mode 100644 index 0000000000..2262446e57 --- /dev/null +++ b/src/common/compat_time.h @@ -0,0 +1,162 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.h + * + * \brief Functions and types for monotonic times. + * + * monotime_* functions try to provide a high-resolution monotonic timer with + * something the best resolution the system provides. monotime_coarse_* + * functions run faster (if the operating system gives us a way to do that) + * but produce a less accurate timer: accuracy will probably be on the order + * of tens of milliseconds. + */ + +#ifndef TOR_COMPAT_TIME_H +#define TOR_COMPAT_TIME_H + +#include "orconfig.h" +#ifdef _WIN32 +#undef HAVE_CLOCK_GETTIME +#endif + +#if defined(HAVE_CLOCK_GETTIME) +/* to ensure definition of CLOCK_MONOTONIC_COARSE if it's there */ +#include <time.h> +#endif + +#if !defined(HAVE_GETTIMEOFDAY) && !defined(HAVE_STRUCT_TIMEVAL_TV_SEC) +/** Implementation of timeval for platforms that don't have it. */ +struct timeval { + time_t tv_sec; + unsigned int tv_usec; +}; +#endif + +/** Represents a monotonic timer in a platform-dependent way. */ +typedef struct monotime_t { +#ifdef __APPLE__ + /* On apple, there is a 64-bit counter whose precision we must look up. */ + uint64_t abstime_; +#elif defined(HAVE_CLOCK_GETTIME) + /* It sure would be nice to use clock_gettime(). Posix is a nice thing. */ + struct timespec ts_; +#elif defined (_WIN32) + /* On Windows, there is a 64-bit counter whose precision we must look up. */ + int64_t pcount_; +#else +#define MONOTIME_USING_GETTIMEOFDAY + /* Otherwise, we will be stuck using gettimeofday. */ + struct timeval tv_; +#endif +} monotime_t; + +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_COARSE) +#define MONOTIME_COARSE_FN_IS_DIFFERENT +#define monotime_coarse_t monotime_t +#elif defined(_WIN32) +#define MONOTIME_COARSE_FN_IS_DIFFERENT +#define MONOTIME_COARSE_TYPE_IS_DIFFERENT +/** Represents a coarse monotonic time in a platform-independent way. */ +typedef struct monotime_coarse_t { + uint64_t tick_count_; +} monotime_coarse_t; +#else +#define monotime_coarse_t monotime_t +#endif + +/** + * Initialize the timing subsystem. This function is idempotent. + */ +void monotime_init(void); +/** + * Set <b>out</b> to the current time. + */ +void monotime_get(monotime_t *out); +/** + * Return the number of nanoseconds between <b>start</b> and <b>end</b>. + */ +int64_t monotime_diff_nsec(const monotime_t *start, const monotime_t *end); +/** + * Return the number of microseconds between <b>start</b> and <b>end</b>. + */ +int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end); +/** + * Return the number of milliseconds between <b>start</b> and <b>end</b>. + */ +int64_t monotime_diff_msec(const monotime_t *start, const monotime_t *end); +/** + * Return the number of nanoseconds since the timer system was initialized. + */ +uint64_t monotime_absolute_nsec(void); +/** + * Return the number of microseconds since the timer system was initialized. + */ +uint64_t monotime_absolute_usec(void); +/** + * Return the number of milliseconds since the timer system was initialized. + */ +uint64_t monotime_absolute_msec(void); + +#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) +/** + * Set <b>out</b> to the current coarse time. + */ +void monotime_coarse_get(monotime_coarse_t *out); +uint64_t monotime_coarse_absolute_nsec(void); +uint64_t monotime_coarse_absolute_usec(void); +uint64_t monotime_coarse_absolute_msec(void); +#else +#define monotime_coarse_get monotime_get +#define monotime_coarse_absolute_nsec monotime_absolute_nsec +#define monotime_coarse_absolute_usec monotime_absolute_usec +#define monotime_coarse_absolute_msec monotime_absolute_msec +#endif + +#if defined(MONOTIME_COARSE_TYPE_IS_DIFFERENT) +int64_t monotime_coarse_diff_nsec(const monotime_coarse_t *start, + const monotime_coarse_t *end); +int64_t monotime_coarse_diff_usec(const monotime_coarse_t *start, + const monotime_coarse_t *end); +int64_t monotime_coarse_diff_msec(const monotime_coarse_t *start, + const monotime_coarse_t *end); +#else +#define monotime_coarse_diff_nsec monotime_diff_nsec +#define monotime_coarse_diff_usec monotime_diff_usec +#define monotime_coarse_diff_msec monotime_diff_msec +#endif + +void tor_gettimeofday(struct timeval *timeval); + +#ifdef TOR_UNIT_TESTS +void tor_sleep_msec(int msec); + +void monotime_enable_test_mocking(void); +void monotime_disable_test_mocking(void); +void monotime_set_mock_time_nsec(int64_t); +#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT) +void monotime_coarse_set_mock_time_nsec(int64_t); +#else +#define monotime_coarse_set_mock_time_nsec monotime_set_mock_time_nsec +#endif +#endif + +#ifdef COMPAT_TIME_PRIVATE +#if defined(_WIN32) || defined(TOR_UNIT_TESTS) +STATIC int64_t ratchet_performance_counter(int64_t count_raw); +STATIC int64_t ratchet_coarse_performance_counter(int64_t count_raw); +#endif +#if defined(MONOTIME_USING_GETTIMEOFDAY) || defined(TOR_UNIT_TESTS) +STATIC void ratchet_timeval(const struct timeval *timeval_raw, + struct timeval *out); +#endif +#ifdef TOR_UNIT_TESTS +void monotime_reset_ratchets_for_testing(void); +#endif +#endif + +#endif + diff --git a/src/common/container.c b/src/common/container.c index ddf3bafa91..ec59dccf62 100644 --- a/src/common/container.c +++ b/src/common/container.c @@ -544,7 +544,7 @@ smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) /** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>, * return the most frequent member in the list. Break ties in favor of * later elements. If the list is empty, return NULL. If count_out is - * non-null, set it to the most frequent member. + * non-null, set it to the count of the most frequent member. */ void * smartlist_get_most_frequent_(const smartlist_t *sl, diff --git a/src/common/container.h b/src/common/container.h index 92ad3f5ec7..71495b660a 100644 --- a/src/common/container.h +++ b/src/common/container.h @@ -526,7 +526,7 @@ void* strmap_remove_lc(strmap_t *map, const char *key); return (valtype*)digestmap_remove((digestmap_t*)map, key); \ } \ ATTR_UNUSED static inline void \ - prefix##free(maptype *map, void (*free_val)(void*)) \ + prefix##f##ree(maptype *map, void (*free_val)(void*)) \ { \ digestmap_free((digestmap_t*)map, free_val); \ } \ diff --git a/src/common/crypto.c b/src/common/crypto.c index f7bb8ff1f9..fff516cc8e 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -29,18 +29,7 @@ #include "crypto_ed25519.h" #include "crypto_format.h" -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#endif - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic push -#endif -/* Some versions of OpenSSL declare X509_STORE_CTX_set_verify_cb twice. - * Suppress the GCC warning so we can build with -Wredundant-decl. */ -#pragma GCC diagnostic ignored "-Wredundant-decls" -#endif +DISABLE_GCC_WARNING(redundant-decls) #include <openssl/err.h> #include <openssl/rsa.h> @@ -53,6 +42,8 @@ #include <openssl/conf.h> #include <openssl/hmac.h> +ENABLE_GCC_WARNING(redundant-decls) + #if __GNUC__ && GCC_VERSION >= 402 #if GCC_VERSION >= 406 #pragma GCC diagnostic pop @@ -65,7 +56,6 @@ #include <ctype.h> #endif #ifdef HAVE_UNISTD_H -#define _GNU_SOURCE #include <unistd.h> #endif #ifdef HAVE_FCNTL_H @@ -77,8 +67,12 @@ #ifdef HAVE_SYS_SYSCALL_H #include <sys/syscall.h> #endif +#ifdef HAVE_SYS_RANDOM_H +#include <sys/random.h> +#endif #include "torlog.h" +#include "torint.h" #include "aes.h" #include "util.h" #include "container.h" @@ -88,15 +82,6 @@ #include "keccak-tiny/keccak-tiny.h" -#ifdef __APPLE__ -/* Apple messed up their getentropy definitions in Sierra. It's not insecure - * or anything (as far as I know) but it makes compatible builds hard. 0.2.9 - * contains the necessary tricks to do it right: in 0.2.8, we're just using - * this blunt instrument. - */ -#undef HAVE_GETENTROPY -#endif - #ifdef ANDROID /* Android's OpenSSL seems to have removed all of its Engine support. */ #define DISABLE_ENGINES @@ -138,15 +123,6 @@ struct crypto_pk_t RSA *key; /**< The key itself */ }; -/** Key and stream information for a stream cipher. */ -struct crypto_cipher_t -{ - char key[CIPHER_KEY_LEN]; /**< The raw key. */ - char iv[CIPHER_IV_LEN]; /**< The initial IV. */ - aes_cnt_cipher_t *cipher; /**< The key in format usable for counter-mode AES - * encryption */ -}; - /** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake * while we're waiting for the second.*/ struct crypto_dh_t { @@ -164,7 +140,7 @@ crypto_get_rsa_padding_overhead(int padding) switch (padding) { case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD; - default: tor_assert(0); return -1; + default: tor_assert(0); return -1; // LCOV_EXCL_LINE } } @@ -176,7 +152,7 @@ crypto_get_rsa_padding(int padding) switch (padding) { case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING; - default: tor_assert(0); return -1; + default: tor_assert(0); return -1; // LCOV_EXCL_LINE } } @@ -201,13 +177,9 @@ crypto_log_errors(int severity, const char *doing) if (!msg) msg = "(null)"; if (!lib) lib = "(null)"; if (!func) func = "(null)"; - if (doing) { - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", + if (BUG(!doing)) doing = "(null)"; + tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", doing, msg, lib, func); - } else { - tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", - msg, lib, func); - } } } @@ -573,38 +545,48 @@ crypto_pk_free(crypto_pk_t *env) } /** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. If you - * provide NULL in place of either one, it is generated at random. - */ + * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both + * must be provided. Key length must be 128, 192, or 256 */ crypto_cipher_t * -crypto_cipher_new_with_iv(const char *key, const char *iv) +crypto_cipher_new_with_iv_and_bits(const uint8_t *key, + const uint8_t *iv, + int bits) { - crypto_cipher_t *env; - - env = tor_malloc_zero(sizeof(crypto_cipher_t)); - - if (key == NULL) - crypto_rand(env->key, CIPHER_KEY_LEN); - else - memcpy(env->key, key, CIPHER_KEY_LEN); - if (iv == NULL) - crypto_rand(env->iv, CIPHER_IV_LEN); - else - memcpy(env->iv, iv, CIPHER_IV_LEN); + tor_assert(key); + tor_assert(iv); - env->cipher = aes_new_cipher(env->key, env->iv); + return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); +} - return env; +/** Allocate and return a new symmetric cipher using the provided key and iv. + * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both + * must be provided. + */ +crypto_cipher_t * +crypto_cipher_new_with_iv(const char *key, const char *iv) +{ + return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, + 128); } /** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all - * zero bytes. */ + * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or + * 256. */ crypto_cipher_t * -crypto_cipher_new(const char *key) +crypto_cipher_new_with_bits(const char *key, int bits) { char zeroiv[CIPHER_IV_LEN]; memset(zeroiv, 0, sizeof(zeroiv)); - return crypto_cipher_new_with_iv(key, zeroiv); + return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, + bits); +} + +/** Return a new crypto_cipher_t with the provided <b>key</b> (of + * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ +crypto_cipher_t * +crypto_cipher_new(const char *key) +{ + return crypto_cipher_new_with_bits(key, 128); } /** Free a symmetric cipher. @@ -615,10 +597,7 @@ crypto_cipher_free(crypto_cipher_t *env) if (!env) return; - tor_assert(env->cipher); - aes_cipher_free(env->cipher); - memwipe(env, 0, sizeof(crypto_cipher_t)); - tor_free(env); + aes_cipher_free(env); } /* public key crypto */ @@ -1006,6 +985,20 @@ crypto_pk_dup_key(crypto_pk_t *env) return env; } +#ifdef TOR_UNIT_TESTS +/** For testing: replace dest with src. (Dest must have a refcount + * of 1) */ +void +crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src) +{ + tor_assert(dest); + tor_assert(dest->refs == 1); + tor_assert(src); + RSA_free(dest->key); + dest->key = RSAPrivateKey_dup(src->key); +} +#endif + /** Make a real honest-to-goodness copy of <b>env</b>, and return it. * Returns NULL on failure. */ crypto_pk_t * @@ -1023,6 +1016,10 @@ crypto_pk_copy_full(crypto_pk_t *env) new_key = RSAPublicKey_dup(env->key); } if (!new_key) { + /* LCOV_EXCL_START + * + * We can't cause RSA*Key_dup() to fail, so we can't really test this. + */ log_err(LD_CRYPTO, "Unable to duplicate a %s key: openssl failed.", privatekey?"private":"public"); crypto_log_errors(LOG_ERR, @@ -1030,6 +1027,7 @@ crypto_pk_copy_full(crypto_pk_t *env) "Duplicating a public key"); tor_fragile_assert(); return NULL; + /* LCOV_EXCL_STOP */ } return crypto_new_pk_from_rsa_(new_key); @@ -1269,10 +1267,12 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, tor_assert(tolen >= fromlen + overhead + CIPHER_KEY_LEN); tor_assert(tolen >= pkeylen); - cipher = crypto_cipher_new(NULL); /* generate a new key. */ + char key[CIPHER_KEY_LEN]; + crypto_rand(key, sizeof(key)); /* generate a new key. */ + cipher = crypto_cipher_new(key); buf = tor_malloc(pkeylen+1); - memcpy(buf, cipher->key, CIPHER_KEY_LEN); + memcpy(buf, key, CIPHER_KEY_LEN); memcpy(buf+CIPHER_KEY_LEN, from, pkeylen-overhead-CIPHER_KEY_LEN); /* Length of symmetrically encrypted data. */ @@ -1287,6 +1287,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, if (r<0) goto err; memwipe(buf, 0, pkeylen); + memwipe(key, 0, sizeof(key)); tor_free(buf); crypto_cipher_free(cipher); tor_assert(outlen+symlen < INT_MAX); @@ -1294,6 +1295,7 @@ crypto_pk_public_hybrid_encrypt(crypto_pk_t *env, err: memwipe(buf, 0, pkeylen); + memwipe(key, 0, sizeof(key)); tor_free(buf); crypto_cipher_free(cipher); return -1; @@ -1585,14 +1587,6 @@ crypto_pk_base64_decode(const char *str, size_t len) /* symmetric crypto */ -/** Return a pointer to the key set for the cipher in <b>env</b>. - */ -const char * -crypto_cipher_get_key(crypto_cipher_t *env) -{ - return env->key; -} - /** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher * <b>env</b>; on success, store the result to <b>to</b> and return 0. * Does not check for failure. @@ -1602,14 +1596,14 @@ crypto_cipher_encrypt(crypto_cipher_t *env, char *to, const char *from, size_t fromlen) { tor_assert(env); - tor_assert(env->cipher); + tor_assert(env); tor_assert(from); tor_assert(fromlen); tor_assert(to); tor_assert(fromlen < SIZE_T_CEILING); memcpy(to, from, fromlen); - aes_crypt_inplace(env->cipher, to, fromlen); + aes_crypt_inplace(env, to, fromlen); return 0; } @@ -1627,7 +1621,7 @@ crypto_cipher_decrypt(crypto_cipher_t *env, char *to, tor_assert(fromlen < SIZE_T_CEILING); memcpy(to, from, fromlen); - aes_crypt_inplace(env->cipher, to, fromlen); + aes_crypt_inplace(env, to, fromlen); return 0; } @@ -1638,7 +1632,7 @@ void crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) { tor_assert(len < SIZE_T_CEILING); - aes_crypt_inplace(env->cipher, buf, len); + aes_crypt_inplace(env, buf, len); } /** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in @@ -1662,11 +1656,14 @@ crypto_cipher_encrypt_with_iv(const char *key, if (tolen < fromlen + CIPHER_IV_LEN) return -1; - cipher = crypto_cipher_new_with_iv(key, NULL); + char iv[CIPHER_IV_LEN]; + crypto_rand(iv, sizeof(iv)); + cipher = crypto_cipher_new_with_iv(key, iv); - memcpy(to, cipher->iv, CIPHER_IV_LEN); + memcpy(to, iv, CIPHER_IV_LEN); crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); crypto_cipher_free(cipher); + memwipe(iv, 0, sizeof(iv)); return (int)(fromlen + CIPHER_IV_LEN); } @@ -1780,8 +1777,10 @@ crypto_digest_algorithm_get_name(digest_algorithm_t alg) case DIGEST_SHA3_512: return "sha3-512"; default: + // LCOV_EXCL_START tor_fragile_assert(); return "??unknown_digest??"; + // LCOV_EXCL_STOP } } @@ -1805,7 +1804,7 @@ crypto_digest_algorithm_parse_name(const char *name) } /** Given an algorithm, return the digest length in bytes. */ -static inline size_t +size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg) { switch (alg) { @@ -1820,8 +1819,8 @@ crypto_digest_algorithm_get_length(digest_algorithm_t alg) case DIGEST_SHA3_512: return DIGEST512_LEN; default: - tor_assert(0); - return 0; /* Unreachable */ + tor_assert(0); // LCOV_EXCL_LINE + return 0; /* Unreachable */ // LCOV_EXCL_LINE } } @@ -1864,23 +1863,53 @@ crypto_digest_alloc_bytes(digest_algorithm_t alg) case DIGEST_SHA3_512: return END_OF_FIELD(d.sha3); default: - tor_assert(0); - return 0; + tor_assert(0); // LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE } #undef END_OF_FIELD #undef STRUCT_FIELD_SIZE } +/** + * Internal function: create and return a new digest object for 'algorithm'. + * Does not typecheck the algorithm. + */ +static crypto_digest_t * +crypto_digest_new_internal(digest_algorithm_t algorithm) +{ + crypto_digest_t *r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); + r->algorithm = algorithm; + + switch (algorithm) + { + case DIGEST_SHA1: + SHA1_Init(&r->d.sha1); + break; + case DIGEST_SHA256: + SHA256_Init(&r->d.sha2); + break; + case DIGEST_SHA512: + SHA512_Init(&r->d.sha512); + break; + case DIGEST_SHA3_256: + keccak_digest_init(&r->d.sha3, 256); + break; + case DIGEST_SHA3_512: + keccak_digest_init(&r->d.sha3, 512); + break; + default: + tor_assert_unreached(); + } + + return r; +} + /** Allocate and return a new digest object to compute SHA1 digests. */ crypto_digest_t * crypto_digest_new(void) { - crypto_digest_t *r; - r = tor_malloc(crypto_digest_alloc_bytes(DIGEST_SHA1)); - SHA1_Init(&r->d.sha1); - r->algorithm = DIGEST_SHA1; - return r; + return crypto_digest_new_internal(DIGEST_SHA1); } /** Allocate and return a new digest object to compute 256-bit digests @@ -1888,15 +1917,8 @@ crypto_digest_new(void) crypto_digest_t * crypto_digest256_new(digest_algorithm_t algorithm) { - crypto_digest_t *r; tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256); - r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); - if (algorithm == DIGEST_SHA256) - SHA256_Init(&r->d.sha2); - else - keccak_digest_init(&r->d.sha3, 256); - r->algorithm = algorithm; - return r; + return crypto_digest_new_internal(algorithm); } /** Allocate and return a new digest object to compute 512-bit digests @@ -1904,15 +1926,8 @@ crypto_digest256_new(digest_algorithm_t algorithm) crypto_digest_t * crypto_digest512_new(digest_algorithm_t algorithm) { - crypto_digest_t *r; tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512); - r = tor_malloc(crypto_digest_alloc_bytes(algorithm)); - if (algorithm == DIGEST_SHA512) - SHA512_Init(&r->d.sha512); - else - keccak_digest_init(&r->d.sha3, 512); - r->algorithm = algorithm; - return r; + return crypto_digest_new_internal(algorithm); } /** Deallocate a digest object. @@ -1955,8 +1970,10 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len); break; default: + /* LCOV_EXCL_START */ tor_fragile_assert(); break; + /* LCOV_EXCL_STOP */ } } @@ -1995,13 +2012,15 @@ crypto_digest_get_digest(crypto_digest_t *digest, case DIGEST_SHA512: SHA512_Final(r, &tmpenv.d.sha512); break; +//LCOV_EXCL_START case DIGEST_SHA3_256: /* FALLSTHROUGH */ case DIGEST_SHA3_512: - log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); - tor_assert(0); /* This is fatal, because it should never happen. */ default: - tor_assert(0); /* Unreachable. */ + log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm); + /* This is fatal, because it should never happen. */ + tor_assert_unreached(); break; +//LCOV_EXCL_STOP } memcpy(out, r, out_len); memwipe(r, 0, sizeof(r)); @@ -2060,27 +2079,7 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, const char *append, digest_algorithm_t alg) { - crypto_digest_t *d = NULL; - switch (alg) { - case DIGEST_SHA1: - d = crypto_digest_new(); - break; - case DIGEST_SHA256: /* FALLSTHROUGH */ - case DIGEST_SHA3_256: - d = crypto_digest256_new(alg); - break; - case DIGEST_SHA512: /* FALLSTHROUGH */ - case DIGEST_SHA3_512: - d = crypto_digest512_new(alg); - break; - default: - log_warn(LD_BUG, "Called with unknown algorithm %d", alg); - /* If fragile_assert is not enabled, wipe output and return - * without running any calculations */ - memwipe(digest_out, 0xff, len_out); - tor_fragile_assert(); - goto free; - } + crypto_digest_t *d = crypto_digest_new_internal(alg); if (prepend) crypto_digest_add_bytes(d, prepend, strlen(prepend)); SMARTLIST_FOREACH(lst, const char *, cp, @@ -2088,8 +2087,6 @@ crypto_digest_smartlist_prefix(char *digest_out, size_t len_out, if (append) crypto_digest_add_bytes(d, append, strlen(append)); crypto_digest_get_digest(d, digest_out, len_out); - - free: crypto_digest_free(d); } @@ -2258,9 +2255,14 @@ crypto_set_tls_dh_prime(void) int r; /* If the space is occupied, free the previous TLS DH prime */ - if (dh_param_p_tls) { + if (BUG(dh_param_p_tls)) { + /* LCOV_EXCL_START + * + * We shouldn't be calling this twice. + */ BN_clear_free(dh_param_p_tls); dh_param_p_tls = NULL; + /* LCOV_EXCL_STOP */ } tls_prime = BN_new(); @@ -2292,8 +2294,8 @@ init_dh_param(void) { BIGNUM *circuit_dh_prime; int r; - if (dh_param_p && dh_param_g) - return; + if (BUG(dh_param_p && dh_param_g)) + return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. circuit_dh_prime = BN_new(); tor_assert(circuit_dh_prime); @@ -2383,10 +2385,13 @@ crypto_dh_new(int dh_type) return res; err: + /* LCOV_EXCL_START + * This error condition is only reached when an allocation fails */ crypto_log_errors(LOG_WARN, "creating DH object"); if (res->dh) DH_free(res->dh); /* frees p and g too */ tor_free(res); return NULL; + /* LCOV_EXCL_STOP */ } /** Return a copy of <b>dh</b>, sharing its internal state. */ @@ -2420,8 +2425,11 @@ crypto_dh_generate_public(crypto_dh_t *dh) again: #endif if (!DH_generate_key(dh->dh)) { + /* LCOV_EXCL_START + * To test this we would need some way to tell openssl to break DH. */ crypto_log_errors(LOG_WARN, "generating DH key"); return -1; + /* LCOV_EXCL_STOP */ } #ifdef OPENSSL_1_1_API /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without @@ -2437,6 +2445,8 @@ crypto_dh_generate_public(crypto_dh_t *dh) } #else if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { + /* LCOV_EXCL_START + * If this happens, then openssl's DH implementation is busted. */ log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" "the-universe chances really do happen. Trying again."); /* Free and clear the keys, so OpenSSL will actually try again. */ @@ -2444,6 +2454,7 @@ crypto_dh_generate_public(crypto_dh_t *dh) BN_clear_free(dh->dh->priv_key); dh->dh->pub_key = dh->dh->priv_key = NULL; goto again; + /* LCOV_EXCL_STOP */ } #endif return 0; @@ -2508,8 +2519,8 @@ tor_check_dh_key(int severity, const BIGNUM *bn) tor_assert(bn); x = BN_new(); tor_assert(x); - if (!dh_param_p) - init_dh_param(); + if (BUG(!dh_param_p)) + init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. BN_set_word(x, 1); if (BN_cmp(bn,x)<=0) { log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); @@ -2531,8 +2542,6 @@ tor_check_dh_key(int severity, const BIGNUM *bn) return -1; } -#undef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) /** Given a DH key exchange object, and our peer's value of g^y (as a * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate * <b>secret_bytes_out</b> bytes of shared key material and write them @@ -2720,6 +2729,11 @@ crypto_seed_weak_rng(tor_weak_rng_t *rng) tor_init_weak_random(rng, seed); } +#ifdef TOR_UNIT_TESTS +int break_strongest_rng_syscall = 0; +int break_strongest_rng_fallback = 0; +#endif + /** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, * via system calls, storing it into <b>out</b>. Return 0 on success, -1 on * failure. A maximum request size of 256 bytes is imposed. @@ -2729,6 +2743,11 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) { tor_assert(out_len <= MAX_STRONGEST_RAND_SIZE); +#ifdef TOR_UNIT_TESTS + if (break_strongest_rng_syscall) + return -1; +#endif + #if defined(_WIN32) static int provider_set = 0; static HCRYPTPROV provider; @@ -2778,6 +2797,7 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) } while (ret == -1 && ((errno == EINTR) ||(errno == EAGAIN))); if (PREDICT_UNLIKELY(ret == -1)) { + /* LCOV_EXCL_START we can't actually make the syscall fail in testing. */ tor_assert(errno != EAGAIN); tor_assert(errno != EINTR); @@ -2785,6 +2805,7 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) log_warn(LD_CRYPTO, "Can't get entropy from getrandom()."); getrandom_works = 0; /* Don't bother trying again. */ return -1; + /* LCOV_EXCL_STOP */ } tor_assert(ret == (long)out_len); @@ -2813,6 +2834,11 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len) static int crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) { +#ifdef TOR_UNIT_TESTS + if (break_strongest_rng_fallback) + return -1; +#endif + #ifdef _WIN32 /* Windows exclusively uses crypto_strongest_rand_syscall(). */ (void)out; @@ -2833,10 +2859,13 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) n = read_all(fd, (char*)out, out_len, 0); close(fd); if (n != out_len) { + /* LCOV_EXCL_START + * We can't make /dev/foorandom actually fail. */ log_warn(LD_CRYPTO, "Error reading from entropy source (read only %lu bytes).", (unsigned long)n); return -1; + /* LCOV_EXCL_STOP */ } return 0; @@ -2850,7 +2879,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) * storing it into <b>out</b>. Return 0 on success, -1 on failure. A maximum * request size of 256 bytes is imposed. */ -static int +STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len) { static const size_t sanity_min_size = 16; @@ -2884,13 +2913,17 @@ crypto_strongest_rand_raw(uint8_t *out, size_t out_len) return 0; } - /* We tried max_attempts times to fill a buffer >= 128 bits long, + /* LCOV_EXCL_START + * + * We tried max_attempts times to fill a buffer >= 128 bits long, * and each time it returned all '0's. Either the system entropy * source is busted, or the user should go out and buy a ticket to * every lottery on the planet. */ log_warn(LD_CRYPTO, "Strong OS entropy returned all zero buffer."); + return -1; + /* LCOV_EXCL_STOP */ } /** Try to get <b>out_len</b> bytes of the strongest entropy we can generate, @@ -2909,10 +2942,12 @@ crypto_strongest_rand(uint8_t *out, size_t out_len) while (out_len) { crypto_rand((char*) inp, DLEN); if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) { + // LCOV_EXCL_START log_err(LD_CRYPTO, "Failed to load strong entropy when generating an " "important key. Exiting."); /* Die with an assertion so we get a stack trace. */ tor_assert(0); + // LCOV_EXCL_STOP } if (out_len >= DLEN) { SHA512(inp, sizeof(inp), out); @@ -2943,7 +2978,7 @@ crypto_seed_rng(void) * functions. If one succeeds, we'll accept the RNG as seeded. */ rand_poll_ok = RAND_poll(); if (rand_poll_ok == 0) - log_warn(LD_CRYPTO, "RAND_poll() failed."); + log_warn(LD_CRYPTO, "RAND_poll() failed."); // LCOV_EXCL_LINE load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf)); if (load_entropy_ok) { @@ -3078,8 +3113,8 @@ crypto_rand_double(void) { /* We just use an unsigned int here; we don't really care about getting * more than 32 bits of resolution */ - unsigned int uint; - crypto_rand((char*)&uint, sizeof(uint)); + unsigned int u; + crypto_rand((char*)&u, sizeof(u)); #if SIZEOF_INT == 4 #define UINT_MAX_AS_DOUBLE 4294967296.0 #elif SIZEOF_INT == 8 @@ -3087,7 +3122,7 @@ crypto_rand_double(void) #else #error SIZEOF_INT is neither 4 nor 8 #endif - return ((double)uint) / UINT_MAX_AS_DOUBLE; + return ((double)u) / UINT_MAX_AS_DOUBLE; } /** Generate and return a new random hostname starting with <b>prefix</b>, diff --git a/src/common/crypto.h b/src/common/crypto.h index 682c4e3253..116e0a62fd 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -13,6 +13,8 @@ #ifndef TOR_CRYPTO_H #define TOR_CRYPTO_H +#include "orconfig.h" + #include <stdio.h> #include "torint.h" #include "testsupport.h" @@ -115,7 +117,7 @@ typedef struct { } common_digests_t; typedef struct crypto_pk_t crypto_pk_t; -typedef struct crypto_cipher_t crypto_cipher_t; +typedef struct aes_cnt_cipher crypto_cipher_t; typedef struct crypto_digest_t crypto_digest_t; typedef struct crypto_xof_t crypto_xof_t; typedef struct crypto_dh_t crypto_dh_t; @@ -136,7 +138,11 @@ void crypto_pk_free(crypto_pk_t *env); void crypto_set_tls_dh_prime(void); crypto_cipher_t *crypto_cipher_new(const char *key); +crypto_cipher_t *crypto_cipher_new_with_bits(const char *key, int bits); crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); +crypto_cipher_t *crypto_cipher_new_with_iv_and_bits(const uint8_t *key, + const uint8_t *iv, + int bits); void crypto_cipher_free(crypto_cipher_t *env); /* public key crypto */ @@ -233,6 +239,7 @@ void crypto_digest_smartlist(char *digest_out, size_t len_out, const struct smartlist_t *lst, const char *append, digest_algorithm_t alg); const char *crypto_digest_algorithm_get_name(digest_algorithm_t alg); +size_t crypto_digest_algorithm_get_length(digest_algorithm_t alg); int crypto_digest_algorithm_parse_name(const char *name); crypto_digest_t *crypto_digest_new(void); crypto_digest_t *crypto_digest256_new(digest_algorithm_t algorithm); @@ -317,6 +324,16 @@ void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); #ifdef CRYPTO_PRIVATE STATIC int crypto_force_rand_ssleay(void); +STATIC int crypto_strongest_rand_raw(uint8_t *out, size_t out_len); + +#ifdef TOR_UNIT_TESTS +extern int break_strongest_rng_syscall; +extern int break_strongest_rng_fallback; +#endif +#endif + +#ifdef TOR_UNIT_TESTS +void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src); #endif #endif diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c index 57c878b79a..fcbee3aba2 100644 --- a/src/common/crypto_curve25519.c +++ b/src/common/crypto_curve25519.c @@ -5,6 +5,14 @@ * \file crypto_curve25519.c * * \brief Wrapper code for a curve25519 implementation. + * + * Curve25519 is an Elliptic-Curve Diffie Hellman handshake, designed by + * Dan Bernstein. For more information, see https://cr.yp.to/ecdh.html + * + * Tor uses Curve25519 as the basis of its "ntor" circuit extension + * handshake, and in related code. The functions in this module are + * used to find the most suitable available Curve25519 implementation, + * to provide wrappers around it, and so on. */ #define CRYPTO_CURVE25519_PRIVATE @@ -39,15 +47,23 @@ int curve25519_donna(uint8_t *mypublic, static void pick_curve25519_basepoint_impl(void); +/** This is set to 1 if we have an optimized Ed25519-based + * implementation for multiplying a value by the basepoint; to 0 if we + * don't, and to -1 if we haven't checked. */ static int curve25519_use_ed = -1; +/** + * Helper function: call the most appropriate backend to compute the + * scalar "secret" times the point "point". Store the result in + * "output". Return 0 on success, negative on failure. + **/ STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, - const uint8_t *basepoint) + const uint8_t *point) { uint8_t bp[CURVE25519_PUBKEY_LEN]; int r; - memcpy(bp, basepoint, CURVE25519_PUBKEY_LEN); + memcpy(bp, point, CURVE25519_PUBKEY_LEN); /* Clear the high bit, in case our backend foolishly looks at it. */ bp[31] &= 0x7f; #ifdef USE_CURVE25519_DONNA @@ -61,12 +77,19 @@ curve25519_impl(uint8_t *output, const uint8_t *secret, return r; } +/** + * Helper function: Multiply the scalar "secret" by the Curve25519 + * basepoint (X=9), and store the result in "output". Return 0 on + * success, -1 on false. + */ STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret) { int r = 0; - if (PREDICT_UNLIKELY(curve25519_use_ed == -1)) { + if (BUG(curve25519_use_ed == -1)) { + /* LCOV_EXCL_START - Only reached if we forgot to call curve25519_init() */ pick_curve25519_basepoint_impl(); + /* LCOV_EXCL_STOP */ } /* TODO: Someone should benchmark curved25519_scalarmult_basepoint versus @@ -83,6 +106,10 @@ curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret) return r; } +/** + * Override the decision of whether to use the Ed25519-based basepoint + * multiply function. Used for testing. + */ void curve25519_set_impl_params(int use_ed) { @@ -140,6 +167,10 @@ curve25519_secret_key_generate(curve25519_secret_key_t *key_out, return 0; } +/** + * Given a secret key in <b>seckey</b>, create the corresponding public + * key in <b>key_out</b>. + */ void curve25519_public_key_generate(curve25519_public_key_t *key_out, const curve25519_secret_key_t *seckey) @@ -147,6 +178,10 @@ curve25519_public_key_generate(curve25519_public_key_t *key_out, curve25519_basepoint_impl(key_out->public_key, seckey->secret_key); } +/** + * Construct a new keypair in *<b>keypair_out</b>. If <b>extra_strong</b> + * is true, this key is possibly going to get used more than once, so + * use a better-than-usual RNG. Return 0 on success, -1 on failure. */ int curve25519_keypair_generate(curve25519_keypair_t *keypair_out, int extra_strong) @@ -157,7 +192,13 @@ curve25519_keypair_generate(curve25519_keypair_t *keypair_out, return 0; } -/* DOCDOC */ +/** Store the keypair <b>keypair</b>, including its secret and public + * parts, to the file <b>fname</b>. Use the string tag <b>tag</b> to + * distinguish this from other Curve25519 keypairs. Return 0 on success, + * -1 on failure. + * + * See crypto_write_tagged_contents_to_file() for more information on + * the metaformat used for these keys.*/ int curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, const char *fname, @@ -180,7 +221,10 @@ curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair, return r; } -/* DOCDOC */ +/** Read a curve25519 keypair from a file named <b>fname</b> created by + * curve25519_keypair_write_to_file(). Store the keypair in + * <b>keypair_out</b>, and the associated tag string in <b>tag_out</b>. + * Return 0 on success, and -1 on failure. */ int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, char **tag_out, @@ -195,6 +239,7 @@ curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out, if (len != sizeof(content)) goto end; + /* Make sure that the public key matches the secret key */ memcpy(keypair_out->seckey.secret_key, content, CURVE25519_SECKEY_LEN); curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey); if (tor_memneq(keypair_out->pubkey.public_key, @@ -290,10 +335,13 @@ pick_curve25519_basepoint_impl(void) if (curve25519_basepoint_spot_check() == 0) return; - log_warn(LD_CRYPTO, "The ed25519-based curve25519 basepoint " + /* LCOV_EXCL_START + * only reachable if our basepoint implementation broken */ + log_warn(LD_BUG|LD_CRYPTO, "The ed25519-based curve25519 basepoint " "multiplication seems broken; using the curve25519 " "implementation."); curve25519_use_ed = 0; + /* LCOV_EXCL_STOP */ } /** Initialize the curve25519 implementations. This is necessary if you're diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h index 547e393567..4011820949 100644 --- a/src/common/crypto_curve25519.h +++ b/src/common/crypto_curve25519.h @@ -14,12 +14,20 @@ /** Length of the result of a curve25519 handshake. */ #define CURVE25519_OUTPUT_LEN 32 -/** Wrapper type for a curve25519 public key */ +/** Wrapper type for a curve25519 public key. + * + * (We define a separate type for these to make it less likely that we'll + * mistake them for secret keys.) + * */ typedef struct curve25519_public_key_t { uint8_t public_key[CURVE25519_PUBKEY_LEN]; } curve25519_public_key_t; -/** Wrapper type for a curve25519 secret key */ +/** Wrapper type for a curve25519 secret key + * + * (We define a separate type for these to make it less likely that we'll + * mistake them for public keys.) + **/ typedef struct curve25519_secret_key_t { uint8_t secret_key[CURVE25519_SECKEY_LEN]; } curve25519_secret_key_t; diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index ea2d8e3892..30ed772274 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -5,6 +5,14 @@ * \file crypto_ed25519.c * * \brief Wrapper code for an ed25519 implementation. + * + * Ed25519 is a Schnorr signature on a Twisted Edwards curve, defined + * by Dan Bernstein. For more information, see https://ed25519.cr.yp.to/ + * + * This module wraps our choice of Ed25519 backend, and provides a few + * convenience functions for checking and generating signatures. It also + * provides Tor-specific tools for key blinding and for converting Ed25519 + * keys to and from the corresponding Curve25519 keys. */ #include "orconfig.h" @@ -28,7 +36,7 @@ static void pick_ed25519_impl(void); static int ed25519_impl_spot_check(void); -/** An Ed25519 implementation */ +/** An Ed25519 implementation, as a set of function pointers. */ typedef struct { int (*selftest)(void); @@ -53,6 +61,8 @@ typedef struct { int); } ed25519_impl_t; +/** The Ref10 Ed25519 implementation. This one is pure C and lightly + * optimized. */ static const ed25519_impl_t impl_ref10 = { NULL, @@ -71,6 +81,8 @@ static const ed25519_impl_t impl_ref10 = { ed25519_ref10_pubkey_from_curve25519_pubkey, }; +/** The Ref10 Ed25519 implementation. This one is heavily optimized, but still + * mostly C. The C still tends to be heavily platform-specific. */ static const ed25519_impl_t impl_donna = { ed25519_donna_selftest, @@ -89,19 +101,31 @@ static const ed25519_impl_t impl_donna = { ed25519_donna_pubkey_from_curve25519_pubkey, }; +/** Which Ed25519 implementation are we using? NULL if we haven't decided + * yet. */ static const ed25519_impl_t *ed25519_impl = NULL; +/** Helper: Return our chosen Ed25519 implementation. + * + * This should only be called after we've picked an implementation, but + * it _does_ recover if you forget this. + **/ static inline const ed25519_impl_t * get_ed_impl(void) { - if (PREDICT_UNLIKELY(ed25519_impl == NULL)) { - pick_ed25519_impl(); + if (BUG(ed25519_impl == NULL)) { + pick_ed25519_impl(); // LCOV_EXCL_LINE - We always call ed25519_init(). } return ed25519_impl; } #ifdef TOR_UNIT_TESTS +/** For testing: used to remember our actual choice of Ed25519 + * implementation */ static const ed25519_impl_t *saved_ed25519_impl = NULL; +/** For testing: Use the Ed25519 implementation called <b>name</b> until + * crypto_ed25519_testing_restore_impl is called. Recognized names are + * "donna" and "ref10". */ void crypto_ed25519_testing_force_impl(const char *name) { @@ -114,6 +138,9 @@ crypto_ed25519_testing_force_impl(const char *name) ed25519_impl = &impl_ref10; } } +/** For testing: go back to whatever Ed25519 implementation we had picked + * before crypto_ed25519_testing_force_impl was called. + */ void crypto_ed25519_testing_restore_impl(void) { @@ -184,9 +211,43 @@ ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong) return 0; } +/* Return a heap-allocated array that contains <b>msg</b> prefixed by the + * string <b>prefix_str</b>. Set <b>final_msg_len_out</b> to the size of the + * final array. If an error occured, return NULL. It's the resonsibility of the + * caller to free the returned array. */ +static uint8_t * +get_prefixed_msg(const uint8_t *msg, size_t msg_len, + const char *prefix_str, + size_t *final_msg_len_out) +{ + size_t prefixed_msg_len, prefix_len; + uint8_t *prefixed_msg; + + tor_assert(prefix_str); + tor_assert(final_msg_len_out); + + prefix_len = strlen(prefix_str); + + /* msg_len + strlen(prefix_str) must not overflow. */ + if (msg_len > SIZE_T_CEILING - prefix_len) { + return NULL; + } + + prefixed_msg_len = msg_len + prefix_len; + prefixed_msg = tor_malloc_zero(prefixed_msg_len); + + memcpy(prefixed_msg, prefix_str, prefix_len); + memcpy(prefixed_msg + prefix_len, msg, msg_len); + + *final_msg_len_out = prefixed_msg_len; + return prefixed_msg; +} + /** * Set <b>signature_out</b> to a signature of the <b>len</b>-byte message * <b>msg</b>, using the secret and public key in <b>keypair</b>. + * + * Return 0 if we successfuly signed the message, otherwise return -1. */ int ed25519_sign(ed25519_signature_t *signature_out, @@ -203,6 +264,37 @@ ed25519_sign(ed25519_signature_t *signature_out, } /** + * Like ed25519_sign(), but also prefix <b>msg</b> with <b>prefix_str</b> + * before signing. <b>prefix_str</b> must be a NUL-terminated string. + */ +int +ed25519_sign_prefixed(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t msg_len, + const char *prefix_str, + const ed25519_keypair_t *keypair) +{ + int retval; + size_t prefixed_msg_len; + uint8_t *prefixed_msg; + + tor_assert(prefix_str); + + prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, + &prefixed_msg_len); + if (!prefixed_msg) { + log_warn(LD_GENERAL, "Failed to get prefixed msg."); + return -1; + } + + retval = ed25519_sign(signature_out, + prefixed_msg, prefixed_msg_len, + keypair); + tor_free(prefixed_msg); + + return retval; +} + +/** * Check whether if <b>signature</b> is a valid signature for the * <b>len</b>-byte message in <b>msg</b> made with the key <b>pubkey</b>. * @@ -217,6 +309,36 @@ ed25519_checksig(const ed25519_signature_t *signature, get_ed_impl()->open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0; } +/** + * Like ed2519_checksig(), but also prefix <b>msg</b> with <b>prefix_str</b> + * before verifying signature. <b>prefix_str</b> must be a NUL-terminated + * string. + */ +int +ed25519_checksig_prefixed(const ed25519_signature_t *signature, + const uint8_t *msg, size_t msg_len, + const char *prefix_str, + const ed25519_public_key_t *pubkey) +{ + int retval; + size_t prefixed_msg_len; + uint8_t *prefixed_msg; + + prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, + &prefixed_msg_len); + if (!prefixed_msg) { + log_warn(LD_GENERAL, "Failed to get prefixed msg."); + return -1; + } + + retval = ed25519_checksig(signature, + prefixed_msg, prefixed_msg_len, + pubkey); + tor_free(prefixed_msg); + + return retval; +} + /** Validate every signature among those in <b>checkable</b>, which contains * exactly <b>n_checkable</b> elements. If <b>okay_out</b> is non-NULL, set * the i'th element of <b>okay_out</b> to 1 if the i'th element of @@ -259,11 +381,11 @@ ed25519_checksig_batch(int *okay_out, int *oks; int all_ok; - ms = tor_malloc(sizeof(uint8_t*)*n_checkable); - lens = tor_malloc(sizeof(size_t)*n_checkable); - pks = tor_malloc(sizeof(uint8_t*)*n_checkable); - sigs = tor_malloc(sizeof(uint8_t*)*n_checkable); - oks = okay_out ? okay_out : tor_malloc(sizeof(int)*n_checkable); + ms = tor_calloc(n_checkable, sizeof(uint8_t*)); + lens = tor_calloc(n_checkable, sizeof(size_t)); + pks = tor_calloc(n_checkable, sizeof(uint8_t*)); + sigs = tor_calloc(n_checkable, sizeof(uint8_t*)); + oks = okay_out ? okay_out : tor_calloc(n_checkable, sizeof(int)); for (i = 0; i < n_checkable; ++i) { ms[i] = checkable[i].msg; @@ -433,6 +555,7 @@ ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out, errno = EINVAL; } + tor_free(*tag_out); return -1; } @@ -472,6 +595,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, errno = EINVAL; } + tor_free(*tag_out); return -1; } @@ -594,9 +718,12 @@ pick_ed25519_impl(void) if (ed25519_impl_spot_check() == 0) return; + /* LCOV_EXCL_START + * unreachable unless ed25519_donna is broken */ log_warn(LD_CRYPTO, "The Ed25519-donna implementation seems broken; using " "the ref10 implementation."); ed25519_impl = &impl_ref10; + /* LCOV_EXCL_STOP */ } /* Initialize the Ed25519 implementation. This is neccessary if you're diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h index 44c2ad9775..31afc49ccc 100644 --- a/src/common/crypto_ed25519.h +++ b/src/common/crypto_ed25519.h @@ -55,6 +55,17 @@ int ed25519_checksig(const ed25519_signature_t *signature, const uint8_t *msg, size_t len, const ed25519_public_key_t *pubkey); +int +ed25519_sign_prefixed(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t len, + const char *prefix_str, + const ed25519_keypair_t *keypair); +int +ed25519_checksig_prefixed(const ed25519_signature_t *signature, + const uint8_t *msg, size_t len, + const char *prefix_str, + const ed25519_public_key_t *pubkey); + /** * A collection of information necessary to check an Ed25519 signature. Used * for batch verification. diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c index bdf9bfd613..2f6d847c83 100644 --- a/src/common/crypto_format.c +++ b/src/common/crypto_format.c @@ -123,6 +123,10 @@ crypto_read_tagged_contents_from_file(const char *fname, return r; } +/** Encode <b>pkey</b> as a base64-encoded string, without trailing "=" + * characters, in the buffer <b>output</b>, which must have at least + * CURVE25519_BASE64_PADDED_LEN+1 bytes available. Return 0 on success, -1 on + * failure. */ int curve25519_public_to_base64(char *output, const curve25519_public_key_t *pkey) @@ -135,6 +139,9 @@ curve25519_public_to_base64(char *output, return 0; } +/** Try to decode a base64-encoded curve25519 public key from <b>input</b> + * into the object at <b>pkey</b>. Return 0 on success, -1 on failure. + * Accepts keys with or without a trailing "=". */ int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input) diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c index 819dc0c39d..31e37c007d 100644 --- a/src/common/crypto_pwbox.c +++ b/src/common/crypto_pwbox.c @@ -61,7 +61,7 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, pwbox_encoded_getarray_skey_header(enc), S2K_MAXLEN, s2k_flags); - if (spec_len < 0 || spec_len > S2K_MAXLEN) + if (BUG(spec_len < 0 || spec_len > S2K_MAXLEN)) goto err; pwbox_encoded_setlen_skey_header(enc, spec_len); enc->header_len = spec_len; @@ -76,10 +76,11 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, /* Now that all the data is in position, derive some keys, encrypt, and * digest */ - if (secret_to_key_derivekey(keys, sizeof(keys), + const int s2k_rv = secret_to_key_derivekey(keys, sizeof(keys), pwbox_encoded_getarray_skey_header(enc), spec_len, - secret, secret_len) < 0) + secret, secret_len); + if (BUG(s2k_rv < 0)) goto err; cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); @@ -87,11 +88,11 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, crypto_cipher_free(cipher); result_len = pwbox_encoded_encoded_len(enc); - if (result_len < 0) + if (BUG(result_len < 0)) goto err; result = tor_malloc(result_len); enc_len = pwbox_encoded_encode(result, result_len, enc); - if (enc_len < 0) + if (BUG(enc_len < 0)) goto err; tor_assert(enc_len == result_len); @@ -107,9 +108,24 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, goto out; err: + /* LCOV_EXCL_START + + This error case is often unreachable if we're correctly coded, unless + somebody adds a new error case somewhere, or unless you're building + without scrypto support. + + - make_specifier can't fail, unless S2K_MAX_LEN is too short. + - secret_to_key_derivekey can't really fail unless we're missing + scrypt, or the underlying function fails, or we pass it a bogus + algorithm or parameters. + - pwbox_encoded_encoded_len can't fail unless we're using trunnel + incorrectly. + - pwbox_encoded_encode can't fail unless we're using trunnel wrong, + or it's buggy. + */ tor_free(result); rv = -1; - + /* LCOV_EXCL_STOP */ out: pwbox_encoded_free(enc); memwipe(keys, 0, sizeof(keys)); diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c index 3bc05f1cf9..5dbd2ad91f 100644 --- a/src/common/crypto_s2k.c +++ b/src/common/crypto_s2k.c @@ -57,7 +57,8 @@ #define SCRYPT_KEY_LEN 32 /** Given an algorithm ID (one of S2K_TYPE_*), return the length of the - * specifier part of it, without the prefix type byte. */ + * specifier part of it, without the prefix type byte. Return -1 if it is not + * a valid algorithm ID. */ static int secret_to_key_spec_len(uint8_t type) { @@ -86,7 +87,8 @@ secret_to_key_key_len(uint8_t type) case S2K_TYPE_SCRYPT: return DIGEST256_LEN; default: - return -1; + tor_fragile_assert(); // LCOV_EXCL_LINE + return -1; // LCOV_EXCL_LINE } } @@ -168,7 +170,7 @@ make_specifier(uint8_t *spec_out, uint8_t type, unsigned flags) spec_out[SCRYPT_SPEC_LEN-1] = (3u << 4) | (1u << 0); break; default: - tor_fragile_assert(); + tor_fragile_assert(); // LCOV_EXCL_LINE - we should have returned above. return S2K_BAD_ALGORITHM; } diff --git a/src/common/di_ops.c b/src/common/di_ops.c index 5dfe828066..4ed49e1164 100644 --- a/src/common/di_ops.c +++ b/src/common/di_ops.c @@ -226,3 +226,49 @@ safe_mem_is_zero(const void *mem, size_t sz) return 1 & ((total - 1) >> 8); } +/** Time-invariant 64-bit greater-than; works on two integers in the range + * (0,INT64_MAX). */ +#if SIZEOF_VOID_P == 8 +#define gt_i64_timei(a,b) ((a) > (b)) +#else +static inline int +gt_i64_timei(uint64_t a, uint64_t b) +{ + int64_t diff = (int64_t) (b - a); + int res = diff >> 63; + return res & 1; +} +#endif + +/** + * Given an array of list of <b>n_entries</b> uint64_t values, whose sum is + * <b>total</b>, find the first i such that the total of all elements 0...i is + * greater than rand_val. + * + * Try to perform this operation in a constant-time way. + */ +int +select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, + uint64_t total, uint64_t rand_val) +{ + int i, i_chosen=-1, n_chosen=0; + uint64_t total_so_far = 0; + + for (i = 0; i < n_entries; ++i) { + total_so_far += entries[i]; + if (gt_i64_timei(total_so_far, rand_val)) { + i_chosen = i; + n_chosen++; + /* Set rand_val to INT64_MAX rather than stopping the loop. This way, + * the time we spend in the loop does not leak which element we chose. */ + rand_val = INT64_MAX; + } + } + tor_assert(total_so_far == total); + tor_assert(n_chosen == 1); + tor_assert(i_chosen >= 0); + tor_assert(i_chosen < n_entries); + + return i_chosen; +} + diff --git a/src/common/di_ops.h b/src/common/di_ops.h index 6e77b5cfd7..0a154302bf 100644 --- a/src/common/di_ops.h +++ b/src/common/di_ops.h @@ -42,6 +42,9 @@ void dimap_add_entry(di_digest256_map_t **map, const uint8_t *key, void *val); void *dimap_search(const di_digest256_map_t *map, const uint8_t *key, void *dflt_val); +int select_array_member_cumulative_timei(const uint64_t *entries, + int n_entries, + uint64_t total, uint64_t rand_val); #endif diff --git a/src/common/handles.h b/src/common/handles.h new file mode 100644 index 0000000000..1ee2322579 --- /dev/null +++ b/src/common/handles.h @@ -0,0 +1,153 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file handles.h + * \brief Macros for C weak-handle implementation. + * + * A 'handle' is a pointer to an object that is allowed to go away while + * the handle stays alive. When you dereference the handle, you might get + * the object, or you might get "NULL". + * + * Use this pattern when an object has a single obvious lifespan, so you don't + * want to use reference counting, but when other objects might need to refer + * to the first object without caring about its lifetime. + * + * To enable a type to have handles, add a HANDLE_ENTRY() field in its + * definition, as in: + * + * struct walrus { + * HANDLE_ENTRY(wlr, walrus); + * // ... + * }; + * + * And invoke HANDLE_DECL(wlr, walrus, [static]) to declare the handle + * manipulation functions (typically in a header): + * + * // opaque handle to walrus. + * typedef struct wlr_handle_t wlr_handle_t; + * + * // make a new handle + * struct wlr_handle_t *wlr_handle_new(struct walrus *); + * + * // release a handle + * void wlr_handle_free(wlr_handle_t *); + * + * // return the pointed-to walrus, or NULL. + * struct walrus *wlr_handle_get(wlr_handle_t *). + * + * // call this function when you're about to free the walrus; + * // it invalidates all handles. (IF YOU DON'T, YOU WILL HAVE + * // DANGLING REFERENCES) + * void wlr_handles_clear(struct walrus *); + * + * Finally, use HANDLE_IMPL() to define the above functions in some + * appropriate C file: HANDLE_IMPL(wlr, walrus, [static]) + * + **/ + +#ifndef TOR_HANDLE_H +#define TOR_HANDLE_H + +#include "orconfig.h" +#include "tor_queue.h" +#include "util.h" + +#define HANDLE_ENTRY(name, structname) \ + struct name ## _handle_head_t *handle_head + +#define HANDLE_DECL(name, structname, linkage) \ + typedef struct name ## _handle_t name ## _handle_t; \ + linkage name ## _handle_t *name ## _handle_new(struct structname *object); \ + linkage void name ## _handle_free(name ## _handle_t *); \ + linkage struct structname *name ## _handle_get(name ## _handle_t *); \ + linkage void name ## _handles_clear(struct structname *object); + +/* + * Implementation notes: there are lots of possible implementations here. We + * could keep a linked list of handles, each with a backpointer to the object, + * and set all of their backpointers to NULL when the object is freed. Or we + * could have the clear function invalidate the object, but not actually let + * the object get freed until the all the handles went away. We could even + * have a hash-table mapping unique identifiers to objects, and have each + * handle be a copy of the unique identifier. (We'll want to build that last + * one eventually if we want cross-process handles.) + * + * But instead we're opting for a single independent 'head' that knows how + * many handles there are, and where the object is (or isn't). This makes + * all of our functions O(1), and most as fast as a single pointer access. + * + * The handles themselves are opaque structures holding a pointer to the head. + * We could instead have each foo_handle_t* be identical to foo_handle_head_t + * *, and save some allocations ... but doing so would make handle leaks + * harder to debug. As it stands, every handle leak is a memory leak, and + * existing memory debugging tools should help with those. We can revisit + * this decision if handles are too slow. + */ + +#define HANDLE_IMPL(name, structname, linkage) \ + /* The 'head' object for a handle-accessible type. This object */ \ + /* persists for as long as the object, or any handles, exist. */ \ + typedef struct name ## _handle_head_t { \ + struct structname *object; /* pointed-to object, or NULL */ \ + unsigned int references; /* number of existing handles */ \ + } name ## _handle_head_t; \ + \ + struct name ## _handle_t { \ + struct name ## _handle_head_t *head; /* reference to the 'head'. */ \ + }; \ + \ + linkage struct name ## _handle_t * \ + name ## _handle_new(struct structname *object) \ + { \ + tor_assert(object); \ + name ## _handle_head_t *head = object->handle_head; \ + if (PREDICT_UNLIKELY(head == NULL)) { \ + head = object->handle_head = tor_malloc_zero(sizeof(*head)); \ + head->object = object; \ + } \ + name ## _handle_t *new_ref = tor_malloc_zero(sizeof(*new_ref)); \ + new_ref->head = head; \ + ++head->references; \ + return new_ref; \ + } \ + \ + linkage void \ + name ## _handle_free(struct name ## _handle_t *ref) \ + { \ + if (! ref) return; \ + name ## _handle_head_t *head = ref->head; \ + tor_assert(head); \ + --head->references; \ + tor_free(ref); \ + if (head->object == NULL && head->references == 0) { \ + tor_free(head); \ + return; \ + } \ + } \ + \ + linkage struct structname * \ + name ## _handle_get(struct name ## _handle_t *ref) \ + { \ + tor_assert(ref); \ + name ## _handle_head_t *head = ref->head; \ + tor_assert(head); \ + return head->object; \ + } \ + \ + linkage void \ + name ## _handles_clear(struct structname *object) \ + { \ + tor_assert(object); \ + name ## _handle_head_t *head = object->handle_head; \ + if (! head) \ + return; \ + object->handle_head = NULL; \ + head->object = NULL; \ + if (head->references == 0) { \ + tor_free(head); \ + } \ + } + +#endif /* TOR_HANDLE_H */ + diff --git a/src/common/include.am b/src/common/include.am index 5afb30da6a..40c463c9d9 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -1,12 +1,14 @@ noinst_LIBRARIES += \ src/common/libor.a \ + src/common/libor-ctime.a \ src/common/libor-crypto.a \ src/common/libor-event.a if UNITTESTS_ENABLED noinst_LIBRARIES += \ src/common/libor-testing.a \ + src/common/libor-ctime-testing.a \ src/common/libor-crypto-testing.a \ src/common/libor-event-testing.a endif @@ -27,12 +29,14 @@ src_common_libcurve25519_donna_a_CFLAGS= if BUILD_CURVE25519_DONNA src_common_libcurve25519_donna_a_SOURCES=\ src/ext/curve25519_donna/curve25519-donna.c +# See bug 13538 -- this code is known to have signed overflow issues. src_common_libcurve25519_donna_a_CFLAGS+=\ - @F_OMIT_FRAME_POINTER@ + @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ noinst_LIBRARIES+=src/common/libcurve25519_donna.a LIBDONNA=src/common/libcurve25519_donna.a else if BUILD_CURVE25519_DONNA_C64 +src_common_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@ src_common_libcurve25519_donna_a_SOURCES=\ src/ext/curve25519_donna/curve25519-donna-c64.c noinst_LIBRARIES+=src/common/libcurve25519_donna.a @@ -58,22 +62,38 @@ else readpassphrase_source= endif -LIBOR_A_SOURCES = \ +if ADD_MULODI4 +mulodi4_source=src/ext/mulodi/mulodi4.c +else +mulodi4_source= +endif + +LIBOR_CTIME_A_SRC = \ + $(mulodi4_source) \ + src/ext/csiphash.c \ + src/common/di_ops.c + +src_common_libor_ctime_a_SOURCES = $(LIBOR_CTIME_A_SRC) +src_common_libor_ctime_testing_a_SOURCES = $(LIBOR_CTIME_A_SRC) +src_common_libor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ +src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) + +LIBOR_A_SRC = \ src/common/address.c \ src/common/backtrace.c \ src/common/compat.c \ src/common/compat_threads.c \ + src/common/compat_time.c \ src/common/container.c \ - src/common/di_ops.c \ src/common/log.c \ src/common/memarea.c \ + src/common/pubsub.c \ src/common/util.c \ + src/common/util_bug.c \ src/common/util_format.c \ src/common/util_process.c \ src/common/sandbox.c \ src/common/workqueue.c \ - src/ext/csiphash.c \ - src/ext/trunnel/trunnel.c \ $(libor_extra_source) \ $(threads_impl_source) \ $(readpassphrase_source) @@ -81,7 +101,7 @@ LIBOR_A_SOURCES = \ src/common/src_common_libor_testing_a-log.$(OBJEXT) \ src/common/log.$(OBJEXT): micro-revision.i -LIBOR_CRYPTO_A_SOURCES = \ +LIBOR_CRYPTO_A_SRC = \ src/common/aes.c \ src/common/crypto.c \ src/common/crypto_pwbox.c \ @@ -89,21 +109,22 @@ LIBOR_CRYPTO_A_SOURCES = \ src/common/crypto_format.c \ src/common/torgzip.c \ src/common/tortls.c \ - src/trunnel/pwbox.c \ src/common/crypto_curve25519.c \ src/common/crypto_ed25519.c -LIBOR_EVENT_A_SOURCES = \ +LIBOR_EVENT_A_SRC = \ src/common/compat_libevent.c \ - src/common/procmon.c + src/common/procmon.c \ + src/common/timers.c \ + src/ext/timeouts/timeout.c -src_common_libor_a_SOURCES = $(LIBOR_A_SOURCES) -src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES) -src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SOURCES) +src_common_libor_a_SOURCES = $(LIBOR_A_SRC) +src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) +src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SRC) -src_common_libor_testing_a_SOURCES = $(LIBOR_A_SOURCES) -src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES) -src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SOURCES) +src_common_libor_testing_a_SOURCES = $(LIBOR_A_SRC) +src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) +src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SRC) src_common_libor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_common_libor_crypto_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) @@ -121,6 +142,7 @@ COMMONHEADERS = \ src/common/compat_libevent.h \ src/common/compat_openssl.h \ src/common/compat_threads.h \ + src/common/compat_time.h \ src/common/container.h \ src/common/crypto.h \ src/common/crypto_curve25519.h \ @@ -129,16 +151,20 @@ COMMONHEADERS = \ src/common/crypto_pwbox.h \ src/common/crypto_s2k.h \ src/common/di_ops.h \ + src/common/handles.h \ src/common/memarea.h \ src/common/linux_syscalls.inc \ src/common/procmon.h \ + src/common/pubsub.h \ src/common/sandbox.h \ src/common/testsupport.h \ + src/common/timers.h \ src/common/torgzip.h \ src/common/torint.h \ src/common/torlog.h \ src/common/tortls.h \ src/common/util.h \ + src/common/util_bug.h \ src/common/util_format.h \ src/common/util_process.h \ src/common/workqueue.h diff --git a/src/common/log.c b/src/common/log.c index 6c387c6244..56adc77f84 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -47,6 +47,8 @@ #define TRUNCATED_STR_LEN 14 /** @} */ +#define raw_assert(x) assert(x) // assert OK + /** Information for a single logfile; only used in log.c */ typedef struct logfile_t { struct logfile_t *next; /**< Next logfile_t in the linked list. */ @@ -75,7 +77,7 @@ sev_to_string(int severity) case LOG_ERR: return "err"; default: /* Call assert, not tor_assert, since tor_assert * calls log on failure. */ - assert(0); return "UNKNOWN"; + raw_assert(0); return "UNKNOWN"; // LCOV_EXCL_LINE } } @@ -95,7 +97,7 @@ should_log_function_name(log_domain_mask_t domain, int severity) return (domain & (LD_BUG|LD_NOFUNCNAME)) == LD_BUG; default: /* Call assert, not tor_assert, since tor_assert calls log on failure. */ - assert(0); return 0; + raw_assert(0); return 0; // LCOV_EXCL_LINE } } @@ -270,7 +272,7 @@ log_tor_version(logfile_t *lf, int reset) return 0; } -const char bug_suffix[] = " (on Tor " VERSION +static const char bug_suffix[] = " (on Tor " VERSION #ifndef _MSC_VER " " #include "micro-revision.i" @@ -293,7 +295,7 @@ format_msg(char *buf, size_t buf_len, char *end_of_prefix; char *buf_end; - assert(buf_len >= 16); /* prevent integer underflow and general stupidity */ + raw_assert(buf_len >= 16); /* prevent integer underflow and stupidity */ buf_len -= 2; /* subtract 2 characters so we have room for \n\0 */ buf_end = buf+buf_len; /* point *after* the last char we can write to */ @@ -482,12 +484,12 @@ logv,(int severity, log_domain_mask_t domain, const char *funcname, int callbacks_deferred = 0; /* Call assert, not tor_assert, since tor_assert calls log on failure. */ - assert(format); + raw_assert(format); /* check that severity is sane. Overrunning the masks array leads to * interesting and hard to diagnose effects */ - assert(severity >= LOG_ERR && severity <= LOG_DEBUG); + raw_assert(severity >= LOG_ERR && severity <= LOG_DEBUG); /* check that we've initialised the log mutex before we try to lock it */ - assert(log_mutex_initialized); + raw_assert(log_mutex_initialized); LOCK_LOGS(); if ((! (domain & LD_NOCB)) && pending_cb_messages @@ -534,6 +536,11 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...) if (severity > log_global_min_severity_) return; va_start(ap,format); +#ifdef TOR_UNIT_TESTS + if (domain & LD_NO_MOCK) + logv__real(severity, domain, NULL, NULL, format, ap); + else +#endif logv(severity, domain, NULL, NULL, format, ap); va_end(ap); } @@ -653,7 +660,7 @@ tor_log_update_sigsafe_err_fds(void) if (!found_real_stderr && int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) { /* Don't use a virtual stderr when we're also logging to stdout. */ - assert(n_sigsafe_log_fds >= 2); /* Don't use assert inside log functions*/ + raw_assert(n_sigsafe_log_fds >= 2); /* Don't tor_assert inside log fns */ sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds]; } @@ -1071,13 +1078,13 @@ mark_logs_temp(void) */ int add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate) + const int truncate_log) { int fd; logfile_t *lf; int open_flags = O_WRONLY|O_CREAT; - open_flags |= truncate ? O_TRUNC : O_APPEND; + open_flags |= truncate_log ? O_TRUNC : O_APPEND; fd = tor_open_cloexec(filename, open_flags, 0644); if (fd<0) diff --git a/src/common/memarea.c b/src/common/memarea.c index 173ed4e1cb..7d16b702e3 100644 --- a/src/common/memarea.c +++ b/src/common/memarea.c @@ -131,7 +131,7 @@ alloc_chunk(size_t sz) /** Release <b>chunk</b> from a memarea. */ static void -chunk_free_unchecked(memarea_chunk_t *chunk) +memarea_chunk_free_unchecked(memarea_chunk_t *chunk) { CHECK_SENTINEL(chunk); tor_free(chunk); @@ -154,7 +154,7 @@ memarea_drop_all(memarea_t *area) memarea_chunk_t *chunk, *next; for (chunk = area->first; chunk; chunk = next) { next = chunk->next_chunk; - chunk_free_unchecked(chunk); + memarea_chunk_free_unchecked(chunk); } area->first = NULL; /*fail fast on */ tor_free(area); @@ -170,7 +170,7 @@ memarea_clear(memarea_t *area) if (area->first->next_chunk) { for (chunk = area->first->next_chunk; chunk; chunk = next) { next = chunk->next_chunk; - chunk_free_unchecked(chunk); + memarea_chunk_free_unchecked(chunk); } area->first->next_chunk = NULL; } diff --git a/src/common/procmon.c b/src/common/procmon.c index 12d53fcd41..c485c760c7 100644 --- a/src/common/procmon.c +++ b/src/common/procmon.c @@ -10,11 +10,7 @@ #include "util.h" -#ifdef HAVE_EVENT2_EVENT_H #include <event2/event.h> -#else -#include <event.h> -#endif #ifdef HAVE_SIGNAL_H #include <signal.h> @@ -116,11 +112,11 @@ struct tor_process_monitor_t { * periodically check whether the process we have a handle to has * ended. */ HANDLE hproc; - /* XXX023 We can and should have Libevent watch hproc for us, - * if/when some version of Libevent 2.x can be told to do so. */ + /* XXXX We should have Libevent watch hproc for us, + * if/when some version of Libevent can be told to do so. */ #endif - /* XXX023 On Linux, we can and should receive the 22nd + /* XXXX On Linux, we can and should receive the 22nd * (space-delimited) field (‘starttime’) of /proc/$PID/stat from the * owning controller and store it, and poll once in a while to see * whether it has changed -- if so, the kernel has *definitely* @@ -130,7 +126,8 @@ struct tor_process_monitor_t { * systems whose admins have mounted procfs, or the start-time field * of the process-information structure returned by kvmgetprocs() on * any system. The latter is ickier. */ - /* XXX023 On FreeBSD (and possibly other kqueue systems), we can and + + /* XXXX On FreeBSD (and possibly other kqueue systems), we can and * should arrange to receive EVFILT_PROC NOTE_EXIT notifications for * pid, so we don't have to do such a heavyweight poll operation in * order to avoid the PID-reassignment race condition. (We would @@ -163,18 +160,10 @@ tor_validate_process_specifier(const char *process_spec, } /* XXXX we should use periodic_timer_new() for this stuff */ -#ifdef HAVE_EVENT2_EVENT_H #define PERIODIC_TIMER_FLAGS EV_PERSIST -#else -#define PERIODIC_TIMER_FLAGS (0) -#endif /* DOCDOC poll_interval_tv */ -static struct timeval poll_interval_tv = {15, 0}; -/* Note: If you port this file to plain Libevent 2, you can make - * poll_interval_tv const. It has to be non-const here because in - * libevent 1.x, event_add expects a pointer to a non-const struct - * timeval. */ +static const struct timeval poll_interval_tv = {15, 0}; /** Create a process-termination monitor for the process specifier * given in <b>process_spec</b>. Return a newly allocated @@ -330,10 +319,6 @@ tor_process_monitor_poll_cb(evutil_socket_t unused1, short unused2, if (its_dead_jim) { procmon->cb(procmon->cb_arg); -#ifndef HAVE_EVENT2_EVENT_H - } else { - evtimer_add(procmon->e, &poll_interval_tv); -#endif } } #endif diff --git a/src/common/pubsub.c b/src/common/pubsub.c new file mode 100644 index 0000000000..b3faf40e00 --- /dev/null +++ b/src/common/pubsub.c @@ -0,0 +1,129 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file pubsub.c + * + * \brief DOCDOC + */ + +#include "orconfig.h" +#include "pubsub.h" +#include "container.h" + +/** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping + * them sorted in priority order. */ +static void +subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s) +{ + int i; + smartlist_t *sl = topic->subscribers; + for (i = 0; i < smartlist_len(sl); ++i) { + pubsub_subscriber_t *other = smartlist_get(sl, i); + if (s->priority < other->priority) { + break; + } + } + smartlist_insert(sl, i, s); +} + +/** + * Add a new subscriber to <b>topic</b>, where (when an event is triggered), + * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>. + * Return a handle to the subscribe which can later be passed to + * pubsub_unsubscribe_(). + * + * Functions are called in priority order, from lowest to highest. + * + * See pubsub.h for <b>subscribe_flags</b>. + */ +const pubsub_subscriber_t * +pubsub_subscribe_(pubsub_topic_t *topic, + pubsub_subscriber_fn_t fn, + void *subscriber_data, + unsigned subscribe_flags, + unsigned priority) +{ + tor_assert(! topic->locked); + if (subscribe_flags & SUBSCRIBE_ATSTART) { + tor_assert(topic->n_events_fired == 0); + } + pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r)); + r->priority = priority; + r->subscriber_flags = subscribe_flags; + r->fn = fn; + r->subscriber_data = subscriber_data; + if (topic->subscribers == NULL) { + topic->subscribers = smartlist_new(); + } + subscriber_insert(topic, r); + return r; +} + +/** + * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this + * function, <b>s</b> may no longer be used. + */ +int +pubsub_unsubscribe_(pubsub_topic_t *topic, + const pubsub_subscriber_t *s) +{ + tor_assert(! topic->locked); + smartlist_t *sl = topic->subscribers; + if (sl == NULL) + return -1; + int i = smartlist_pos(sl, s); + if (i == -1) + return -1; + pubsub_subscriber_t *tmp = smartlist_get(sl, i); + tor_assert(tmp == s); + smartlist_del_keeporder(sl, i); + tor_free(tmp); + return 0; +} + +/** + * For every subscriber s in <b>topic</b>, invoke notify_fn on s and + * event_data. Return 0 if there were no nonzero return values, and -1 if + * there were any. + */ +int +pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, + void *event_data, unsigned notify_flags) +{ + tor_assert(! topic->locked); + (void) notify_flags; + smartlist_t *sl = topic->subscribers; + int n_bad = 0; + ++topic->n_events_fired; + if (sl == NULL) + return -1; + topic->locked = 1; + SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { + int r = notify_fn(s, event_data); + if (r != 0) + ++n_bad; + } SMARTLIST_FOREACH_END(s); + topic->locked = 0; + return (n_bad == 0) ? 0 : -1; +} + +/** + * Release all storage held by <b>topic</b>. + */ +void +pubsub_clear_(pubsub_topic_t *topic) +{ + tor_assert(! topic->locked); + + smartlist_t *sl = topic->subscribers; + if (sl == NULL) + return; + SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { + tor_free(s); + } SMARTLIST_FOREACH_END(s); + smartlist_free(sl); + topic->subscribers = NULL; + topic->n_events_fired = 0; +} + diff --git a/src/common/pubsub.h b/src/common/pubsub.h new file mode 100644 index 0000000000..bbb4f02a42 --- /dev/null +++ b/src/common/pubsub.h @@ -0,0 +1,179 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file pubsub.h + * \brief Macros to implement publish/subscribe abstractions. + * + * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use + * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T). + * + * Doing this will declare the following types: + * typedef struct T_event_data_t T_event_data_t; // you define this struct + * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too. + * typedef struct T_subscriber_t T_subscriber_t; // opaque + * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*); + * + * and it will declare the following functions: + * const T_subscriber_t *T_subscribe(T_subscriber_fn_t, + * T_subscriber_data_t *, + * unsigned flags, + * unsigned priority); + * int T_unsubscribe(const T_subscriber_t *) + * + * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which + * declares: + * + * static int T_notify(T_event_data_t *, unsigned notify_flags); + * static void T_clear(void); + * + * And in some C file, you would define these functions with: + * IMPLEMENT_PUBSUB_TOPIC(static, T). + * + * The implementations will be small typesafe wrappers over generic versions + * of the above functions. + * + * To use the typesafe functions, you add any number of subscribers with + * T_subscribe(). Each has an associated function pointer, data pointer, + * and priority. Later, you can invoke T_notify() to declare that the + * event has occurred. Each of the subscribers will be invoked once. + **/ + +#ifndef TOR_PUBSUB_H +#define TOR_PUBSUB_H + +#include "torint.h" + +/** + * Flag for T_subscribe: die with an assertion failure if the event + * have ever been published before. Used when a subscriber must absolutely + * never have missed an event. + */ +#define SUBSCRIBE_ATSTART (1u<<0) + +#define DECLARE_PUBSUB_STRUCT_TYPES(name) \ + /* You define this type. */ \ + typedef struct name ## _event_data_t name ## _event_data_t; \ + /* You define this type. */ \ + typedef struct name ## _subscriber_data_t name ## _subscriber_data_t; + +#define DECLARE_PUBSUB_TOPIC(name) \ + /* This type is opaque. */ \ + typedef struct name ## _subscriber_t name ## _subscriber_t; \ + /* You declare functions matching this type. */ \ + typedef int (*name ## _subscriber_fn_t)( \ + name ## _event_data_t *data, \ + name ## _subscriber_data_t *extra); \ + /* Call this function to subscribe to a topic. */ \ + const name ## _subscriber_t *name ## _subscribe( \ + name##_subscriber_fn_t subscriber, \ + name##_subscriber_data_t *extra_data, \ + unsigned flags, \ + unsigned priority); \ + /* Call this function to unsubscribe from a topic. */ \ + int name ## _unsubscribe(const name##_subscriber_t *s); + +#define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \ + /* Call this function to notify all subscribers. Flags not yet used. */ \ + linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \ + /* Call this function to release storage held by the topic. */ \ + linkage void name ## _clear(void); + +/** + * Type used to hold a generic function for a subscriber. + * + * [Yes, it is safe to cast to this, so long as we cast back to the original + * type before calling. From C99: "A pointer to a function of one type may be + * converted to a pointer to a function of another type and back again; the + * result shall compare equal to the original pointer."] +*/ +typedef int (*pubsub_subscriber_fn_t)(void *, void *); + +/** + * Helper type to implement pubsub abstraction. Don't use this directly. + * It represents a subscriber. + */ +typedef struct pubsub_subscriber_t { + /** Function to invoke when the event triggers. */ + pubsub_subscriber_fn_t fn; + /** Data associated with this subscriber. */ + void *subscriber_data; + /** Priority for this subscriber. Low priorities happen first. */ + unsigned priority; + /** Flags set on this subscriber. Not yet used.*/ + unsigned subscriber_flags; +} pubsub_subscriber_t; + +/** + * Helper type to implement pubsub abstraction. Don't use this directly. + * It represents a topic, and keeps a record of subscribers. + */ +typedef struct pubsub_topic_t { + /** List of subscribers to this topic. May be NULL. */ + struct smartlist_t *subscribers; + /** Total number of times that pubsub_notify_() has ever been called on this + * topic. */ + uint64_t n_events_fired; + /** True iff we're running 'notify' on this topic, and shouldn't allow + * any concurrent modifications or events. */ + unsigned locked; +} pubsub_topic_t; + +const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic, + pubsub_subscriber_fn_t fn, + void *subscriber_data, + unsigned subscribe_flags, + unsigned priority); +int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub); +void pubsub_clear_(pubsub_topic_t *topic); +typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber, + void *notify_data); +int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, + void *notify_data, unsigned notify_flags); + +#define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \ + static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \ + const name ## _subscriber_t * \ + name ## _subscribe(name##_subscriber_fn_t subscriber, \ + name##_subscriber_data_t *extra_data, \ + unsigned flags, \ + unsigned priority) \ + { \ + const pubsub_subscriber_t *s; \ + s = pubsub_subscribe_(&name##_topic_, \ + (pubsub_subscriber_fn_t)subscriber, \ + extra_data, \ + flags, \ + priority); \ + return (const name##_subscriber_t *)s; \ + } \ + int \ + name ## _unsubscribe(const name##_subscriber_t *subscriber) \ + { \ + return pubsub_unsubscribe_(&name##_topic_, \ + (const pubsub_subscriber_t *)subscriber); \ + } \ + static int \ + name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \ + void *notify_data) \ + { \ + name ## _subscriber_fn_t fn; \ + fn = (name ## _subscriber_fn_t) subscriber->fn; \ + return fn(notify_data, subscriber->subscriber_data); \ + } \ + notify_linkage int \ + name ## _notify(name ## _event_data_t *event_data, unsigned flags) \ + { \ + return pubsub_notify_(&name##_topic_, \ + name##_call_the_notify_fn_, \ + event_data, \ + flags); \ + } \ + notify_linkage void \ + name ## _clear(void) \ + { \ + pubsub_clear_(&name##_topic_); \ + } + +#endif /* TOR_PUBSUB_H */ + diff --git a/src/common/sandbox.c b/src/common/sandbox.c index 74187e5d63..da96ad8248 100644 --- a/src/common/sandbox.c +++ b/src/common/sandbox.c @@ -39,8 +39,6 @@ #if defined(USE_LIBSECCOMP) -#define _GNU_SOURCE - #include <sys/mman.h> #include <sys/syscall.h> #include <sys/types.h> @@ -138,6 +136,9 @@ static int filter_nopar_gen[] = { #ifdef HAVE_PIPE SCMP_SYS(pipe), #endif +#ifdef __NR_fchmod + SCMP_SYS(fchmod), +#endif SCMP_SYS(fcntl), SCMP_SYS(fstat), #ifdef __NR_fstat64 @@ -157,6 +158,7 @@ static int filter_nopar_gen[] = { #ifdef __NR_getgid32 SCMP_SYS(getgid32), #endif + SCMP_SYS(getpid), #ifdef __NR_getrlimit SCMP_SYS(getrlimit), #endif @@ -186,11 +188,17 @@ static int filter_nopar_gen[] = { SCMP_SYS(read), SCMP_SYS(rt_sigreturn), SCMP_SYS(sched_getaffinity), +#ifdef __NR_sched_yield + SCMP_SYS(sched_yield), +#endif SCMP_SYS(sendmsg), SCMP_SYS(set_robust_list), #ifdef __NR_setrlimit SCMP_SYS(setrlimit), #endif +#ifdef __NR_sigaltstack + SCMP_SYS(sigaltstack), +#endif #ifdef __NR_sigreturn SCMP_SYS(sigreturn), #endif @@ -840,7 +848,7 @@ sb_epoll_ctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } /** - * Function responsible for setting up the fcntl64 syscall for + * Function responsible for setting up the prctl syscall for * the seccomp filter sandbox. * * NOTE: if multiple filters need to be added, the PR_SECCOMP parameter needs @@ -861,7 +869,7 @@ sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } /** - * Function responsible for setting up the fcntl64 syscall for + * Function responsible for setting up the mprotect syscall for * the seccomp filter sandbox. * * NOTE: does not NEED to be here.. currently only occurs before filter; will @@ -1260,7 +1268,7 @@ prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg) /** * Auxiliary function used in order to allocate a sandbox_cfg_t element and set - * it's values according the the parameter list. All elements are initialised + * its values according the parameter list. All elements are initialised * with the 'prot' field set to false, as the pointer is not protected at this * point. */ @@ -1462,7 +1470,7 @@ static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t) HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node, cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq); + cached_getaddrinfo_items_eq) HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node, cached_getaddrinfo_item_hash, cached_getaddrinfo_items_eq, @@ -1575,13 +1583,14 @@ sandbox_add_addrinfo(const char *name) void sandbox_free_getaddrinfo_cache(void) { - cached_getaddrinfo_item_t **next, **item; + cached_getaddrinfo_item_t **next, **item, *this; for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache); item; item = next) { + this = *item; next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item); - cached_getaddrinfo_item_free(*item); + cached_getaddrinfo_item_free(this); } HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache); diff --git a/src/common/sandbox.h b/src/common/sandbox.h index 2defd8bbd4..c5963e3119 100644 --- a/src/common/sandbox.h +++ b/src/common/sandbox.h @@ -39,12 +39,6 @@ typedef struct sandbox_cfg_elem sandbox_cfg_t; */ #ifdef USE_LIBSECCOMP -#ifndef __USE_GNU -#define __USE_GNU -#endif -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif #include <sys/ucontext.h> #include <seccomp.h> #include <netdb.h> diff --git a/src/common/testsupport.h b/src/common/testsupport.h index 3bb11a7e41..9ad2ba77e0 100644 --- a/src/common/testsupport.h +++ b/src/common/testsupport.h @@ -6,8 +6,10 @@ #ifdef TOR_UNIT_TESTS #define STATIC +#define EXTERN(type, name) extern type name; #else #define STATIC static +#define EXTERN(type, name) #endif /** Quick and dirty macros to implement test mocking. @@ -60,6 +62,12 @@ #define MOCK_IMPL(rv, funcname, arglist) \ rv(*funcname) arglist = funcname ##__real; \ rv funcname ##__real arglist +#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \ + rv funcname ##__real arglist attr; \ + extern rv(*funcname) arglist +#define MOCK_IMPL(rv, funcname, arglist) \ + rv(*funcname) arglist = funcname ##__real; \ + rv funcname ##__real arglist #define MOCK(func, replacement) \ do { \ (func) = (replacement); \ @@ -71,6 +79,8 @@ #else #define MOCK_DECL(rv, funcname, arglist) \ rv funcname arglist +#define MOCK_DECL_ATTR(rv, funcname, arglist, attr) \ + rv funcname arglist attr #define MOCK_IMPL(rv, funcname, arglist) \ rv funcname arglist #endif diff --git a/src/common/timers.c b/src/common/timers.c new file mode 100644 index 0000000000..41b2008ac4 --- /dev/null +++ b/src/common/timers.c @@ -0,0 +1,293 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file timers.c + * \brief Wrapper around William Ahern's fast hierarchical timer wheel + * implementation, to tie it in with a libevent backend. + * + * Only use these functions from the main thread. + * + * The main advantage of tor_timer_t over using libevent's timers is that + * they're way more efficient if we need to have thousands or millions of + * them. For more information, see + * http://www.25thandclement.com/~william/projects/timeout.c.html + * + * Periodic timers are available in the backend, but I've turned them off. + * We can turn them back on if needed. + */ + +/* Notes: + * + * Having a way to free all timers on shutdown would free people from the + * need to track them. Not sure if that's clever though. + * + * In an ideal world, Libevent would just switch to use this backend, and we + * could throw this file away. But even if Libevent does switch, we'll be + * stuck with legacy libevents for some time. + */ + +#include "orconfig.h" + +#include "compat.h" +#include "compat_libevent.h" +#include "timers.h" +#include "torlog.h" +#include "util.h" + +#include <event2/event.h> + +struct timeout_cb { + timer_cb_fn_t cb; + void *arg; +}; + +/* + * These definitions are for timeouts.c and timeouts.h. + */ +#ifdef __GNUC__ +/* We're not exposing any of the functions outside this file. */ +#define TIMEOUT_PUBLIC __attribute__((__unused__)) static +#else +/* We're not exposing any of the functions outside this file. */ +#define TIMEOUT_PUBLIC static +#endif +/* We're not using periodic events. */ +#define TIMEOUT_DISABLE_INTERVALS +/* We always know the global_timeouts object, so we don't need each timeout + * to keep a pointer to it. */ +#define TIMEOUT_DISABLE_RELATIVE_ACCESS +/* We're providing our own struct timeout_cb. */ +#define TIMEOUT_CB_OVERRIDE +/* We're going to support timers that are pretty far out in advance. Making + * this big can be inefficient, but having a significant number of timers + * above TIMEOUT_MAX can also be super-inefficent. Choosing 5 here sets + * timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */ +#define WHEEL_NUM 5 +#include "src/ext/timeouts/timeout.c" + +static struct timeouts *global_timeouts = NULL; +static struct event *global_timer_event = NULL; + +static monotime_t start_of_time; + +/** We need to choose this value carefully. Because we're using timer wheels, + * it actually costs us to have extra resolution we don't use. So for now, + * I'm going to define our resolution as .1 msec, and hope that's good enough. + * + * Note that two of the most popular libevent backends (epoll without timerfd, + * and windows select), simply can't support sub-millisecond resolution, + * do this is optimistic for a lot of users. + */ +#define USEC_PER_TICK 100 + +/** One million microseconds in a second */ +#define USEC_PER_SEC 1000000 + +/** Check at least once every N seconds. */ +#define MIN_CHECK_SECONDS 3600 + +/** Check at least once every N ticks. */ +#define MIN_CHECK_TICKS \ + (((timeout_t)MIN_CHECK_SECONDS) * (1000000 / USEC_PER_TICK)) + +/** + * Convert the timeval in <b>tv</b> to a timeout_t, and return it. + * + * The output resolution is set by USEC_PER_TICK. Only use this to convert + * delays to number of ticks; the time represented by 0 is undefined. + */ +static timeout_t +tv_to_timeout(const struct timeval *tv) +{ + uint64_t usec = tv->tv_usec; + usec += ((uint64_t)USEC_PER_SEC) * tv->tv_sec; + return usec / USEC_PER_TICK; +} + +/** + * Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>. Only + * use this for delays, not absolute times. + */ +static void +timeout_to_tv(timeout_t t, struct timeval *tv_out) +{ + t *= USEC_PER_TICK; + tv_out->tv_usec = (int)(t % USEC_PER_SEC); + tv_out->tv_sec = (time_t)(t / USEC_PER_SEC); +} + +/** + * Update the timer <b>tv</b> to the current time in <b>tv</b>. + */ +static void +timer_advance_to_cur_time(const monotime_t *now) +{ + timeout_t cur_tick = CEIL_DIV(monotime_diff_usec(&start_of_time, now), + USEC_PER_TICK); + timeouts_update(global_timeouts, cur_tick); +} + +/** + * Adjust the time at which the libevent timer should fire based on + * the next-expiring time in <b>global_timeouts</b> + */ +static void +libevent_timer_reschedule(void) +{ + monotime_t now; + monotime_get(&now); + timer_advance_to_cur_time(&now); + + timeout_t delay = timeouts_timeout(global_timeouts); + + struct timeval d; + if (delay > MIN_CHECK_TICKS) + delay = MIN_CHECK_TICKS; + timeout_to_tv(delay, &d); + event_add(global_timer_event, &d); +} + +/** + * Invoked when the libevent timer has expired: see which tor_timer_t events + * have fired, activate their callbacks, and reschedule the libevent timer. + */ +static void +libevent_timer_callback(evutil_socket_t fd, short what, void *arg) +{ + (void)fd; + (void)what; + (void)arg; + + monotime_t now; + monotime_get(&now); + timer_advance_to_cur_time(&now); + + tor_timer_t *t; + while ((t = timeouts_get(global_timeouts))) { + t->callback.cb(t, t->callback.arg, &now); + } + + libevent_timer_reschedule(); +} + +/** + * Initialize the timers subsystem. Requires that libevent has already been + * initialized. + */ +void +timers_initialize(void) +{ + if (BUG(global_timeouts)) + return; // LCOV_EXCL_LINE + + timeout_error_t err; + global_timeouts = timeouts_open(0, &err); + if (!global_timeouts) { + // LCOV_EXCL_START -- this can only fail on malloc failure. + log_err(LD_BUG, "Unable to open timer backend: %s", strerror(err)); + tor_assert(0); + // LCOV_EXCL_STOP + } + + monotime_init(); + monotime_get(&start_of_time); + + struct event *timer_event; + timer_event = tor_event_new(tor_libevent_get_base(), + -1, 0, libevent_timer_callback, NULL); + tor_assert(timer_event); + global_timer_event = timer_event; + + libevent_timer_reschedule(); +} + +/** + * Release all storage held in the timers subsystem. Does not fire timers. + */ +void +timers_shutdown(void) +{ + if (global_timer_event) { + tor_event_free(global_timer_event); + global_timer_event = NULL; + } + if (global_timeouts) { + timeouts_close(global_timeouts); + global_timeouts = NULL; + } +} + +/** + * Allocate and return a new timer, with given callback and argument. + */ +tor_timer_t * +timer_new(timer_cb_fn_t cb, void *arg) +{ + tor_timer_t *t = tor_malloc(sizeof(tor_timer_t)); + timeout_init(t, 0); + timer_set_cb(t, cb, arg); + return t; +} + +/** + * Release all storage held by <b>t</b>, and unschedule it if was already + * scheduled. + */ +void +timer_free(tor_timer_t *t) +{ + if (! t) + return; + + timeouts_del(global_timeouts, t); + tor_free(t); +} + +/** + * Change the callback and argument associated with a timer <b>t</b>. + */ +void +timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg) +{ + t->callback.cb = cb; + t->callback.arg = arg; +} + +/** + * Schedule the timer t to fire at the current time plus a delay of + * <b>delay</b> microseconds. All times are relative to monotime_get(). + */ +void +timer_schedule(tor_timer_t *t, const struct timeval *tv) +{ + const timeout_t delay = tv_to_timeout(tv); + + monotime_t now; + monotime_get(&now); + timer_advance_to_cur_time(&now); + + /* Take the old timeout value. */ + timeout_t to = timeouts_timeout(global_timeouts); + + timeouts_add(global_timeouts, t, delay); + + /* Should we update the libevent timer? */ + if (to <= delay) { + return; /* we're already going to fire before this timer would trigger. */ + } + libevent_timer_reschedule(); +} + +/** + * Cancel the timer <b>t</b> if it is currently scheduled. (It's okay to call + * this on an unscheduled timer. + */ +void +timer_disable(tor_timer_t *t) +{ + timeouts_del(global_timeouts, t); + /* We don't reschedule the libevent timer here, since it's okay if it fires + * early. */ +} + diff --git a/src/common/timers.h b/src/common/timers.h new file mode 100644 index 0000000000..5f918f8e15 --- /dev/null +++ b/src/common/timers.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TIMERS_H +#define TOR_TIMERS_H + +#include "orconfig.h" +#include "testsupport.h" + +struct monotime_t; +typedef struct timeout tor_timer_t; +typedef void (*timer_cb_fn_t)(tor_timer_t *, void *, + const struct monotime_t *); +tor_timer_t *timer_new(timer_cb_fn_t cb, void *arg); +void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg); +void timer_schedule(tor_timer_t *t, const struct timeval *delay); +void timer_disable(tor_timer_t *t); +void timer_free(tor_timer_t *t); + +void timers_initialize(void); +void timers_shutdown(void); + +#endif + diff --git a/src/common/torgzip.c b/src/common/torgzip.c index 71e55f8723..3353f0ef61 100644 --- a/src/common/torgzip.c +++ b/src/common/torgzip.c @@ -46,34 +46,16 @@ #include <zlib.h> +#if defined ZLIB_VERNUM && ZLIB_VERNUM < 0x1200 +#error "We require zlib version 1.2 or later." +#endif + static size_t tor_zlib_state_size_precalc(int inflate, int windowbits, int memlevel); /** Total number of bytes allocated for zlib state */ static size_t total_zlib_allocation = 0; -/** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't; - * set to -1 if we haven't checked yet. */ -static int gzip_is_supported = -1; - -/** Return true iff we support gzip-based compression. Otherwise, we need to - * use zlib. */ -int -is_gzip_supported(void) -{ - if (gzip_is_supported >= 0) - return gzip_is_supported; - - if (!strcmpstart(ZLIB_VERSION, "0.") || - !strcmpstart(ZLIB_VERSION, "1.0") || - !strcmpstart(ZLIB_VERSION, "1.1")) - gzip_is_supported = 0; - else - gzip_is_supported = 1; - - return gzip_is_supported; -} - /** Return a string representation of the version of the currently running * version of zlib. */ const char * @@ -165,12 +147,6 @@ tor_gzip_compress(char **out, size_t *out_len, *out = NULL; - if (method == GZIP_METHOD && !is_gzip_supported()) { - /* Old zlib version don't support gzip in deflateInit2 */ - log_warn(LD_BUG, "Gzip not supported with zlib %s", ZLIB_VERSION); - goto err; - } - stream = tor_malloc_zero(sizeof(struct z_stream_s)); stream->zalloc = Z_NULL; stream->zfree = Z_NULL; @@ -182,9 +158,11 @@ tor_gzip_compress(char **out, size_t *out_len, method_bits(method, HIGH_COMPRESSION), get_memlevel(HIGH_COMPRESSION), Z_DEFAULT_STRATEGY) != Z_OK) { + //LCOV_EXCL_START -- we can only provoke failure by giving junk arguments. log_warn(LD_GENERAL, "Error from deflateInit2: %s", stream->msg?stream->msg:"<no message>"); goto err; + //LCOV_EXCL_STOP } /* Guess 50% compression. */ @@ -237,13 +215,12 @@ tor_gzip_compress(char **out, size_t *out_len, * the newly unsigned field isn't negative." */ tor_assert(stream->total_out >= 0); #endif - if (((size_t)stream->total_out) > out_size + 4097) { - /* If we're wasting more than 4k, don't. */ - *out = tor_realloc(*out, stream->total_out + 1); - } if (deflateEnd(stream)!=Z_OK) { + // LCOV_EXCL_START -- unreachable if we handled the zlib structure right + tor_assert_nonfatal_unreached(); log_warn(LD_BUG, "Error freeing gzip structures"); goto err; + // LCOV_EXCL_STOP } tor_free(stream); @@ -291,12 +268,6 @@ tor_gzip_uncompress(char **out, size_t *out_len, tor_assert(in); tor_assert(in_len < UINT_MAX); - if (method == GZIP_METHOD && !is_gzip_supported()) { - /* Old zlib version don't support gzip in inflateInit2 */ - log_warn(LD_BUG, "Gzip not supported with zlib %s", ZLIB_VERSION); - return -1; - } - *out = NULL; stream = tor_malloc_zero(sizeof(struct z_stream_s)); @@ -308,9 +279,11 @@ tor_gzip_uncompress(char **out, size_t *out_len, if (inflateInit2(stream, method_bits(method, HIGH_COMPRESSION)) != Z_OK) { + // LCOV_EXCL_START -- can only hit this if we give bad inputs. log_warn(LD_GENERAL, "Error from inflateInit2: %s", stream->msg?stream->msg:"<no message>"); goto err; + // LCOV_EXCL_STOP } out_size = in_len * 2; /* guess 50% compression. */ @@ -445,19 +418,13 @@ struct tor_zlib_state_t { * <b>compress</b>, it's for compression; otherwise it's for * decompression. */ tor_zlib_state_t * -tor_zlib_new(int compress, compress_method_t method, +tor_zlib_new(int compress_, compress_method_t method, zlib_compression_level_t compression_level) { tor_zlib_state_t *out; int bits, memlevel; - if (method == GZIP_METHOD && !is_gzip_supported()) { - /* Old zlib version don't support gzip in inflateInit2 */ - log_warn(LD_BUG, "Gzip not supported with zlib %s", ZLIB_VERSION); - return NULL; - } - - if (! compress) { + if (! compress_) { /* use this setting for decompression, since we might have the * max number of window bits */ compression_level = HIGH_COMPRESSION; @@ -467,19 +434,19 @@ tor_zlib_new(int compress, compress_method_t method, out->stream.zalloc = Z_NULL; out->stream.zfree = Z_NULL; out->stream.opaque = NULL; - out->compress = compress; + out->compress = compress_; bits = method_bits(method, compression_level); memlevel = get_memlevel(compression_level); - if (compress) { + if (compress_) { if (deflateInit2(&out->stream, Z_BEST_COMPRESSION, Z_DEFLATED, bits, memlevel, Z_DEFAULT_STRATEGY) != Z_OK) - goto err; + goto err; // LCOV_EXCL_LINE } else { if (inflateInit2(&out->stream, bits) != Z_OK) - goto err; + goto err; // LCOV_EXCL_LINE } - out->allocation = tor_zlib_state_size_precalc(!compress, bits, memlevel); + out->allocation = tor_zlib_state_size_precalc(!compress_, bits, memlevel); total_zlib_allocation += out->allocation; @@ -573,13 +540,13 @@ tor_zlib_free(tor_zlib_state_t *state) /** Return an approximate number of bytes used in RAM to hold a state with * window bits <b>windowBits</b> and compression level 'memlevel' */ static size_t -tor_zlib_state_size_precalc(int inflate, int windowbits, int memlevel) +tor_zlib_state_size_precalc(int inflate_, int windowbits, int memlevel) { windowbits &= 15; #define A_FEW_KILOBYTES 2048 - if (inflate) { + if (inflate_) { /* From zconf.h: "The memory requirements for inflate are (in bytes) 1 << windowBits diff --git a/src/common/torlog.h b/src/common/torlog.h index 578af7caea..6732a42741 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -109,6 +109,11 @@ * would. Used as a flag, not a log domain. */ #define LD_NOFUNCNAME (1u<<30) +#ifdef TOR_UNIT_TESTS +/** This log message should not be intercepted by mock_saving_logv */ +#define LD_NO_MOCK (1u<<29) +#endif + /** Mask of zero or more log domains, OR'd together. */ typedef uint32_t log_domain_mask_t; @@ -176,7 +181,7 @@ void log_fn_ratelim_(struct ratelim_t *ratelim, int severity, const char *format, ...) CHECK_PRINTF(5,6); -#if defined(__GNUC__) +#if defined(__GNUC__) && __GNUC__ <= 3 /* These are the GCC varidaic macros, so that older versions of GCC don't * break. */ diff --git a/src/common/tortls.c b/src/common/tortls.c index 89ad6af939..d61cc2e58a 100644 --- a/src/common/tortls.c +++ b/src/common/tortls.c @@ -24,18 +24,11 @@ #include <ws2tcpip.h> #endif -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#endif +#include "compat.h" -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic push -#endif /* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ -#pragma GCC diagnostic ignored "-Wredundant-decls" -#endif +DISABLE_GCC_WARNING(redundant-decls) #include <openssl/opensslv.h> #include "crypto.h" @@ -53,20 +46,7 @@ #include <openssl/bn.h> #include <openssl/rsa.h> -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif - -#ifdef USE_BUFFEREVENTS -#include <event2/bufferevent_ssl.h> -#include <event2/buffer.h> -#include <event2/event.h> -#include "compat_libevent.h" -#endif +ENABLE_GCC_WARNING(redundant-decls) #define TORTLS_PRIVATE #include "tortls.h" @@ -572,12 +552,11 @@ MOCK_IMPL(STATIC X509 *, * claiming extra unsupported ciphers in order to avoid fingerprinting. */ #define SERVER_CIPHER_LIST \ (TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" \ - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" \ - SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA) + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA) /** List of ciphers that servers should select from when we actually have * our choice of what cipher to use. */ -const char UNRESTRICTED_SERVER_CIPHER_LIST[] = +static const char UNRESTRICTED_SERVER_CIPHER_LIST[] = /* This list is autogenerated with the gen_server_ciphers.py script; * don't hand-edit it. */ #ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 @@ -613,12 +592,8 @@ const char UNRESTRICTED_SERVER_CIPHER_LIST[] = /* Required */ TLS1_TXT_DHE_RSA_WITH_AES_256_SHA ":" /* Required */ - TLS1_TXT_DHE_RSA_WITH_AES_128_SHA ":" -#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA - TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA ":" -#endif - /* Required */ - SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA; + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA + ; /* Note: to set up your own private testing network with link crypto * disabled, set your Tors' cipher list to @@ -702,6 +677,15 @@ MOCK_IMPL(STATIC tor_x509_cert_t *, return cert; } +/** Return a new copy of <b>cert</b>. */ +tor_x509_cert_t * +tor_x509_cert_dup(const tor_x509_cert_t *cert) +{ + tor_assert(cert); + X509 *x509 = cert->cert; + return tor_x509_cert_new(X509_dup(x509)); +} + /** Read a DER-encoded X509 cert, of length exactly <b>certificate_len</b>, * from a <b>certificate</b>. Return a newly allocated tor_x509_cert_t on * success and NULL on failure. */ @@ -1509,6 +1493,10 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val) tor_tls_t *tls; (void) val; + IF_BUG_ONCE(ssl == NULL) { + return; // LCOV_EXCL_LINE + } + tor_tls_debug_state_callback(ssl, type, val); if (type != SSL_CB_ACCEPT_LOOP) @@ -2030,7 +2018,8 @@ tor_tls_peer_has_cert(tor_tls_t *tls) return 1; } -/** Return the peer certificate, or NULL if there isn't one. */ +/** Return a newly allocated copy of the peer certificate, or NULL if there + * isn't one. */ MOCK_IMPL(tor_x509_cert_t *, tor_tls_get_peer_cert,(tor_tls_t *tls)) { @@ -2042,6 +2031,24 @@ tor_tls_get_peer_cert,(tor_tls_t *tls)) return tor_x509_cert_new(cert); } +/** Return a newly allocated copy of the cerficate we used on the connection, + * or NULL if somehow we didn't use one. */ +MOCK_IMPL(tor_x509_cert_t *, +tor_tls_get_own_cert,(tor_tls_t *tls)) +{ + X509 *cert = SSL_get_certificate(tls->ssl); + tls_log_errors(tls, LOG_WARN, LD_HANDSHAKE, + "getting own-connection certificate"); + if (!cert) + return NULL; + /* Fun inconsistency: SSL_get_peer_certificate increments the reference + * count, but SSL_get_certificate does not. */ + X509 *duplicate = X509_dup(cert); + if (BUG(duplicate == NULL)) + return NULL; + return tor_x509_cert_new(duplicate); +} + /** Warn that a certificate lifetime extends through a certain range. */ static void log_cert_lifetime(int severity, const X509 *cert, const char *problem) @@ -2499,78 +2506,6 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls, #endif } -#ifdef USE_BUFFEREVENTS -/** Construct and return an TLS-encrypting bufferevent to send data over - * <b>socket</b>, which must match the socket of the underlying bufferevent - * <b>bufev_in</b>. The TLS object <b>tls</b> is used for encryption. - * - * This function will either create a filtering bufferevent that wraps around - * <b>bufev_in</b>, or it will free bufev_in and return a new bufferevent that - * uses the <b>tls</b> to talk to the network directly. Do not use - * <b>bufev_in</b> after calling this function. - * - * The connection will start out doing a server handshake if <b>receiving</b> - * is strue, and a client handshake otherwise. - * - * Returns NULL on failure. - */ -struct bufferevent * -tor_tls_init_bufferevent(tor_tls_t *tls, struct bufferevent *bufev_in, - evutil_socket_t socket, int receiving, - int filter) -{ - struct bufferevent *out; - const enum bufferevent_ssl_state state = receiving ? - BUFFEREVENT_SSL_ACCEPTING : BUFFEREVENT_SSL_CONNECTING; - - if (filter || tor_libevent_using_iocp_bufferevents()) { - /* Grab an extra reference to the SSL, since BEV_OPT_CLOSE_ON_FREE - means that the SSL will get freed too. - - This increment makes our SSL usage not-threadsafe, BTW. We should - see if we're allowed to use CRYPTO_add from outside openssl. */ - tls->ssl->references += 1; - out = bufferevent_openssl_filter_new(tor_libevent_get_base(), - bufev_in, - tls->ssl, - state, - BEV_OPT_DEFER_CALLBACKS| - BEV_OPT_CLOSE_ON_FREE); - /* Tell the underlying bufferevent when to accept more data from the SSL - filter (only when it's got less than 32K to write), and when to notify - the SSL filter that it could write more (when it drops under 24K). */ - bufferevent_setwatermark(bufev_in, EV_WRITE, 24*1024, 32*1024); - } else { - if (bufev_in) { - evutil_socket_t s = bufferevent_getfd(bufev_in); - tor_assert(s == -1 || s == socket); - tor_assert(evbuffer_get_length(bufferevent_get_input(bufev_in)) == 0); - tor_assert(evbuffer_get_length(bufferevent_get_output(bufev_in)) == 0); - tor_assert(BIO_number_read(SSL_get_rbio(tls->ssl)) == 0); - tor_assert(BIO_number_written(SSL_get_rbio(tls->ssl)) == 0); - bufferevent_free(bufev_in); - } - - /* Current versions (as of 2.0.x) of Libevent need to defer - * bufferevent_openssl callbacks, or else our callback functions will - * get called reentrantly, which is bad for us. - */ - out = bufferevent_openssl_socket_new(tor_libevent_get_base(), - socket, - tls->ssl, - state, - BEV_OPT_DEFER_CALLBACKS); - } - tls->state = TOR_TLS_ST_BUFFEREVENT; - - /* Unblock _after_ creating the bufferevent, since accept/connect tend to - * clear flags. */ - tor_tls_unblock_renegotiation(tls); - - return out; -} -#endif - /** Check whether the ECC group requested is supported by the current OpenSSL * library instance. Return 1 if the group is supported, and 0 if not. */ diff --git a/src/common/tortls.h b/src/common/tortls.h index 1a59c67df3..f018c45c82 100644 --- a/src/common/tortls.h +++ b/src/common/tortls.h @@ -164,8 +164,18 @@ STATIC int tor_tls_context_init_one(tor_tls_context_t **ppcontext, int is_client); STATIC void tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing); + +#ifdef TOR_UNIT_TESTS +extern int tor_tls_object_ex_data_index; +extern tor_tls_context_t *server_tls_context; +extern tor_tls_context_t *client_tls_context; +extern uint16_t v2_cipher_list[]; +extern uint64_t total_bytes_written_over_tls; +extern uint64_t total_bytes_written_by_tls; #endif +#endif /* endif TORTLS_PRIVATE */ + const char *tor_tls_err_to_string(int err); void tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz); @@ -187,7 +197,9 @@ void tor_tls_set_renegotiate_callback(tor_tls_t *tls, int tor_tls_is_server(tor_tls_t *tls); void tor_tls_free(tor_tls_t *tls); int tor_tls_peer_has_cert(tor_tls_t *tls); +tor_x509_cert_t *tor_x509_cert_dup(const tor_x509_cert_t *cert); MOCK_DECL(tor_x509_cert_t *,tor_tls_get_peer_cert,(tor_tls_t *tls)); +MOCK_DECL(tor_x509_cert_t *,tor_tls_get_own_cert,(tor_tls_t *tls)); int tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity); int tor_tls_check_lifetime(int severity, tor_tls_t *tls, int past_tolerance, @@ -225,14 +237,6 @@ void check_no_tls_errors_(const char *fname, int line); void tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, int severity, int domain, const char *doing); -#ifdef USE_BUFFEREVENTS -int tor_tls_start_renegotiating(tor_tls_t *tls); -struct bufferevent *tor_tls_init_bufferevent(tor_tls_t *tls, - struct bufferevent *bufev_in, - evutil_socket_t socket, int receiving, - int filter); -#endif - void tor_x509_cert_free(tor_x509_cert_t *cert); tor_x509_cert_t *tor_x509_cert_decode(const uint8_t *certificate, size_t certificate_len); diff --git a/src/common/util.c b/src/common/util.c index b2b97613a7..b7468dfcb3 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -9,10 +9,6 @@ * process control. **/ -/* This is required on rh7 to make strptime not complain. - */ -#define _GNU_SOURCE - #include "orconfig.h" #ifdef HAVE_FCNTL_H #include <fcntl.h> @@ -105,23 +101,6 @@ #endif /* ===== - * Assertion helper. - * ===== */ -/** Helper for tor_assert: report the assertion failure. */ -void -tor_assertion_failed_(const char *fname, unsigned int line, - const char *func, const char *expr) -{ - char buf[256]; - log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.", - fname, line, func, expr); - tor_snprintf(buf, sizeof(buf), - "Assertion %s failed in %s at %s:%u", - expr, func, fname, line); - log_backtrace(LOG_ERR, LD_BUG, buf); -} - -/* ===== * Memory management * ===== */ #ifdef USE_DMALLOC @@ -168,15 +147,17 @@ tor_malloc_(size_t size DMALLOC_PARAMS) #ifdef USE_DMALLOC result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); #else - result = malloc(size); + result = raw_malloc(size); #endif if (PREDICT_UNLIKELY(result == NULL)) { + /* LCOV_EXCL_START */ log_err(LD_MM,"Out of memory on malloc(). Dying."); /* If these functions die within a worker process, they won't call * spawn_exit, but that's ok, since the parent will run out of memory soon * anyway. */ exit(1); + /* LCOV_EXCL_STOP */ } return result; } @@ -221,6 +202,15 @@ size_mul_check(const size_t x, const size_t y) x <= SIZE_MAX / y); } +#ifdef TOR_UNIT_TESTS +/** Exposed for unit tests only */ +int +size_mul_check__(const size_t x, const size_t y) +{ + return size_mul_check(x,y); +} +#endif + /** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill * the memory with zero bytes, and return a pointer to the result. * Log and terminate the process on error. (Same as @@ -256,12 +246,14 @@ tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS) #ifdef USE_DMALLOC result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); #else - result = realloc(ptr, size); + result = raw_realloc(ptr, size); #endif if (PREDICT_UNLIKELY(result == NULL)) { + /* LCOV_EXCL_START */ log_err(LD_MM,"Out of memory on realloc(). Dying."); exit(1); + /* LCOV_EXCL_STOP */ } return result; } @@ -287,19 +279,21 @@ tor_reallocarray_(void *ptr, size_t sz1, size_t sz2 DMALLOC_PARAMS) char * tor_strdup_(const char *s DMALLOC_PARAMS) { - char *dup; + char *duplicate; tor_assert(s); #ifdef USE_DMALLOC - dup = dmalloc_strdup(file, line, s, 0); + duplicate = dmalloc_strdup(file, line, s, 0); #else - dup = strdup(s); + duplicate = raw_strdup(s); #endif - if (PREDICT_UNLIKELY(dup == NULL)) { + if (PREDICT_UNLIKELY(duplicate == NULL)) { + /* LCOV_EXCL_START */ log_err(LD_MM,"Out of memory on strdup(). Dying."); exit(1); + /* LCOV_EXCL_STOP */ } - return dup; + return duplicate; } /** Allocate and return a new string containing the first <b>n</b> @@ -311,17 +305,17 @@ tor_strdup_(const char *s DMALLOC_PARAMS) char * tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) { - char *dup; + char *duplicate; tor_assert(s); tor_assert(n < SIZE_T_CEILING); - dup = tor_malloc_((n+1) DMALLOC_FN_ARGS); + duplicate = tor_malloc_((n+1) DMALLOC_FN_ARGS); /* Performance note: Ordinarily we prefer strlcpy to strncpy. But * this function gets called a whole lot, and platform strncpy is * much faster than strlcpy when strlen(s) is much longer than n. */ - strncpy(dup, s, n); - dup[n]='\0'; - return dup; + strncpy(duplicate, s, n); + duplicate[n]='\0'; + return duplicate; } /** Allocate a chunk of <b>len</b> bytes, with the same contents as the @@ -329,12 +323,12 @@ tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) void * tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) { - char *dup; + char *duplicate; tor_assert(len < SIZE_T_CEILING); tor_assert(mem); - dup = tor_malloc_(len DMALLOC_FN_ARGS); - memcpy(dup, mem, len); - return dup; + duplicate = tor_malloc_(len DMALLOC_FN_ARGS); + memcpy(duplicate, mem, len); + return duplicate; } /** As tor_memdup(), but add an extra 0 byte at the end of the resulting @@ -342,13 +336,13 @@ tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) void * tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) { - char *dup; + char *duplicate; tor_assert(len < SIZE_T_CEILING+1); tor_assert(mem); - dup = tor_malloc_(len+1 DMALLOC_FN_ARGS); - memcpy(dup, mem, len); - dup[len] = '\0'; - return dup; + duplicate = tor_malloc_(len+1 DMALLOC_FN_ARGS); + memcpy(duplicate, mem, len); + duplicate[len] = '\0'; + return duplicate; } /** Helper for places that need to take a function pointer to the right @@ -359,6 +353,7 @@ tor_free_(void *mem) tor_free(mem); } +DISABLE_GCC_WARNING(aggregate-return) /** Call the platform malloc info function, and dump the results to the log at * level <b>severity</b>. If no such function exists, do nothing. */ void @@ -386,6 +381,7 @@ tor_log_mallinfo(int severity) ); #endif } +ENABLE_GCC_WARNING(aggregate-return) /* ===== * Math @@ -530,21 +526,6 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) return number; } -/** Return the lowest x in [INT64_MIN, INT64_MAX] such that x is at least - * <b>number</b>, and x modulo <b>divisor</b> == 0. If no such x can be - * expressed as an int64_t, return INT64_MAX */ -int64_t -round_int64_to_next_multiple_of(int64_t number, int64_t divisor) -{ - tor_assert(divisor > 0); - if (INT64_MAX - divisor + 1 < number) - return INT64_MAX; - if (number >= 0) - number += divisor - 1; - number -= number % divisor; - return number; -} - /** Transform a random value <b>p</b> from the uniform distribution in * [0.0, 1.0[ into a Laplace distributed value with location parameter * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result @@ -575,7 +556,7 @@ sample_laplace_distribution(double mu, double b, double p) * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater * than 0. */ int64_t -add_laplace_noise(int64_t signal, double random, double delta_f, +add_laplace_noise(int64_t signal_, double random_, double delta_f, double epsilon) { int64_t noise; @@ -588,15 +569,38 @@ add_laplace_noise(int64_t signal, double random, double delta_f, /* Just add noise, no further signal */ noise = sample_laplace_distribution(0.0, delta_f / epsilon, - random); + random_); /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ - if (noise > 0 && INT64_MAX - noise < signal) + if (noise > 0 && INT64_MAX - noise < signal_) return INT64_MAX; - else if (noise < 0 && INT64_MIN - noise > signal) + else if (noise < 0 && INT64_MIN - noise > signal_) return INT64_MIN; else - return signal + noise; + return signal_ + noise; +} + +/* Helper: return greatest common divisor of a,b */ +static uint64_t +gcd64(uint64_t a, uint64_t b) +{ + while (b) { + uint64_t t = b; + b = a % b; + a = t; + } + return a; +} + +/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it. + * Requires that the denominator is greater than 0. */ +void +simplify_fraction64(uint64_t *numer, uint64_t *denom) +{ + tor_assert(denom); + uint64_t gcd = gcd64(*numer, *denom); + *numer /= gcd; + *denom /= gcd; } /** Return the number of bits set in <b>v</b>. */ @@ -634,12 +638,12 @@ n_bits_set_u8(uint8_t v) void tor_strstrip(char *s, const char *strip) { - char *read = s; - while (*read) { - if (strchr(strip, *read)) { - ++read; + char *readp = s; + while (*readp) { + if (strchr(strip, *readp)) { + ++readp; } else { - *s++ = *read++; + *s++ = *readp++; } } *s = '\0'; @@ -1130,6 +1134,9 @@ tor_digest256_is_zero(const char *digest) /* Were there unexpected unconverted characters? */ \ if (!next && *endptr) \ goto err; \ + /* Illogical (max, min) inputs? */ \ + if (BUG(max < min)) \ + goto err; \ /* Is r within limits? */ \ if (r < min || r > max) \ goto err; \ @@ -1402,42 +1409,138 @@ tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) * Time * ===== */ +#define TOR_USEC_PER_SEC 1000000 + +/** Return the difference between start->tv_sec and end->tv_sec. + * Returns INT64_MAX on overflow and underflow. + */ +static int64_t +tv_secdiff_impl(const struct timeval *start, const struct timeval *end) +{ + const int64_t s = (int64_t)start->tv_sec; + const int64_t e = (int64_t)end->tv_sec; + + /* This may not be the most efficient way of implemeting this check, + * but it's easy to see that it's correct and doesn't overflow */ + + if (s > 0 && e < INT64_MIN + s) { + /* s is positive: equivalent to e - s < INT64_MIN, but without any + * overflow */ + return INT64_MAX; + } else if (s < 0 && e > INT64_MAX + s) { + /* s is negative: equivalent to e - s > INT64_MAX, but without any + * overflow */ + return INT64_MAX; + } + + return e - s; +} + /** Return the number of microseconds elapsed between *start and *end. + * Returns LONG_MAX on overflow and underflow. */ long tv_udiff(const struct timeval *start, const struct timeval *end) { - long udiff; - long secdiff = end->tv_sec - start->tv_sec; + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "start tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(start->tv_usec)); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "end tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(end->tv_usec)); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t udiff; + const int64_t secdiff = tv_secdiff_impl(start, end); - if (labs(secdiff+1) > LONG_MAX/1000000) { + /* end->tv_usec - start->tv_usec can be up to 1 second either way */ + if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || + secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { log_warn(LD_GENERAL, "comparing times on microsecond detail too far " - "apart: %ld seconds", secdiff); + "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); + return LONG_MAX; + } + + /* we'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { return LONG_MAX; } +#endif - udiff = secdiff*1000000L + (end->tv_usec - start->tv_usec); - return udiff; + return (long)udiff; } /** Return the number of milliseconds elapsed between *start and *end. + * If the tv_usec difference is 500, rounds away from zero. + * Returns LONG_MAX on overflow and underflow. */ long tv_mdiff(const struct timeval *start, const struct timeval *end) { - long mdiff; - long secdiff = end->tv_sec - start->tv_sec; + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "start tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(start->tv_usec)); + return LONG_MAX; + } - if (labs(secdiff+1) > LONG_MAX/1000) { + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "end tv_usec: " I64_FORMAT " microseconds", + I64_PRINTF_ARG(end->tv_usec)); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t mdiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the + * mdiff calculation may add another temporary second for rounding. + * Whether this actually causes overflow depends on the compiler's constant + * folding and order of operations. */ + if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || + secdiff < (int64_t)(LONG_MIN/1000 + 1)) { log_warn(LD_GENERAL, "comparing times on millisecond detail too far " - "apart: %ld seconds", secdiff); + "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); return LONG_MAX; } /* Subtract and round */ - mdiff = secdiff*1000L + - ((long)end->tv_usec - (long)start->tv_usec + 500L) / 1000L; - return mdiff; + mdiff = secdiff*1000 + + /* We add a million usec here to ensure that the result is positive, + * so that the round-towards-zero behavior of the division will give + * the right result for rounding to the nearest msec. Later we subtract + * 1000 in order to get the correct result. + * We'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 + - 1000; + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)mdiff; } /** @@ -1456,11 +1559,12 @@ tv_to_msec(const struct timeval *tv) #define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400))) /** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */ static int -n_leapdays(int y1, int y2) +n_leapdays(int year1, int year2) { - --y1; - --y2; - return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); + --year1; + --year2; + return (year2/4 - year1/4) - (year2/100 - year1/100) + + (year2/400 - year1/400); } /** Number of days per month in non-leap year; used by tor_timegm and * parse_rfc1123_time. */ @@ -1638,11 +1742,16 @@ parse_rfc1123_time(const char *buf, time_t *t) tm.tm_sec = (int)tm_sec; if (tm.tm_year < 1970) { + /* LCOV_EXCL_START + * XXXX I think this is dead code; we already checked for + * invalid_year above. */ + tor_assert_nonfatal_unreached(); char *esc = esc_for_log(buf); log_warn(LD_GENERAL, "Got invalid RFC1123 time %s. (Before 1970)", esc); tor_free(esc); return -1; + /* LCOV_EXCL_STOP */ } tm.tm_year -= 1900; @@ -1726,10 +1835,15 @@ parse_iso_time_(const char *cp, time_t *t, int strict) st_tm.tm_wday = 0; /* Should be ignored. */ if (st_tm.tm_year < 70) { + /* LCOV_EXCL_START + * XXXX I think this is dead code; we already checked for + * year < 1970 above. */ + tor_assert_nonfatal_unreached(); char *esc = esc_for_log(cp); log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc); tor_free(esc); return -1; + /* LCOV_EXCL_STOP */ } return tor_timegm(&st_tm, t); } @@ -1893,7 +2007,9 @@ update_approx_time(time_t now) /** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number * of calls to rate_limit_is_ready (including this one!) since the last time - * rate_limit_is_ready returned nonzero. Otherwise return 0. */ + * rate_limit_is_ready returned nonzero. Otherwise return 0. + * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning + * about this event and stop counting. */ static int rate_limit_is_ready(ratelim_t *lim, time_t now) { @@ -1903,7 +2019,10 @@ rate_limit_is_ready(ratelim_t *lim, time_t now) lim->n_calls_since_last_time = 0; return res; } else { - ++lim->n_calls_since_last_time; + if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { + ++lim->n_calls_since_last_time; + } + return 0; } } @@ -1920,9 +2039,12 @@ rate_limit_log(ratelim_t *lim, time_t now) return tor_strdup(""); } else { char *cp=NULL; + const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; + /* XXXX this is not exactly correct: the messages could have occurred + * any time between the old value of lim->allowed and now. */ tor_asprintf(&cp, - " [%d similar message(s) suppressed in last %d seconds]", - n-1, lim->rate); + " [%s%d similar message(s) suppressed in last %d seconds]", + opt_over, n-1, lim->rate); return cp; } } else { @@ -2011,6 +2133,16 @@ clean_name_for_stat(char *name) #endif } +/** Wrapper for unlink() to make it mockable for the test suite; returns 0 + * if unlinking the file succeeded, -1 and sets errno if unlinking fails. + */ + +MOCK_IMPL(int, +tor_unlink,(const char *pathname)) +{ + return unlink(pathname); +} + /** Return: * FN_ERROR if filename can't be read, is NULL, or is zero-length, * FN_NOENT if it doesn't exist, @@ -2059,11 +2191,13 @@ file_status(const char *fname) } } -/** Check whether <b>dirname</b> exists and is private. If yes return 0. If - * it does not exist, and <b>check</b>&CPD_CREATE is set, try to create it - * and return 0 on success. If it does not exist, and - * <b>check</b>&CPD_CHECK, and we think we can create it, return 0. Else - * return -1. If CPD_GROUP_OK is set, then it's okay if the directory +/** Check whether <b>dirname</b> exists and is private. If yes return 0. + * If <b>dirname</b> does not exist: + * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success. + * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0. + * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0. + * - otherwise, return -1. + * If CPD_GROUP_OK is set, then it's okay if the directory * is group-readable, but in all cases we create the directory mode 0700. * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and * if the directory is created it will use mode 0750 with group read @@ -2074,9 +2208,9 @@ file_status(const char *fname) * When effective_user is not NULL, check permissions against the given user * and its primary group. */ -int -check_private_dir(const char *dirname, cpd_check_t check, - const char *effective_user) +MOCK_IMPL(int, +check_private_dir,(const char *dirname, cpd_check_t check, + const char *effective_user)) { int r; struct stat st; @@ -2189,13 +2323,14 @@ check_private_dir(const char *dirname, cpd_check_t check, running_gid = getgid(); } if (st.st_uid != running_uid) { - const struct passwd *pw = NULL; + const struct passwd *pw_uid = NULL; char *process_ownername = NULL; - pw = tor_getpwuid(running_uid); - process_ownername = pw ? tor_strdup(pw->pw_name) : tor_strdup("<unknown>"); + pw_uid = tor_getpwuid(running_uid); + process_ownername = pw_uid ? tor_strdup(pw_uid->pw_name) : + tor_strdup("<unknown>"); - pw = tor_getpwuid(st.st_uid); + pw_uid = tor_getpwuid(st.st_uid); log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by " "%s (%d). Perhaps you are running Tor as the wrong user?", @@ -2304,8 +2439,8 @@ check_private_dir(const char *dirname, cpd_check_t check, * function, and all other functions in util.c that create files, create them * with mode 0600. */ -int -write_str_to_file(const char *fname, const char *str, int bin) +MOCK_IMPL(int, +write_str_to_file,(const char *fname, const char *str, int bin)) { #ifdef _WIN32 if (!bin && strchr(str, '\r')) { @@ -2664,8 +2799,8 @@ read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) * the call to stat and the call to read_all: the resulting string will * be truncated. */ -char * -read_file_to_str(const char *filename, int flags, struct stat *stat_out) +MOCK_IMPL(char *, +read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) { int fd; /* router file */ struct stat statbuf; @@ -2773,7 +2908,7 @@ read_file_to_str(const char *filename, int flags, struct stat *stat_out) * provided), and return a pointer to the position in <b>s</b> immediately * after the string. On failure, return NULL. */ -static const char * +const char * unescape_string(const char *s, char **result, size_t *size_out) { const char *cp; @@ -2820,9 +2955,11 @@ unescape_string(const char *s, char **result, size_t *size_out) if (size_out) *size_out = out - *result; return cp+1; case '\0': + /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */ tor_fragile_assert(); tor_free(*result); return NULL; + /* LCOV_EXCL_STOP */ case '\\': switch (cp[1]) { @@ -2836,8 +2973,12 @@ unescape_string(const char *s, char **result, size_t *size_out) x1 = hex_decode_digit(cp[2]); x2 = hex_decode_digit(cp[3]); if (x1 == -1 || x2 == -1) { - tor_free(*result); - return NULL; + /* LCOV_EXCL_START */ + /* we caught this above in the initial loop. */ + tor_assert_nonfatal_unreached(); + tor_free(*result); + return NULL; + /* LCOV_EXCL_STOP */ } *out++ = ((x1<<4) + x2); @@ -2863,7 +3004,11 @@ unescape_string(const char *s, char **result, size_t *size_out) cp += 2; break; default: + /* LCOV_EXCL_START */ + /* we caught this above in the initial loop. */ + tor_assert_nonfatal_unreached(); tor_free(*result); return NULL; + /* LCOV_EXCL_STOP */ } break; default: @@ -2936,6 +3081,8 @@ parse_config_line_from_str_verbose(const char *line, char **key_out, } while (*line == ' ' || *line == '\t') ++line; + if (*line == '\r' && *(++line) == '\n') + ++line; if (*line && *line != '#' && *line != '\n') { if (err_out) *err_out = "Excess data after quoted string"; @@ -3079,7 +3226,7 @@ digit_to_num(char d) * success, store the result in <b>out</b>, advance bufp to the next * character, and return 0. On failure, return -1. */ static int -scan_unsigned(const char **bufp, unsigned long *out, int width, int base) +scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base) { unsigned long result = 0; int scanned_so_far = 0; @@ -3092,7 +3239,7 @@ scan_unsigned(const char **bufp, unsigned long *out, int width, int base) while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) && scanned_so_far < width) { - int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); + unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); // Check for overflow beforehand, without actually causing any overflow // This preserves functionality on compilers that don't wrap overflow // (i.e. that trap or optimise away overflow) @@ -3138,14 +3285,15 @@ scan_signed(const char **bufp, long *out, int width) if (neg && result > 0) { if (result > ((unsigned long)LONG_MAX) + 1) return -1; /* Underflow */ - // Avoid overflow on the cast to signed long when result is LONG_MIN - // by subtracting 1 from the unsigned long positive value, - // then, after it has been cast to signed and negated, - // subtracting the original 1 (the double-subtraction is intentional). - // Otherwise, the cast to signed could cause a temporary long - // to equal LONG_MAX + 1, which is undefined. - // We avoid underflow on the subtraction by treating -0 as positive. - *out = (-(long)(result - 1)) - 1; + else if (result == ((unsigned long)LONG_MAX) + 1) + *out = LONG_MIN; + else { + /* We once had a far more clever no-overflow conversion here, but + * some versions of GCC apparently ran it into the ground. Now + * we just check for LONG_MIN explicitly. + */ + *out = -(long)result; + } } else { if (result > LONG_MAX) return -1; /* Overflow */ @@ -3291,8 +3439,10 @@ tor_vsscanf(const char *buf, const char *pattern, va_list ap) *out = lng; } else { int *out = va_arg(ap, int *); +#if LONG_MAX > INT_MAX if (lng < INT_MIN || lng > INT_MAX) return n_matched; +#endif *out = (int)lng; } ++pattern; @@ -3387,8 +3537,8 @@ smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, /** Return a new list containing the filenames in the directory <b>dirname</b>. * Return NULL on error or if <b>dirname</b> is not a directory. */ -smartlist_t * -tor_listdir(const char *dirname) +MOCK_IMPL(smartlist_t *, +tor_listdir, (const char *dirname)) { smartlist_t *result; #ifdef _WIN32 @@ -3495,13 +3645,17 @@ start_daemon(void) start_daemon_called = 1; if (pipe(daemon_filedes)) { + /* LCOV_EXCL_START */ log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); exit(1); + /* LCOV_EXCL_STOP */ } pid = fork(); if (pid < 0) { + /* LCOV_EXCL_START */ log_err(LD_GENERAL,"fork failed. Exiting."); exit(1); + /* LCOV_EXCL_STOP */ } if (pid) { /* Parent */ int ok; @@ -3563,8 +3717,10 @@ finish_daemon(const char *desired_cwd) nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); if (nullfd < 0) { + /* LCOV_EXCL_START */ log_err(LD_GENERAL,"/dev/null can't be opened. Exiting."); exit(1); + /* LCOV_EXCL_STOP */ } /* close fds linking to invoking terminal, but * close usual incoming fds, but redirect them somewhere @@ -3573,8 +3729,10 @@ finish_daemon(const char *desired_cwd) if (dup2(nullfd,0) < 0 || dup2(nullfd,1) < 0 || dup2(nullfd,2) < 0) { + /* LCOV_EXCL_START */ log_err(LD_GENERAL,"dup2 failed. Exiting."); exit(1); + /* LCOV_EXCL_STOP */ } if (nullfd > 2) close(nullfd); @@ -3688,9 +3846,9 @@ format_win_cmdline_argument(const char *arg) formatted_arg[i++] = '"'; /* Add characters */ - SMARTLIST_FOREACH(arg_chars, char*, c, + SMARTLIST_FOREACH(arg_chars, char*, ch, { - formatted_arg[i++] = *c; + formatted_arg[i++] = *ch; }); /* Add trailing quote */ @@ -3771,7 +3929,7 @@ format_number_sigsafe(unsigned long x, char *buf, int buf_len, /* NOT tor_assert; see above. */ if (cp != buf) { - abort(); + abort(); // LCOV_EXCL_LINE } return len; @@ -4349,7 +4507,7 @@ tor_spawn_background(const char *const filename, const char **argv, _exit(255); /* Never reached, but avoids compiler warning */ - return status; + return status; // LCOV_EXCL_LINE } /* In parent */ @@ -4548,13 +4706,13 @@ tor_get_exit_code(process_handle_t *process_handle, return PROCESS_EXIT_RUNNING; } else if (retval != process_handle->pid) { log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", - process_handle->pid, strerror(errno)); + (int)process_handle->pid, strerror(errno)); return PROCESS_EXIT_ERROR; } if (!WIFEXITED(stat_loc)) { log_warn(LD_GENERAL, "Process %d did not exit normally", - process_handle->pid); + (int)process_handle->pid); return PROCESS_EXIT_ERROR; } @@ -5535,7 +5693,7 @@ tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) int64_t clamp_double_to_int64(double number) { - int exp; + int exponent; #if defined(__MINGW32__) || defined(__MINGW64__) /* @@ -5558,15 +5716,15 @@ DISABLE_GCC_WARNING(float-conversion) * magnitude of number is strictly less than 2^exp. * * If number is infinite, the call to frexp is legal but the contents of - * exp are unspecified. */ - frexp(number, &exp); + * are exponent unspecified. */ + frexp(number, &exponent); /* If the magnitude of number is strictly less than 2^63, the truncated * version of number is guaranteed to be representable. The only * representable integer for which this is not the case is INT64_MIN, but * it is covered by the logic below. */ - if (isfinite(number) && exp <= 63) { - return number; + if (isfinite(number) && exponent <= 63) { + return (int64_t)number; } /* Handle infinities and finite numbers with magnitude >= 2^63. */ @@ -5576,3 +5734,24 @@ ENABLE_GCC_WARNING(float-conversion) #endif } +/** Return a uint64_t value from <b>a</b> in network byte order. */ +uint64_t +tor_htonll(uint64_t a) +{ +#ifdef WORDS_BIGENDIAN + /* Big endian. */ + return a; +#else /* WORDS_BIGENDIAN */ + /* Little endian. The worst... */ + return htonl((uint32_t)(a>>32)) | + (((uint64_t)htonl((uint32_t)a))<<32); +#endif /* WORDS_BIGENDIAN */ +} + +/** Return a uint64_t value from <b>a</b> in host byte order. */ +uint64_t +tor_ntohll(uint64_t a) +{ + return tor_htonll(a); +} + diff --git a/src/common/util.h b/src/common/util.h index ebcf88b32d..479fc8d610 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -22,6 +22,7 @@ /* for the correct alias to struct stat */ #include <sys/stat.h> #endif +#include "util_bug.h" #ifndef O_BINARY #define O_BINARY 0 @@ -33,41 +34,6 @@ #define O_NOFOLLOW 0 #endif -/* Replace assert() with a variant that sends failures to the log before - * calling assert() normally. - */ -#ifdef NDEBUG -/* Nobody should ever want to build with NDEBUG set. 99% of our asserts will - * be outside the critical path anyway, so it's silly to disable bug-checking - * throughout the entire program just because a few asserts are slowing you - * down. Profile, optimize the critical path, and keep debugging on. - * - * And I'm not just saying that because some of our asserts check - * security-critical properties. - */ -#error "Sorry; we don't support building with NDEBUG." -#endif - -/* Sometimes we don't want to use assertions during branch coverage tests; it - * leads to tons of unreached branches which in reality are only assertions we - * didn't hit. */ -#if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) -#define tor_assert(a) STMT_BEGIN \ - (void)(a); \ - STMT_END -#else -/** Like assert(3), but send assertion failures to the log as well as to - * stderr. */ -#define tor_assert(expr) STMT_BEGIN \ - if (PREDICT_UNLIKELY(!(expr))) { \ - tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \ - abort(); \ - } STMT_END -#endif - -void tor_assertion_failed_(const char *fname, unsigned int line, - const char *func, const char *expr); - /* If we're building with dmalloc, we want all of our memory allocation * functions to take an extra file/line pair of arguments. If not, not. * We define DMALLOC_PARAMS to the extra parameters to insert in the @@ -81,11 +47,6 @@ void tor_assertion_failed_(const char *fname, unsigned int line, #define DMALLOC_ARGS #endif -/** Define this if you want Tor to crash when any problem comes up, - * so you can get a coredump and track things down. */ -// #define tor_fragile_assert() tor_assert(0) -#define tor_fragile_assert() - /* Memory management */ void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; @@ -100,6 +61,8 @@ void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1)); void tor_free_(void *mem); +uint64_t tor_htonll(uint64_t a); +uint64_t tor_ntohll(uint64_t a); #ifdef USE_DMALLOC extern int dmalloc_free(const char *file, const int line, void *pnt, const int func_id); @@ -119,7 +82,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt, */ #define tor_free(p) STMT_BEGIN \ if (PREDICT_LIKELY((p)!=NULL)) { \ - free(p); \ + raw_free(p); \ (p)=NULL; \ } \ STMT_END @@ -136,6 +99,14 @@ extern int dmalloc_free(const char *file, const int line, void *pnt, #define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS) #define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n DMALLOC_ARGS) +/* Aliases for the underlying system malloc/realloc/free. Only use + * them to indicate "I really want the underlying system function, I know + * what I'm doing." */ +#define raw_malloc malloc +#define raw_realloc realloc +#define raw_free free +#define raw_strdup strdup + void tor_log_mallinfo(int severity); /** Return the offset of <b>member</b> within the type <b>tp</b>, in bytes */ @@ -184,12 +155,12 @@ uint64_t round_to_power_of_2(uint64_t u64); unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); -int64_t round_int64_to_next_multiple_of(int64_t number, int64_t divisor); int64_t sample_laplace_distribution(double mu, double b, double p); int64_t add_laplace_noise(int64_t signal, double random, double delta_f, double epsilon); int n_bits_set_u8(uint8_t v); int64_t clamp_double_to_int64(double number); +void simplify_fraction64(uint64_t *numer, uint64_t *denom); /* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> * and positive <b>b</b>. Works on integer types only. Not defined if a+b can @@ -330,6 +301,7 @@ typedef struct ratelim_t { } ratelim_t; #define RATELIM_INIT(r) { (r), 0, 0 } +#define RATELIM_TOOMANY (16*1000*1000) char *rate_limit_log(ratelim_t *lim, time_t now); @@ -349,6 +321,8 @@ const char *stream_status_to_string(enum stream_status stream_status); enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count); +MOCK_DECL(int,tor_unlink,(const char *pathname)); + /** Return values from file_status(); see that function's documentation * for details. */ typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; @@ -364,8 +338,9 @@ typedef unsigned int cpd_check_t; #define CPD_GROUP_READ (1u << 3) #define CPD_CHECK_MODE_ONLY (1u << 4) #define CPD_RELAX_DIRMODE_CHECK (1u << 5) -int check_private_dir(const char *dirname, cpd_check_t check, - const char *effective_user); +MOCK_DECL(int, check_private_dir, + (const char *dirname, cpd_check_t check, + const char *effective_user)); #define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) #define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) @@ -378,7 +353,8 @@ FILE *start_writing_to_stdio_file(const char *fname, int open_flags, int mode, FILE *fdopen_file(open_file_t *file_data); int finish_writing_to_file(open_file_t *file_data); int abort_writing_to_file(open_file_t *file_data); -int write_str_to_file(const char *fname, const char *str, int bin); +MOCK_DECL(int, +write_str_to_file,(const char *fname, const char *str, int bin)); MOCK_DECL(int, write_bytes_to_file,(const char *fname, const char *str, size_t len, int bin)); @@ -403,18 +379,18 @@ int write_bytes_to_new_file(const char *fname, const char *str, size_t len, #ifndef _WIN32 struct stat; #endif -char *read_file_to_str(const char *filename, int flags, struct stat *stat_out) - ATTR_MALLOC; +MOCK_DECL_ATTR(char *, read_file_to_str, + (const char *filename, int flags, struct stat *stat_out), + ATTR_MALLOC); char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) ATTR_MALLOC; +const char *unescape_string(const char *s, char **result, size_t *size_out); const char *parse_config_line_from_str_verbose(const char *line, char **key_out, char **value_out, const char **err_out); -#define parse_config_line_from_str(line,key_out,value_out) \ - parse_config_line_from_str_verbose((line),(key_out),(value_out),NULL) char *expand_filename(const char *filename); -struct smartlist_t *tor_listdir(const char *dirname); +MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); int path_is_relative(const char *filename); /* Process helpers */ @@ -575,6 +551,10 @@ STATIC int format_helper_exit_status(unsigned char child_state, #endif +#ifdef TOR_UNIT_TESTS +int size_mul_check__(const size_t x, const size_t y); +#endif + #define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) #endif diff --git a/src/common/util_bug.c b/src/common/util_bug.c new file mode 100644 index 0000000000..08aba47974 --- /dev/null +++ b/src/common/util_bug.c @@ -0,0 +1,115 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file util_bug.c + **/ + +#include "orconfig.h" +#include "util_bug.h" +#include "torlog.h" +#include "backtrace.h" +#include "container.h" + +#ifdef TOR_UNIT_TESTS +static void (*failed_assertion_cb)(void) = NULL; +static int n_bugs_to_capture = 0; +static smartlist_t *bug_messages = NULL; +#define capturing_bugs() (bug_messages != NULL && n_bugs_to_capture) +void +tor_capture_bugs_(int n) +{ + tor_end_capture_bugs_(); + bug_messages = smartlist_new(); + n_bugs_to_capture = n; +} +void +tor_end_capture_bugs_(void) +{ + n_bugs_to_capture = 0; + if (!bug_messages) + return; + SMARTLIST_FOREACH(bug_messages, char *, cp, tor_free(cp)); + smartlist_free(bug_messages); + bug_messages = NULL; +} +const smartlist_t * +tor_get_captured_bug_log_(void) +{ + return bug_messages; +} +static void +add_captured_bug(const char *s) +{ + --n_bugs_to_capture; + smartlist_add(bug_messages, tor_strdup(s)); +} +/** Set a callback to be invoked when we get any tor_bug_occurred_ + * invocation. We use this in the unit tests so that a nonfatal + * assertion failure can also count as a test failure. + */ +void +tor_set_failed_assertion_callback(void (*fn)(void)) +{ + failed_assertion_cb = fn; +} +#else +#define capturing_bugs() (0) +#define add_captured_bug(s) do { } while (0) +#endif + +/** Helper for tor_assert: report the assertion failure. */ +void +tor_assertion_failed_(const char *fname, unsigned int line, + const char *func, const char *expr) +{ + char buf[256]; + log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.", + fname, line, func, expr); + tor_snprintf(buf, sizeof(buf), + "Assertion %s failed in %s at %s:%u", + expr, func, fname, line); + log_backtrace(LOG_ERR, LD_BUG, buf); +} + +/** Helper for tor_assert_nonfatal: report the assertion failure. */ +void +tor_bug_occurred_(const char *fname, unsigned int line, + const char *func, const char *expr, + int once) +{ + char buf[256]; + const char *once_str = once ? + " (Future instances of this warning will be silenced.)": ""; + if (! expr) { + if (capturing_bugs()) { + add_captured_bug("This line should not have been reached."); + return; + } + log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s", + fname, line, func, once_str); + tor_snprintf(buf, sizeof(buf), + "Line unexpectedly reached at %s at %s:%u", + func, fname, line); + } else { + if (capturing_bugs()) { + add_captured_bug(expr); + return; + } + log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s", + fname, line, func, expr, once_str); + tor_snprintf(buf, sizeof(buf), + "Non-fatal assertion %s failed in %s at %s:%u", + expr, func, fname, line); + } + log_backtrace(LOG_WARN, LD_BUG, buf); + +#ifdef TOR_UNIT_TESTS + if (failed_assertion_cb) { + failed_assertion_cb(); + } +#endif +} + diff --git a/src/common/util_bug.h b/src/common/util_bug.h new file mode 100644 index 0000000000..e02778110b --- /dev/null +++ b/src/common/util_bug.h @@ -0,0 +1,160 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file util_bug.h + **/ + +#ifndef TOR_UTIL_BUG_H +#define TOR_UTIL_BUG_H + +#include "orconfig.h" +#include "compat.h" +#include "testsupport.h" + +/* Replace assert() with a variant that sends failures to the log before + * calling assert() normally. + */ +#ifdef NDEBUG +/* Nobody should ever want to build with NDEBUG set. 99% of our asserts will + * be outside the critical path anyway, so it's silly to disable bug-checking + * throughout the entire program just because a few asserts are slowing you + * down. Profile, optimize the critical path, and keep debugging on. + * + * And I'm not just saying that because some of our asserts check + * security-critical properties. + */ +#error "Sorry; we don't support building with NDEBUG." +#endif + +/* Sometimes we don't want to use assertions during branch coverage tests; it + * leads to tons of unreached branches which in reality are only assertions we + * didn't hit. */ +#if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) +#define tor_assert(a) STMT_BEGIN \ + (void)(a); \ + STMT_END +#else +/** Like assert(3), but send assertion failures to the log as well as to + * stderr. */ +#define tor_assert(expr) STMT_BEGIN \ + if (PREDICT_UNLIKELY(!(expr))) { \ + tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \ + abort(); \ + } STMT_END +#endif + +#define tor_assert_unreached() tor_assert(0) + +/* Non-fatal bug assertions. The "unreached" variants mean "this line should + * never be reached." The "once" variants mean "Don't log a warning more than + * once". + * + * The 'BUG' macro checks a boolean condition and logs an error message if it + * is true. Example usage: + * if (BUG(x == NULL)) + * return -1; + */ + +#ifdef ALL_BUGS_ARE_FATAL +#define tor_assert_nonfatal_unreached() tor_assert(0) +#define tor_assert_nonfatal(cond) tor_assert((cond)) +#define tor_assert_nonfatal_unreached_once() tor_assert(0) +#define tor_assert_nonfatal_once(cond) tor_assert((cond)) +#define BUG(cond) \ + (PREDICT_UNLIKELY(cond) ? \ + (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")"), \ + abort(), 1) \ + : 0) +#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) +#define tor_assert_nonfatal_unreached() STMT_NIL +#define tor_assert_nonfatal(cond) ((void)(cond)) +#define tor_assert_nonfatal_unreached_once() STMT_NIL +#define tor_assert_nonfatal_once(cond) ((void)(cond)) +#define BUG(cond) (PREDICT_UNLIKELY(cond) ? 1 : 0) +#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */ +#define tor_assert_nonfatal_unreached() STMT_BEGIN \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0); \ + STMT_END +#define tor_assert_nonfatal(cond) STMT_BEGIN \ + if (PREDICT_UNLIKELY(!(cond))) { \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0); \ + } \ + STMT_END +#define tor_assert_nonfatal_unreached_once() STMT_BEGIN \ + static int warning_logged__ = 0; \ + if (!warning_logged__) { \ + warning_logged__ = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1); \ + } \ + STMT_END +#define tor_assert_nonfatal_once(cond) STMT_BEGIN \ + static int warning_logged__ = 0; \ + if (!warning_logged__ && PREDICT_UNLIKELY(!(cond))) { \ + warning_logged__ = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1); \ + } \ + STMT_END +#define BUG(cond) \ + (PREDICT_UNLIKELY(cond) ? \ + (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0), 1) \ + : 0) +#endif + +#ifdef __GNUC__ +#define IF_BUG_ONCE__(cond,var) \ + if (( { \ + static int var = 0; \ + int bool_result = (cond); \ + if (PREDICT_UNLIKELY(bool_result) && !var) { \ + var = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ + "!("#cond")", 1); \ + } \ + PREDICT_UNLIKELY(bool_result); } )) +#else +#define IF_BUG_ONCE__(cond,var) \ + static int var = 0; \ + if (PREDICT_UNLIKELY(cond) ? \ + (var ? 1 : \ + (var=1, \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ + "!("#cond")", 1), \ + 1)) \ + : 0) +#endif +#define IF_BUG_ONCE_VARNAME_(a) \ + warning_logged_on_ ## a ## __ +#define IF_BUG_ONCE_VARNAME__(a) \ + IF_BUG_ONCE_VARNAME_(a) + +/** This macro behaves as 'if (bug(x))', except that it only logs its + * warning once, no matter how many times it triggers. + */ + +#define IF_BUG_ONCE(cond) \ + IF_BUG_ONCE__((cond), \ + IF_BUG_ONCE_VARNAME__(__LINE__)) + +/** Define this if you want Tor to crash when any problem comes up, + * so you can get a coredump and track things down. */ +// #define tor_fragile_assert() tor_assert_unreached(0) +#define tor_fragile_assert() tor_assert_nonfatal_unreached_once() + +void tor_assertion_failed_(const char *fname, unsigned int line, + const char *func, const char *expr); +void tor_bug_occurred_(const char *fname, unsigned int line, + const char *func, const char *expr, + int once); + +#ifdef TOR_UNIT_TESTS +void tor_capture_bugs_(int n); +void tor_end_capture_bugs_(void); +const struct smartlist_t *tor_get_captured_bug_log_(void); +void tor_set_failed_assertion_callback(void (*fn)(void)); +#endif + +#endif + diff --git a/src/common/util_format.c b/src/common/util_format.c index 8aae9e8771..aef9db85c8 100644 --- a/src/common/util_format.c +++ b/src/common/util_format.c @@ -21,33 +21,48 @@ #include <string.h> #include <stdlib.h> -/** Implements base32 encoding as in RFC 4648. Limitation: Requires - * that srclen*8 is a multiple of 5. - */ +/* Return the base32 encoded size in bytes using the source length srclen. + * The NUL terminated byte is added as well since every base32 encoding + * requires enough space for it. */ +size_t +base32_encoded_size(size_t srclen) +{ + size_t enclen; + enclen = CEIL_DIV(srclen*8, 5) + 1; + tor_assert(enclen < INT_MAX && enclen > srclen); + return enclen; +} + +/** Implements base32 encoding as in RFC 4648. */ void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen) { unsigned int i, v, u; - size_t nbits = srclen * 8, bit; + size_t nbits = srclen * 8; + size_t bit; tor_assert(srclen < SIZE_T_CEILING/8); - tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */ - tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */ + /* We need enough space for the encoded data and the extra NUL byte. */ + tor_assert(base32_encoded_size(srclen) <= destlen); tor_assert(destlen < SIZE_T_CEILING); + /* Make sure we leave no uninitialized data in the destination buffer. */ + memset(dest, 0, destlen); + for (i=0,bit=0; bit < nbits; ++i, bit+=5) { /* set v to the 16-bit value starting at src[bits/8], 0-padded. */ v = ((uint8_t)src[bit/8]) << 8; - if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1]; - /* set u to the 5-bit value at the bit'th bit of src. */ + if (bit+5<nbits) + v += (uint8_t)src[(bit/8)+1]; + /* set u to the 5-bit value at the bit'th bit of buf. */ u = (v >> (11-(bit%8))) & 0x1F; dest[i] = BASE32_CHARS[u]; } dest[i] = '\0'; } -/** Implements base32 decoding as in RFC 4648. Limitation: Requires - * that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise. +/** Implements base32 decoding as in RFC 4648. + * Returns 0 if successful, -1 otherwise. */ int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) @@ -57,13 +72,13 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) unsigned int i; size_t nbits, j, bit; char *tmp; - nbits = srclen * 5; + nbits = ((srclen * 5) / 8) * 8; tor_assert(srclen < SIZE_T_CEILING / 5); - tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */ tor_assert((nbits/8) <= destlen); /* We need enough space. */ tor_assert(destlen < SIZE_T_CEILING); + /* Make sure we leave no uninitialized data in the destination buffer. */ memset(dest, 0, destlen); /* Convert base32 encoded chars to the 5-bit values that they represent. */ @@ -73,7 +88,7 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen) else if (src[j] > 0x31 && src[j] < 0x38) tmp[j] = src[j] - 0x18; else if (src[j] > 0x40 && src[j] < 0x5B) tmp[j] = src[j] - 0x41; else { - log_warn(LD_BUG, "illegal character in base32 encoded string"); + log_warn(LD_GENERAL, "illegal character in base32 encoded string"); tor_free(tmp); return -1; } @@ -186,7 +201,8 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, if (enclen > INT_MAX) return -1; - memset(dest, 0, enclen); + /* Make sure we leave no uninitialized data in the destination buffer. */ + memset(dest, 0, destlen); /* XXX/Yawning: If this ends up being too slow, this can be sped up * by separating the multiline format case and the normal case, and @@ -249,7 +265,7 @@ base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, break; default: /* Something went catastrophically wrong. */ - tor_fragile_assert(); + tor_fragile_assert(); // LCOV_EXCL_LINE return -1; } @@ -387,6 +403,7 @@ base64_decode(char *dest, size_t destlen, const char *src, size_t srclen) if (destlen > SIZE_T_CEILING) return -1; + /* Make sure we leave no uninitialized data in the destination buffer. */ memset(dest, 0, destlen); /* Iterate over all the bytes in src. Each one will add 0 or 6 bits to the @@ -461,6 +478,9 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen) tor_assert(destlen >= srclen*2+1); tor_assert(destlen < SIZE_T_CEILING); + /* Make sure we leave no uninitialized data in the destination buffer. */ + memset(dest, 0, destlen); + cp = dest; end = src+srclen; while (src<end) { @@ -504,20 +524,24 @@ hex_decode_digit(char c) return hex_decode_digit_(c); } -/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode it - * and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>. - * Return 0 on success, -1 on failure. */ +/** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode + * it and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>. + * Return the number of bytes decoded on success, -1 on failure. If + * <b>destlen</b> is greater than INT_MAX or less than half of + * <b>srclen</b>, -1 is returned. */ int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) { const char *end; - + char *dest_orig = dest; int v1,v2; + if ((srclen % 2) != 0) return -1; - if (destlen < srclen/2 || destlen > SIZE_T_CEILING) + if (destlen < srclen/2 || destlen > INT_MAX) return -1; + /* Make sure we leave no uninitialized data in the destination buffer. */ memset(dest, 0, destlen); end = src+srclen; @@ -530,6 +554,9 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) ++dest; src+=2; } - return 0; + + tor_assert((dest-dest_orig) <= (ptrdiff_t) destlen); + + return (int) (dest-dest_orig); } diff --git a/src/common/util_format.h b/src/common/util_format.h index a748a4f3cf..20ac711d10 100644 --- a/src/common/util_format.h +++ b/src/common/util_format.h @@ -24,6 +24,7 @@ int base64_decode_nopad(uint8_t *dest, size_t destlen, #define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567" void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen); +size_t base32_encoded_size(size_t srclen); int hex_decode_digit(char c); void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen); diff --git a/src/common/util_process.c b/src/common/util_process.c index 848b238318..abda63720c 100644 --- a/src/common/util_process.c +++ b/src/common/util_process.c @@ -61,9 +61,9 @@ process_map_entries_eq_(const waitpid_callback_t *a, static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER(); HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_, - process_map_entries_eq_); + process_map_entries_eq_) HT_GENERATE2(process_map, waitpid_callback_t, node, process_map_entry_hash_, - process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_); + process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_) /** * Begin monitoring the child pid <b>pid</b> to see if we get a SIGCHLD for diff --git a/src/common/workqueue.c b/src/common/workqueue.c index 0a38550de0..e1fb663a2a 100644 --- a/src/common/workqueue.c +++ b/src/common/workqueue.c @@ -6,6 +6,20 @@ * * \brief Implements worker threads, queues of work for them, and mechanisms * for them to send answers back to the main thread. + * + * The main structure here is a threadpool_t : it manages a set of worker + * threads, a queue of pending work, and a reply queue. Every piece of work + * is a workqueue_entry_t, containing data to process and a function to + * process it with. + * + * The main thread informs the worker threads of pending work by using a + * condition variable. The workers inform the main process of completed work + * by using an alert_sockets_t object, as implemented in compat_threads.c. + * + * The main thread can also queue an "update" that will be handled by all the + * workers. This is useful for updating state that all the workers share. + * + * In Tor today, there is currently only one thread pool, used in cpuworker.c. */ #include "orconfig.h" @@ -262,9 +276,12 @@ workerthread_new(void *state, threadpool_t *pool, replyqueue_t *replyqueue) thr->in_pool = pool; if (spawn_func(worker_thread_main, thr) < 0) { + //LCOV_EXCL_START + tor_assert_nonfatal_unreached(); log_err(LD_GENERAL, "Can't launch worker thread."); tor_free(thr); return NULL; + //LCOV_EXCL_STOP } return thr; @@ -375,8 +392,8 @@ threadpool_queue_update(threadpool_t *pool, static int threadpool_start_threads(threadpool_t *pool, int n) { - if (n < 0) - return -1; + if (BUG(n < 0)) + return -1; // LCOV_EXCL_LINE if (n > MAX_THREADS) n = MAX_THREADS; @@ -391,9 +408,12 @@ threadpool_start_threads(threadpool_t *pool, int n) workerthread_t *thr = workerthread_new(state, pool, pool->reply_queue); if (!thr) { + //LCOV_EXCL_START + tor_assert_nonfatal_unreached(); pool->free_thread_state_fn(state); tor_mutex_release(&pool->lock); return -1; + //LCOV_EXCL_STOP } thr->index = pool->n_threads; pool->threads[pool->n_threads++] = thr; @@ -429,10 +449,13 @@ threadpool_new(int n_threads, pool->reply_queue = replyqueue; if (threadpool_start_threads(pool, n_threads) < 0) { + //LCOV_EXCL_START + tor_assert_nonfatal_unreached(); tor_cond_uninit(&pool->condition); tor_mutex_uninit(&pool->lock); tor_free(pool); return NULL; + //LCOV_EXCL_STOP } return pool; @@ -456,8 +479,10 @@ replyqueue_new(uint32_t alertsocks_flags) rq = tor_malloc_zero(sizeof(replyqueue_t)); if (alert_sockets_create(&rq->alert, alertsocks_flags) < 0) { + //LCOV_EXCL_START tor_free(rq); return NULL; + //LCOV_EXCL_STOP } tor_mutex_init(&rq->lock); @@ -486,10 +511,12 @@ void replyqueue_process(replyqueue_t *queue) { if (queue->alert.drain_fn(queue->alert.read_fd) < 0) { + //LCOV_EXCL_START static ratelim_t warn_limit = RATELIM_INIT(7200); log_fn_ratelim(&warn_limit, LOG_WARN, LD_GENERAL, "Failure from drain_fd: %s", tor_socket_strerror(tor_socket_errno(queue->alert.read_fd))); + //LCOV_EXCL_STOP } tor_mutex_acquire(&queue->lock); diff --git a/src/common/workqueue.h b/src/common/workqueue.h index 89282e6f21..54276767b0 100644 --- a/src/common/workqueue.h +++ b/src/common/workqueue.h @@ -7,7 +7,7 @@ #include "compat.h" /** A replyqueue is used to tell the main thread about the outcome of - * work that we queued for the the workers. */ + * work that we queued for the workers. */ typedef struct replyqueue_s replyqueue_t; /** A thread-pool manages starting threads and passing work to them. */ typedef struct threadpool_s threadpool_t; |