diff options
Diffstat (limited to 'src/lib')
62 files changed, 640 insertions, 208 deletions
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c index d7b73e3807..a5031a47a6 100644 --- a/src/lib/buf/buffers.c +++ b/src/lib/buf/buffers.c @@ -285,7 +285,7 @@ buf_t * buf_new_with_data(const char *cp, size_t sz) { /* Validate arguments */ - if (!cp || sz <= 0 || sz >= INT_MAX) { + if (!cp || sz <= 0 || sz > BUF_MAX_LEN) { return NULL; } @@ -530,9 +530,9 @@ buf_add(buf_t *buf, const char *string, size_t string_len) return (int)buf->datalen; check(); - if (BUG(buf->datalen >= INT_MAX)) + if (BUG(buf->datalen > BUF_MAX_LEN)) return -1; - if (BUG(buf->datalen >= INT_MAX - string_len)) + if (BUG(buf->datalen > BUF_MAX_LEN - string_len)) return -1; while (string_len) { @@ -551,7 +551,7 @@ buf_add(buf_t *buf, const char *string, size_t string_len) } check(); - tor_assert(buf->datalen < INT_MAX); + tor_assert(buf->datalen <= BUF_MAX_LEN); return (int)buf->datalen; } @@ -645,7 +645,7 @@ buf_get_bytes(buf_t *buf, char *string, size_t string_len) buf_peek(buf, string, string_len); buf_drain(buf, string_len); check(); - tor_assert(buf->datalen < INT_MAX); + tor_assert(buf->datalen <= BUF_MAX_LEN); return (int)buf->datalen; } @@ -660,9 +660,9 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) char b[4096]; size_t cp, len; - if (BUG(buf_out->datalen >= INT_MAX || *buf_flushlen >= INT_MAX)) + if (BUG(buf_out->datalen > BUF_MAX_LEN || *buf_flushlen > BUF_MAX_LEN)) return -1; - if (BUG(buf_out->datalen >= INT_MAX - *buf_flushlen)) + if (BUG(buf_out->datalen > BUF_MAX_LEN - *buf_flushlen)) return -1; len = *buf_flushlen; @@ -670,7 +670,7 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen) len = buf_in->datalen; cp = len; /* Remember the number of bytes we intend to copy. */ - tor_assert(cp < INT_MAX); + tor_assert(cp <= BUF_MAX_LEN); while (len) { /* This isn't the most efficient implementation one could imagine, since * it does two copies instead of 1, but I kinda doubt that this will be @@ -694,9 +694,9 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in) return; if (buf_datalen(buf_in) == 0) return; - if (BUG(buf_out->datalen >= INT_MAX || buf_in->datalen >= INT_MAX)) + if (BUG(buf_out->datalen > BUF_MAX_LEN || buf_in->datalen > BUF_MAX_LEN)) return; - if (BUG(buf_out->datalen >= INT_MAX - buf_in->datalen)) + if (BUG(buf_out->datalen > BUF_MAX_LEN - buf_in->datalen)) return; if (buf_out->head == NULL) { @@ -750,7 +750,7 @@ buf_find_pos_of_char(char ch, buf_pos_t *out) char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos); if (cp) { out->chunk = chunk; - tor_assert(cp - chunk->data < INT_MAX); + tor_assert(cp - chunk->data <= BUF_MAX_LEN); out->pos = (int)(cp - chunk->data); return out->chunk_pos + out->pos; } else { @@ -766,7 +766,7 @@ buf_find_pos_of_char(char ch, buf_pos_t *out) static inline int buf_pos_inc(buf_pos_t *pos) { - tor_assert(pos->pos < INT_MAX - 1); + tor_assert(pos->pos < BUF_MAX_LEN); ++pos->pos; if (pos->pos == (ptrdiff_t)pos->chunk->datalen) { if (!pos->chunk->next) @@ -813,7 +813,7 @@ buf_find_string_offset(const buf_t *buf, const char *s, size_t n) buf_pos_init(buf, &pos); while (buf_find_pos_of_char(*s, &pos) >= 0) { if (buf_matches_at_pos(&pos, s, n)) { - tor_assert(pos.chunk_pos + pos.pos < INT_MAX); + tor_assert(pos.chunk_pos + pos.pos <= BUF_MAX_LEN); return (int)(pos.chunk_pos + pos.pos); } else { if (buf_pos_inc(&pos)<0) @@ -847,7 +847,7 @@ buf_find_offset_of_char(buf_t *buf, char ch) { chunk_t *chunk; ptrdiff_t offset = 0; - tor_assert(buf->datalen < INT_MAX); + tor_assert(buf->datalen <= BUF_MAX_LEN); for (chunk = buf->head; chunk; chunk = chunk->next) { char *cp = memchr(chunk->data, ch, chunk->datalen); if (cp) @@ -917,7 +917,7 @@ buf_assert_ok(buf_t *buf) for (ch = buf->head; ch; ch = ch->next) { total += ch->datalen; tor_assert(ch->datalen <= ch->memlen); - tor_assert(ch->datalen < INT_MAX); + tor_assert(ch->datalen <= BUF_MAX_LEN); tor_assert(ch->data >= &ch->mem[0]); tor_assert(ch->data <= &ch->mem[0]+ch->memlen); if (ch->data == &ch->mem[0]+ch->memlen) { diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h index fadd4174c0..d8a77feb72 100644 --- a/src/lib/buf/buffers.h +++ b/src/lib/buf/buffers.h @@ -29,6 +29,9 @@ void buf_free_(buf_t *buf); void buf_clear(buf_t *buf); buf_t *buf_copy(const buf_t *buf); +/** Maximum bytes in a buffer, inclusive. */ +#define BUF_MAX_LEN (INT_MAX - 1) + MOCK_DECL(size_t, buf_datalen, (const buf_t *buf)); size_t buf_allocation(const buf_t *buf); size_t buf_slack(const buf_t *buf); diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h index 015b5af320..96aa912652 100644 --- a/src/lib/cc/compat_compiler.h +++ b/src/lib/cc/compat_compiler.h @@ -25,11 +25,11 @@ #endif /* defined(__has_feature) */ #ifndef NULL_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent NULL as zero. We can't cope." +#error "Your platform does not represent NULL as zero. We can't cope." #endif #ifndef DOUBLE_0_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent 0.0 as zeros. We can't cope." +#error "Your platform does not represent 0.0 as zeros. We can't cope." #endif #if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h index cef1482bdc..af7a90431c 100644 --- a/src/lib/cc/torint.h +++ b/src/lib/cc/torint.h @@ -49,7 +49,7 @@ typedef int32_t ssize_t; * aren't 2's complement, and you don't define LONG_MAX, then you're so * bizarre that I want nothing to do with you. */ #ifndef USING_TWOS_COMPLEMENT -#error "Seems that your platform doesn't use 2's complement arithmetic. Argh." +#error "Your platform doesn't use 2's complement arithmetic." #endif #ifndef TIME_MAX @@ -126,12 +126,11 @@ typedef int32_t ssize_t; #define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16)) #if SIZEOF_INT > SIZEOF_VOID_P -#error "sizeof(int) > sizeof(void *) - Tor cannot be built on this platform!" +#error "sizeof(int) > sizeof(void *) - Can't build Tor here." #endif #if SIZEOF_UNSIGNED_INT > SIZEOF_VOID_P -#error "sizeof(unsigned int) > sizeof(void *) - Tor cannot be built on this \ -platform!" +#error "sizeof(unsigned int) > sizeof(void *) - Can't build Tor here." #endif #endif /* !defined(TOR_TORINT_H) */ diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c index c62d7d5d2a..7ce3910d84 100644 --- a/src/lib/compress/compress.c +++ b/src/lib/compress/compress.c @@ -694,7 +694,8 @@ subsys_compress_initialize(void) const subsys_fns_t sys_compress = { .name = "compress", + SUBSYS_DECLARE_LOCATION(), .supported = true, - .level = -70, + .level = -55, .initialize = subsys_compress_initialize, }; diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h index ebc2736aaa..081ebf397f 100644 --- a/src/lib/conf/conftypes.h +++ b/src/lib/conf/conftypes.h @@ -260,6 +260,7 @@ typedef struct config_deprecation_t { const char *why_deprecated; } config_deprecation_t; +#ifndef COCCI /** * Handy macro for declaring "In the config file or on the command line, you * can abbreviate <b>tok</b>s as <b>tok</b>". Used inside an array of @@ -268,7 +269,8 @@ typedef struct config_deprecation_t { * For example, to declare "NumCpu" as an abbreviation for "NumCPUs", * you can say PLURAL(NumCpu). **/ -#define PLURAL(tok) { #tok, #tok "s", 0, 0 } +#define PLURAL(tok) { (#tok), (#tok "s"), 0, 0 } +#endif /* !defined(COCCI) */ /** * Validation function: verify whether a configuation object is well-formed diff --git a/src/lib/confmgt/unitparse.c b/src/lib/confmgt/unitparse.c index 61edc60694..99716e8d9d 100644 --- a/src/lib/confmgt/unitparse.c +++ b/src/lib/confmgt/unitparse.c @@ -23,6 +23,7 @@ /** Table to map the names of memory units to the number of bytes they * contain. */ +// clang-format off const struct unit_table_t memory_units[] = { { "", 1 }, { "b", 1<< 0 }, @@ -67,9 +68,11 @@ const struct unit_table_t memory_units[] = { { "tbit", UINT64_C(1)<<37 }, { NULL, 0 }, }; +// clang-format on /** Table to map the names of time units to the number of seconds they * contain. */ +// clang-format off const struct unit_table_t time_units[] = { { "", 1 }, { "second", 1 }, @@ -86,9 +89,11 @@ const struct unit_table_t time_units[] = { { "months", 2629728, }, { NULL, 0 }, }; +// clang-format on /** Table to map the names of time units to the number of milliseconds * they contain. */ +// clang-format off const struct unit_table_t time_msec_units[] = { { "", 1 }, { "msec", 1 }, @@ -106,6 +111,7 @@ const struct unit_table_t time_msec_units[] = { { "weeks", 7*24*60*60*1000 }, { NULL, 0 }, }; +// clang-format on /** Parse a string <b>val</b> containing a number, zero or more * spaces, and an optional unit string. If the unit appears in the diff --git a/src/lib/container/map.c b/src/lib/container/map.c index c3fb0b5c8a..7db84313ea 100644 --- a/src/lib/container/map.c +++ b/src/lib/container/map.c @@ -85,21 +85,21 @@ digest256map_entry_hash(const digest256map_entry_t *a) } HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq) + strmap_entries_eq); HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) + strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_); HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq) + digestmap_entries_eq); HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) + digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_); HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, digest256map_entry_hash, - digest256map_entries_eq) + digest256map_entries_eq); HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, digest256map_entry_hash, - digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_) + digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_); #define strmap_entry_free(ent) \ FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) diff --git a/src/lib/container/map.h b/src/lib/container/map.h index 989ecfad80..dbc1967247 100644 --- a/src/lib/container/map.h +++ b/src/lib/container/map.h @@ -19,29 +19,29 @@ #define DECLARE_MAP_FNS(mapname_t, keytype, prefix) \ typedef struct mapname_t mapname_t; \ - typedef struct prefix##entry_t *prefix##iter_t; \ - MOCK_DECL(mapname_t*, prefix##new, (void)); \ - void* prefix##set(mapname_t *map, keytype key, void *val); \ - void* prefix##get(const mapname_t *map, keytype key); \ - void* prefix##remove(mapname_t *map, keytype key); \ - MOCK_DECL(void, prefix##free_, (mapname_t *map, void (*free_val)(void*))); \ - int prefix##isempty(const mapname_t *map); \ - int prefix##size(const mapname_t *map); \ - prefix##iter_t *prefix##iter_init(mapname_t *map); \ - prefix##iter_t *prefix##iter_next(mapname_t *map, prefix##iter_t *iter); \ - prefix##iter_t *prefix##iter_next_rmv(mapname_t *map, \ - prefix##iter_t *iter); \ - void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ - int prefix##iter_done(prefix##iter_t *iter); \ - void prefix##assert_ok(const mapname_t *map) + typedef struct prefix##_entry_t *prefix##_iter_t; \ + MOCK_DECL(mapname_t*, prefix##_new, (void)); \ + void* prefix##_set(mapname_t *map, keytype key, void *val); \ + void* prefix##_get(const mapname_t *map, keytype key); \ + void* prefix##_remove(mapname_t *map, keytype key); \ + MOCK_DECL(void, prefix##_free_, (mapname_t *map, void (*free_val)(void*))); \ + int prefix##_isempty(const mapname_t *map); \ + int prefix##_size(const mapname_t *map); \ + prefix##_iter_t *prefix##_iter_init(mapname_t *map); \ + prefix##_iter_t *prefix##_iter_next(mapname_t *map, prefix##_iter_t *iter); \ + prefix##_iter_t *prefix##_iter_next_rmv(mapname_t *map, \ + prefix##_iter_t *iter); \ + void prefix##_iter_get(prefix##_iter_t *iter, keytype *keyp, void **valp); \ + int prefix##_iter_done(prefix##_iter_t *iter); \ + void prefix##_assert_ok(const mapname_t *map) /* Map from const char * to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(strmap_t, const char *, strmap_); +DECLARE_MAP_FNS(strmap_t, const char *, strmap); /* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); +DECLARE_MAP_FNS(digestmap_t, const char *, digestmap); /* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash * table. */ -DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); +DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map); #define MAP_FREE_AND_NULL(mapname_t, map, fn) \ do { \ @@ -56,12 +56,12 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); #undef DECLARE_MAP_FNS /** Iterates over the key-value pairs in a map <b>map</b> in order. - * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). + * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap or digestmap). * The map's keys and values are of type keytype and valtype respectively; * each iteration assigns them to keyvar and valvar. * * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * MAP_FOREACH(digestmap, m, const char *, k, routerinfo_t *, r) { * // use k and r * } MAP_FOREACH_END. */ @@ -81,21 +81,21 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); */ #define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ + prefix##_iter_t *keyvar##_iter; \ + for (keyvar##_iter = prefix##_iter_init(map); \ + !prefix##_iter_done(keyvar##_iter); \ + keyvar##_iter = prefix##_iter_next(map, keyvar##_iter)) { \ keytype keyvar; \ void *valvar##_voidp; \ valtype valvar; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + prefix##_iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ valvar = valvar##_voidp; /** As MAP_FOREACH, except allows members to be removed from the map * during the iteration via MAP_DEL_CURRENT. Example use: * * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * MAP_FOREACH(digestmap, m, const char *, k, routerinfo_t *, r) { * if (is_very_old(r)) * MAP_DEL_CURRENT(k); * } MAP_FOREACH_END. @@ -121,18 +121,18 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); */ #define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ + prefix##_iter_t *keyvar##_iter; \ int keyvar##_del=0; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ + for (keyvar##_iter = prefix##_iter_init(map); \ + !prefix##_iter_done(keyvar##_iter); \ keyvar##_iter = keyvar##_del ? \ - prefix##iter_next_rmv(map, keyvar##_iter) : \ - prefix##iter_next(map, keyvar##_iter)) { \ + prefix##_iter_next_rmv(map, keyvar##_iter) : \ + prefix##_iter_next(map, keyvar##_iter)) { \ keytype keyvar; \ void *valvar##_voidp; \ valtype valvar; \ keyvar##_del=0; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + prefix##_iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ valvar = valvar##_voidp; /** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon @@ -152,7 +152,7 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); * } DIGESTMAP_FOREACH_END. */ #define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) + MAP_FOREACH(digestmap, map, const char *, keyvar, valtype, valvar) /** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or * keytype. @@ -163,21 +163,21 @@ DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); * } DIGESTMAP_FOREACH_END. */ #define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) + MAP_FOREACH_MODIFY(digestmap, map, const char *, keyvar, valtype, valvar) /** Used to end a DIGESTMAP_FOREACH() block. */ #define DIGESTMAP_FOREACH_END MAP_FOREACH_END #define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar) + MAP_FOREACH(digest256map, map, const uint8_t *, keyvar, valtype, valvar) #define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \ + MAP_FOREACH_MODIFY(digest256map, map, const uint8_t *, \ keyvar, valtype, valvar) #define DIGEST256MAP_FOREACH_END MAP_FOREACH_END #define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) + MAP_FOREACH(strmap, map, const char *, keyvar, valtype, valvar) #define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) + MAP_FOREACH_MODIFY(strmap, map, const char *, keyvar, valtype, valvar) #define STRMAP_FOREACH_END MAP_FOREACH_END void* strmap_set_lc(strmap_t *map, const char *key, void *val); @@ -186,66 +186,66 @@ void* strmap_remove_lc(strmap_t *map, const char *key); #define DECLARE_TYPED_DIGESTMAP_FNS(prefix, mapname_t, valtype) \ typedef struct mapname_t mapname_t; \ - typedef struct prefix##iter_t *prefix##iter_t; \ + typedef struct prefix##_iter_t *prefix##_iter_t; \ ATTR_UNUSED static inline mapname_t* \ - prefix##new(void) \ + prefix##_new(void) \ { \ return (mapname_t*)digestmap_new(); \ } \ ATTR_UNUSED static inline digestmap_t* \ - prefix##to_digestmap(mapname_t *map) \ + prefix##_to_digestmap(mapname_t *map) \ { \ return (digestmap_t*)map; \ } \ ATTR_UNUSED static inline valtype* \ - prefix##get(mapname_t *map, const char *key) \ + prefix##_get(mapname_t *map, const char *key) \ { \ return (valtype*)digestmap_get((digestmap_t*)map, key); \ } \ ATTR_UNUSED static inline valtype* \ - prefix##set(mapname_t *map, const char *key, valtype *val) \ + prefix##_set(mapname_t *map, const char *key, valtype *val) \ { \ return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ } \ ATTR_UNUSED static inline valtype* \ - prefix##remove(mapname_t *map, const char *key) \ + prefix##_remove(mapname_t *map, const char *key) \ { \ return (valtype*)digestmap_remove((digestmap_t*)map, key); \ } \ ATTR_UNUSED static inline void \ - prefix##f##ree_(mapname_t *map, void (*free_val)(void*)) \ + prefix##_f##ree_(mapname_t *map, void (*free_val)(void*)) \ { \ digestmap_free_((digestmap_t*)map, free_val); \ } \ ATTR_UNUSED static inline int \ - prefix##isempty(mapname_t *map) \ + prefix##_isempty(mapname_t *map) \ { \ return digestmap_isempty((digestmap_t*)map); \ } \ ATTR_UNUSED static inline int \ - prefix##size(mapname_t *map) \ + prefix##_size(mapname_t *map) \ { \ return digestmap_size((digestmap_t*)map); \ } \ ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_init(mapname_t *map) \ + prefix##_iter_t *prefix##_iter_init(mapname_t *map) \ { \ - return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ + return (prefix##_iter_t*) digestmap_iter_init((digestmap_t*)map); \ } \ ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_next(mapname_t *map, prefix##iter_t *iter) \ + prefix##_iter_t *prefix##_iter_next(mapname_t *map, prefix##_iter_t *iter) \ { \ - return (prefix##iter_t*) digestmap_iter_next( \ + return (prefix##_iter_t*) digestmap_iter_next( \ (digestmap_t*)map, (digestmap_iter_t*)iter); \ } \ - ATTR_UNUSED static inline prefix##iter_t* \ - prefix##iter_next_rmv(mapname_t *map, prefix##iter_t *iter) \ + ATTR_UNUSED static inline prefix##_iter_t* \ + prefix##_iter_next_rmv(mapname_t *map, prefix##_iter_t *iter) \ { \ - return (prefix##iter_t*) digestmap_iter_next_rmv( \ + return (prefix##_iter_t*) digestmap_iter_next_rmv( \ (digestmap_t*)map, (digestmap_iter_t*)iter); \ } \ ATTR_UNUSED static inline void \ - prefix##iter_get(prefix##iter_t *iter, \ + prefix##_iter_get(prefix##_iter_t *iter, \ const char **keyp, \ valtype **valp) \ { \ @@ -254,7 +254,7 @@ void* strmap_remove_lc(strmap_t *map, const char *key); *valp = v; \ } \ ATTR_UNUSED static inline int \ - prefix##iter_done(prefix##iter_t *iter) \ + prefix##_iter_done(prefix##_iter_t *iter) \ { \ return digestmap_iter_done((digestmap_iter_t*)iter); \ } diff --git a/src/lib/container/namemap.c b/src/lib/container/namemap.c index 28695ee3a1..e286cad947 100644 --- a/src/lib/container/namemap.c +++ b/src/lib/container/namemap.c @@ -35,9 +35,9 @@ mapped_name_hash(const mapped_name_t *a) } HT_PROTOTYPE(namemap_ht, mapped_name_t, node, mapped_name_hash, - mapped_name_eq) + mapped_name_eq); HT_GENERATE2(namemap_ht, mapped_name_t, node, mapped_name_hash, - mapped_name_eq, 0.6, tor_reallocarray_, tor_free_) + mapped_name_eq, 0.6, tor_reallocarray_, tor_free_); /** Set up an uninitialized <b>map</b>. */ void diff --git a/src/lib/crypt_ops/certs.md b/src/lib/crypt_ops/certs.md index 2768548b2a..f3bd8c2c96 100644 --- a/src/lib/crypt_ops/certs.md +++ b/src/lib/crypt_ops/certs.md @@ -1,5 +1,5 @@ -@page certificates Certificates in Tor. +@page certificates Certificates in Tor We have, alas, several certificate types in Tor. @@ -27,4 +27,3 @@ their associated keys. documents that include keys and which are signed by keys. You can consider these documents to be an additional kind of certificate if you want.) - diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c index f09bf07c4d..a836bd8645 100644 --- a/src/lib/crypt_ops/crypto_init.c +++ b/src/lib/crypt_ops/crypto_init.c @@ -317,6 +317,7 @@ crypto_set_options(void *arg) const struct subsys_fns_t sys_crypto = { .name = "crypto", + SUBSYS_DECLARE_LOCATION(), .supported = true, .level = -60, .initialize = subsys_crypto_initialize, diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c index ffbfa2d56c..b2516c4bdc 100644 --- a/src/lib/crypt_ops/crypto_rand_numeric.c +++ b/src/lib/crypt_ops/crypto_rand_numeric.c @@ -33,8 +33,8 @@ /** * Return a pseudorandom integer chosen uniformly from the values between 0 - * and <b>limit</b>-1 inclusive. limit must be strictly between 0 and - * UINT_MAX. */ + * and <b>limit</b>-1 inclusive. limit must be strictly greater than 0, and + * less than UINT_MAX. */ unsigned crypto_rand_uint(unsigned limit) { diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c index d54db43b92..c96ee81fd3 100644 --- a/src/lib/crypt_ops/crypto_rsa_openssl.c +++ b/src/lib/crypt_ops/crypto_rsa_openssl.c @@ -583,15 +583,15 @@ rsa_private_key_too_long(RSA *rsa, int max_bits) dmp1 = RSA_get0_dmp1(rsa); dmq1 = RSA_get0_dmq1(rsa); iqmp = RSA_get0_iqmp(rsa); -#else +#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1)) */ /* The accessors above did not exist in openssl 1.1.0. */ p = q = dmp1 = dmq1 = iqmp = NULL; RSA_get0_key(rsa, &n, &e, &d); -#endif +#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1) */ if (RSA_bits(rsa) > max_bits) return true; -#else +#else /* !defined(OPENSSL_1_1_API) */ n = rsa->n; e = rsa->e; p = rsa->p; @@ -600,7 +600,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits) dmp1 = rsa->dmp1; dmq1 = rsa->dmq1; iqmp = rsa->iqmp; -#endif +#endif /* defined(OPENSSL_1_1_API) */ if (n && BN_num_bits(n) > max_bits) return true; diff --git a/src/lib/crypt_ops/crypto_util.c b/src/lib/crypt_ops/crypto_util.c index 60e81af165..7ebb860d09 100644 --- a/src/lib/crypt_ops/crypto_util.c +++ b/src/lib/crypt_ops/crypto_util.c @@ -107,3 +107,17 @@ memwipe(void *mem, uint8_t byte, size_t sz) **/ memset(mem, byte, sz); } + +/** + * Securely all memory in <b>str</b>, then free it. + * + * As tor_free(), tolerates null pointers. + **/ +void +tor_str_wipe_and_free_(char *str) +{ + if (!str) + return; + memwipe(str, 0, strlen(str)); + tor_free_(str); +} diff --git a/src/lib/crypt_ops/crypto_util.h b/src/lib/crypt_ops/crypto_util.h index 4c08180f92..36ee230176 100644 --- a/src/lib/crypt_ops/crypto_util.h +++ b/src/lib/crypt_ops/crypto_util.h @@ -14,8 +14,18 @@ #define TOR_CRYPTO_UTIL_H #include "lib/cc/torint.h" +#include "lib/malloc/malloc.h" /** OpenSSL-based utility functions. */ void memwipe(void *mem, uint8_t byte, size_t sz); +void tor_str_wipe_and_free_(char *str); +/** + * Securely all memory in <b>str</b>, then free it. + * + * As tor_free(), tolerates null pointers, and sets <b>str</b> to NULL. + **/ +#define tor_str_wipe_and_free(str) \ + FREE_AND_NULL(char, tor_str_wipe_and_free_, (str)) + #endif /* !defined(TOR_CRYPTO_UTIL_H) */ diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c index 7448a9973e..d57d286990 100644 --- a/src/lib/ctime/di_ops.c +++ b/src/lib/ctime/di_ops.c @@ -72,10 +72,10 @@ tor_memcmp(const void *a, const void *b, size_t len) * actually implementation-defined in standard C. So how do we * get away with assuming it? Easy. We check.) */ #if ((-60 >> 8) != -1) -#error "According to cpp, right-shift doesn't perform sign-extension." +#error "cpp says right-shift doesn't perform sign-extension." #endif #ifndef RSHIFT_DOES_SIGN_EXTEND -#error "According to configure, right-shift doesn't perform sign-extension." +#error "configure says right-shift doesn't perform sign-extension." #endif /* If v1 == v2, equal_p is ~0, so this will leave retval @@ -279,3 +279,30 @@ select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, return i_chosen; } + +/** + * If <b>s</b> is true, then copy <b>n</b> bytes from <b>src</b> to + * <b>dest</b>. Otherwise leave <b>dest</b> alone. + * + * This function behaves the same as + * + * if (s) + * memcpy(dest, src, n); + * + * except that it tries to run in the same amount of time whether <b>s</b> is + * true or not. + **/ +void +memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n) +{ + // If s is true, mask will be ~0. If s is false, mask will be 0. + const char mask = (char) -(signed char)s; + + char *destp = dest; + const char *srcp = src; + for (size_t i = 0; i < n; ++i) { + *destp = (*destp & ~mask) | (*srcp & mask); + ++destp; + ++srcp; + } +} diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h index 4ff8f03165..9fe2884ecc 100644 --- a/src/lib/ctime/di_ops.h +++ b/src/lib/ctime/di_ops.h @@ -73,4 +73,6 @@ int select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, uint64_t total, uint64_t rand_val); +void memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n); + #endif /* !defined(TOR_DI_OPS_H) */ diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c index ff8bacba3c..613e4a00c6 100644 --- a/src/lib/encoding/confline.c +++ b/src/lib/encoding/confline.c @@ -151,6 +151,8 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended, if (allow_include && !strcmp(k, "%include") && handle_include) { tor_free(k); include_used = 1; + log_notice(LD_CONFIG, "Processing configuration path \"%s\" at " + "recursion level %d.", v, recursion_level); config_line_t *include_list; if (handle_include(v, recursion_level, extended, &include_list, @@ -161,9 +163,6 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended, tor_free(v); return -1; } - log_notice(LD_CONFIG, "Included configuration file or " - "directory at recursion level %d: \"%s\".", - recursion_level, v); *next = include_list; if (list_last) next = &list_last->next; @@ -253,6 +252,35 @@ config_lines_dup_and_filter(const config_line_t *inp, return result; } +/** + * Given a linelist <b>inp</b> beginning with the key <b>header</b>, find the + * next line with that key, and remove that instance and all following lines + * from the list. Return the lines that were removed. Operate + * case-insensitively. + * + * For example, if the header is "H", and <b>inp</b> contains "H, A, B, H, C, + * H, D", this function will alter <b>inp</b> to contain only "H, A, B", and + * return the elements "H, C, H, D" as a separate list. + **/ +config_line_t * +config_lines_partition(config_line_t *inp, const char *header) +{ + if (BUG(inp == NULL)) + return NULL; + if (BUG(strcasecmp(inp->key, header))) + return NULL; + + /* Advance ptr until it points to the link to the next segment of this + list. */ + config_line_t **ptr = &inp->next; + while (*ptr && strcasecmp((*ptr)->key, header)) { + ptr = &(*ptr)->next; + } + config_line_t *remainder = *ptr; + *ptr = NULL; + return remainder; +} + /** Return true iff a and b contain identical keys and values in identical * order. */ int diff --git a/src/lib/encoding/confline.h b/src/lib/encoding/confline.h index cd343e0e99..ce0d6c6e17 100644 --- a/src/lib/encoding/confline.h +++ b/src/lib/encoding/confline.h @@ -50,6 +50,7 @@ const config_line_t *config_line_find(const config_line_t *lines, const char *key); const config_line_t *config_line_find_case(const config_line_t *lines, const char *key); +config_line_t *config_lines_partition(config_line_t *inp, const char *header); int config_lines_eq(const config_line_t *a, const config_line_t *b); int config_count_key(const config_line_t *a, const char *key); void config_free_lines_(config_line_t *front); diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c index 46fc853550..8ee1521f3b 100644 --- a/src/lib/err/torerr_sys.c +++ b/src/lib/err/torerr_sys.c @@ -34,6 +34,7 @@ subsys_torerr_shutdown(void) const subsys_fns_t sys_torerr = { .name = "err", + SUBSYS_DECLARE_LOCATION(), /* Low-level error handling is a diagnostic feature, we want it to init * right after windows process security, and shutdown last. * (Security never shuts down.) */ diff --git a/src/lib/evloop/evloop_sys.c b/src/lib/evloop/evloop_sys.c index fecec2f264..b639810c23 100644 --- a/src/lib/evloop/evloop_sys.c +++ b/src/lib/evloop/evloop_sys.c @@ -41,6 +41,7 @@ subsys_evloop_shutdown(void) const struct subsys_fns_t sys_evloop = { .name = "evloop", + SUBSYS_DECLARE_LOCATION(), .supported = true, .level = -20, .initialize = subsys_evloop_initialize, diff --git a/src/lib/evloop/timers.c b/src/lib/evloop/timers.c index 7be9bae08e..11418e93fd 100644 --- a/src/lib/evloop/timers.c +++ b/src/lib/evloop/timers.c @@ -11,7 +11,7 @@ * 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 + * https://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. diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c index 392b2f4541..9583093c12 100644 --- a/src/lib/fs/conffile.c +++ b/src/lib/fs/conffile.c @@ -152,6 +152,7 @@ config_process_include(const char *path, int recursion_level, int extended, int rv = -1; SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { + log_notice(LD_CONFIG, "Including configuration file \"%s\".", config_file); config_line_t *included_config = NULL; config_line_t *included_config_last = NULL; if (config_get_included_config(config_file, recursion_level, extended, diff --git a/src/lib/llharden/.may_include b/src/lib/llharden/.may_include new file mode 100644 index 0000000000..038237dadf --- /dev/null +++ b/src/lib/llharden/.may_include @@ -0,0 +1,3 @@ +lib/llharden/*.h +lib/subsys/*.h +orconfig.h diff --git a/src/lib/llharden/include.am b/src/lib/llharden/include.am new file mode 100644 index 0000000000..0a4788c7dc --- /dev/null +++ b/src/lib/llharden/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-llharden.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-llharden-testing.a +endif + +# ADD_C_FILE: INSERT SOURCES HERE. +src_lib_libtor_llharden_a_SOURCES = \ + src/lib/llharden/winprocess_sys.c + +src_lib_libtor_llharden_testing_a_SOURCES = \ + $(src_lib_libtor_llharden_a_SOURCES) +src_lib_libtor_llharden_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_llharden_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +# ADD_C_FILE: INSERT HEADERS HERE. +noinst_HEADERS += \ + src/lib/llharden/winprocess_sys.h diff --git a/src/lib/llharden/lib_llharden.md b/src/lib/llharden/lib_llharden.md new file mode 100644 index 0000000000..69e9af5327 --- /dev/null +++ b/src/lib/llharden/lib_llharden.md @@ -0,0 +1,6 @@ +@dir /lib/llharden +@brief lib/llharden: low-level unconditional process hardening + +This module contains process hardening code that we want to run before any +other code, including configuration. It needs to be self-contained, since +nothing else will be initialized at this point. diff --git a/src/lib/process/winprocess_sys.c b/src/lib/llharden/winprocess_sys.c index e43a77e467..f2c88d8c75 100644 --- a/src/lib/process/winprocess_sys.c +++ b/src/lib/llharden/winprocess_sys.c @@ -8,7 +8,7 @@ #include "orconfig.h" #include "lib/subsys/subsys.h" -#include "lib/process/winprocess_sys.h" +#include "lib/llharden/winprocess_sys.h" #include <stdbool.h> #include <stddef.h> @@ -58,6 +58,7 @@ subsys_winprocess_initialize(void) const subsys_fns_t sys_winprocess = { .name = "winprocess", + SUBSYS_DECLARE_LOCATION(), /* HeapEnableTerminationOnCorruption and setdeppolicy() are security * features, we want them to run first. */ .level = -100, diff --git a/src/lib/process/winprocess_sys.h b/src/lib/llharden/winprocess_sys.h index bece1b3da9..bece1b3da9 100644 --- a/src/lib/process/winprocess_sys.h +++ b/src/lib/llharden/winprocess_sys.h diff --git a/src/lib/log/log.c b/src/lib/log/log.c index eb81515746..9ee87c0668 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -523,7 +523,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len, * pass them, and some very old ones do not detect overflow so well. * Regrettably, they call their maximum line length MAXLINE. */ #if MAXLINE < 64 -#warning "MAXLINE is a very low number; it might not be from syslog.h." +#warning "MAXLINE is very low; it might not be from syslog.h." #endif char *m = msg_after_prefix; if (msg_len >= MAXLINE) diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c index 1be4f5b7d8..021c05d3e6 100644 --- a/src/lib/log/log_sys.c +++ b/src/lib/log/log_sys.c @@ -28,6 +28,7 @@ subsys_logging_shutdown(void) const subsys_fns_t sys_logging = { .name = "log", + SUBSYS_DECLARE_LOCATION(), .supported = true, /* Logging depends on threads, approx time, raw logging, and security. * Most other lib modules depend on logging. */ diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index 581ae85f47..d698ddd8a6 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -71,7 +71,6 @@ tor_set_failed_assertion_callback(void (*fn)(void)) /** Helper for tor_assert: report the assertion failure. */ void -CHECK_PRINTF(5, 6) tor_assertion_failed_(const char *fname, unsigned int line, const char *func, const char *expr, const char *fmt, ...) @@ -104,7 +103,6 @@ tor_assertion_failed_(const char *fname, unsigned int line, /** Helper for tor_assert_nonfatal: report the assertion failure. */ void -CHECK_PRINTF(6, 7) tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, int once, const char *fmt, ...) diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index d9dbc7ee09..684dc7c6dd 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -142,6 +142,8 @@ #define ALL_BUGS_ARE_FATAL #endif +/** Define ALL_BUGS_ARE_FATAL if you want Tor to crash when any problem comes + * up, so you can get a coredump and track things down. */ #ifdef ALL_BUGS_ARE_FATAL #define tor_assert_nonfatal_unreached() tor_assert(0) #define tor_assert_nonfatal(cond) tor_assert((cond)) @@ -154,6 +156,9 @@ (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \ tor_abort_(), 1) \ : 0) +#ifndef COCCI +#define IF_BUG_ONCE(cond) if (BUG(cond)) +#endif #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)) @@ -164,6 +169,9 @@ #define tor_assert_nonfatal_unreached_once() STMT_NIL #define tor_assert_nonfatal_once(cond) ((void)(cond)) #define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0) +#ifndef COCCI +#define IF_BUG_ONCE(cond) if (BUG(cond)) +#endif #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, NULL); \ @@ -200,7 +208,6 @@ (ASSERT_PREDICT_UNLIKELY_(cond) ? \ (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \ : 0) -#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */ #ifndef COCCI #ifdef __GNUC__ @@ -232,7 +239,7 @@ #define IF_BUG_ONCE_VARNAME__(a) \ IF_BUG_ONCE_VARNAME_(a) -/** This macro behaves as 'if (bug(x))', except that it only logs its +/** This macro behaves as 'if (BUG(x))', except that it only logs its * warning once, no matter how many times it triggers. */ @@ -240,6 +247,8 @@ IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \ IF_BUG_ONCE_VARNAME__(__LINE__)) +#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */ + /** * Use this macro after a nonfatal assertion, and before a case statement * where you would want to fall through. @@ -251,9 +260,13 @@ #define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL FALLTHROUGH #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_unreached(0) +/** In older code, we used tor_fragile_assert() to mark optional failure + * points. At these points, we could make some debug builds fail. + * (But release builds would continue.) + * + * To get the same behaviour in recent tor versions, define + * ALL_BUGS_ARE_FATAL, and use any non-fatal assertion or *BUG() macro. + */ #define tor_fragile_assert() tor_assert_nonfatal_unreached_once() void tor_assertion_failed_(const char *fname, unsigned int line, diff --git a/src/lib/malloc/map_anon.c b/src/lib/malloc/map_anon.c index 1926b61f07..628966012a 100644 --- a/src/lib/malloc/map_anon.c +++ b/src/lib/malloc/map_anon.c @@ -78,7 +78,7 @@ #endif /* defined(HAVE_MINHERIT) || ... */ #if defined(HAVE_MINHERIT) && !defined(FLAG_ZERO) && !defined(FLAG_NOINHERIT) -#warning "minherit() is defined, but we couldn't find the right flag for it." +#warning "minherit() is defined, but FLAG_ZERO/NOINHERIT are not." #warning "This is probably a bug in Tor's support for this platform." #endif diff --git a/src/lib/math/laplace.c b/src/lib/math/laplace.c index 5c1d686a9c..a0e67384e6 100644 --- a/src/lib/math/laplace.c +++ b/src/lib/math/laplace.c @@ -29,7 +29,7 @@ sample_laplace_distribution(double mu, double b, double p) tor_assert(p >= 0.0 && p < 1.0); /* This is the "inverse cumulative distribution function" from: - * http://en.wikipedia.org/wiki/Laplace_distribution */ + * https://en.wikipedia.org/wiki/Laplace_distribution */ if (p <= 0.0) { /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler * options can cause the program to trap. */ diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c index 548d256023..31d485120e 100644 --- a/src/lib/math/prob_distr.c +++ b/src/lib/math/prob_distr.c @@ -1284,15 +1284,16 @@ sample_genpareto_locscale(uint32_t s, double p0, double mu, double sigma, /** * Deterministically sample from the geometric distribution with * per-trial success probability p. - * + **/ +// clang-format off +/* * XXX Quantify the error (KL divergence?) of this * ceiling-of-exponential sampler from a true geometric distribution, * which we could get by rejection sampling. Relevant papers: * * John F. Monahan, `Accuracy in Random Number Generation', * Mathematics of Computation 45(172), October 1984, pp. 559--568. -*https://pdfs.semanticscholar.org/aca6/74b96da1df77b2224e8cfc5dd6d61a471632.pdf - * +https://pdfs.semanticscholar.org/aca6/74b96da1df77b2224e8cfc5dd6d61a471632.pdf * Karl Bringmann and Tobias Friedrich, `Exact and Efficient * Generation of Geometric Random Variates and Random Graphs', in * Proceedings of the 40th International Colloaquium on Automata, @@ -1301,6 +1302,7 @@ sample_genpareto_locscale(uint32_t s, double p0, double mu, double sigma, * https://doi.org/10.1007/978-3-642-39206-1_23 * https://people.mpi-inf.mpg.de/~kbringma/paper/2013ICALP-1.pdf */ +// clang-format on static double sample_geometric(uint32_t s, double p0, double p) { diff --git a/src/lib/memarea/memarea.c b/src/lib/memarea/memarea.c index d677c364a4..4d26c20eeb 100644 --- a/src/lib/memarea/memarea.c +++ b/src/lib/memarea/memarea.c @@ -39,7 +39,7 @@ #elif MEMAREA_ALIGN == 8 #define MEMAREA_ALIGN_MASK ((uintptr_t)7) #else -#error "void* is neither 4 nor 8 bytes long. I don't know how to align stuff." +#error "void* is neither 4 nor 8 bytes long." #endif /* MEMAREA_ALIGN == 4 || ... */ #if defined(__GNUC__) && defined(FLEXIBLE_ARRAY_MEMBER) diff --git a/src/lib/net/.may_include b/src/lib/net/.may_include index e4368f799b..6e9af9737a 100644 --- a/src/lib/net/.may_include +++ b/src/lib/net/.may_include @@ -14,4 +14,5 @@ lib/net/*.h lib/string/*.h lib/subsys/*.h lib/testsupport/*.h -lib/malloc/*.h
\ No newline at end of file +lib/malloc/*.h +lib/smartlist_core/*.h diff --git a/src/lib/net/address.c b/src/lib/net/address.c index d623cdd131..6d46f9b955 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -97,7 +97,7 @@ * work correctly. Bail out here if we've found a platform where AF_UNSPEC * isn't 0. */ #if AF_UNSPEC != 0 -#error We rely on AF_UNSPEC being 0. Let us know about your platform, please! +#error "We rely on AF_UNSPEC being 0. Yours isn't. Please tell us more!" #endif CTASSERT(AF_UNSPEC == 0); @@ -608,7 +608,8 @@ tor_addr_parse_mask_ports(const char *s, family = AF_INET; tor_addr_from_ipv4h(addr_out, 0); } else if (flags & TAPMP_STAR_IPV6_ONLY) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + static uint8_t nil_bytes[16] = + { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; family = AF_INET6; tor_addr_from_ipv6_bytes(addr_out, nil_bytes); } else { @@ -629,7 +630,7 @@ tor_addr_parse_mask_ports(const char *s, tor_addr_from_ipv4h(addr_out, 0); any_flag = 1; } else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) { - static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; + static uint8_t nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; family = AF_INET6; tor_addr_from_ipv6_bytes(addr_out, nil_bytes); any_flag = 1; @@ -817,8 +818,12 @@ tor_addr_is_loopback(const tor_addr_t *addr) /* Is addr valid? * Checks that addr is non-NULL and not tor_addr_is_null(). - * If for_listening is true, IPv4 addr 0.0.0.0 is allowed. - * It means "bind to all addresses on the local machine". */ + * If for_listening is true, all IPv4 and IPv6 addresses are valid, including + * 0.0.0.0 (for IPv4) and :: (for IPv6). When listening, these addresses mean + * "bind to all addresses on the local machine". + * Otherwise, 0.0.0.0 and :: are invalid, because they are null addresses. + * All unspecified and unix addresses are invalid, regardless of for_listening. + */ int tor_addr_is_valid(const tor_addr_t *addr, int for_listening) { @@ -827,10 +832,11 @@ tor_addr_is_valid(const tor_addr_t *addr, int for_listening) return 0; } - /* Only allow IPv4 0.0.0.0 for_listening. */ - if (for_listening && addr->family == AF_INET - && tor_addr_to_ipv4h(addr) == 0) { - return 1; + /* Allow all IPv4 and IPv6 addresses, when for_listening is true */ + if (for_listening) { + if (addr->family == AF_INET || addr->family == AF_INET6) { + return 1; + } } /* Otherwise, the address is valid if it's not tor_addr_is_null() */ @@ -882,7 +888,7 @@ tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr) /** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at * <b>ipv6_bytes</b>. */ void -tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) +tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes) { tor_assert(dest); tor_assert(ipv6_bytes); @@ -895,7 +901,21 @@ tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes) void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6) { - tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr); + tor_addr_from_ipv6_bytes(dest, in6->s6_addr); +} + +/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>. + * <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear + * <b>dest</b>. */ +void +tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src) +{ + tor_assert(dest); + tor_assert(src); + memset(dest, 0, 16); + IF_BUG_ONCE(src->family != AF_INET6) + return; + memcpy(dest, src->addr.in6_addr.s6_addr, 16); } /** Copy a tor_addr_t from <b>src</b> to <b>dest</b>. @@ -1169,25 +1189,67 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate) const char * fmt_addrport(const tor_addr_t *addr, uint16_t port) { - /* Add space for a colon and up to 5 digits. */ - static char buf[TOR_ADDR_BUF_LEN + 6]; + static char buf[TOR_ADDRPORT_BUF_LEN]; tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port); return buf; } /** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4 * addresses. Also not thread-safe, also clobbers its return buffer on - * repeated calls. */ + * repeated calls. Clean internal buffer and return empty string on failure. */ const char * fmt_addr32(uint32_t addr) { static char buf[INET_NTOA_BUF_LEN]; struct in_addr in; + int success; + in.s_addr = htonl(addr); - tor_inet_ntoa(&in, buf, sizeof(buf)); + + success = tor_inet_ntoa(&in, buf, sizeof(buf)); + tor_assertf_nonfatal(success >= 0, + "Failed to convert IP 0x%08X (HBO) to string", addr); + + IF_BUG_ONCE(success < 0) { + memset(buf, 0, INET_NTOA_BUF_LEN); + } + return buf; } +/** Return a string representing the family of <b>addr</b>. + * + * This string is a string constant, and must not be freed. + * This function is thread-safe. + */ +const char * +fmt_addr_family(const tor_addr_t *addr) +{ + static int default_bug_once = 0; + + IF_BUG_ONCE(!addr) + return "NULL pointer"; + + switch (tor_addr_family(addr)) { + case AF_INET6: + return "IPv6"; + case AF_INET: + return "IPv4"; + case AF_UNIX: + return "UNIX socket"; + case AF_UNSPEC: + return "unspecified"; + default: + if (!default_bug_once) { + log_warn(LD_BUG, "Called with unknown address family %d", + (int)tor_addr_family(addr)); + default_bug_once = 1; + } + return "unknown"; + } + //return "(unreachable code)"; +} + /** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string * may be an IPv4 address, or an IPv6 address surrounded by square brackets. * @@ -1412,10 +1474,10 @@ ifconf_free_ifc_buf(struct ifconf *ifc) * into smartlist of <b>tor_addr_t</b> structures. */ STATIC smartlist_t * -ifreq_to_smartlist(char *buf, size_t buflen) +ifreq_to_smartlist(const uint8_t *buf, size_t buflen) { smartlist_t *result = smartlist_new(); - char *end = buf + buflen; + const uint8_t *end = buf + buflen; /* These acrobatics are due to alignment issues which trigger * undefined behaviour traps on OSX. */ @@ -1489,7 +1551,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family) /* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we * don't know if we got everything during ioctl. */ } while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE); - result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len); + result = ifreq_to_smartlist((const uint8_t *)ifc.ifc_buf, ifc.ifc_len); done: if (fd >= 0) @@ -1642,11 +1704,15 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)) * Ideally, we want the default route, see #12377 for details */ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) { tor_addr_copy(addr, a); + const bool is_internal = tor_addr_is_internal(a, 0); rv = 0; + log_debug(LD_NET, "Found %s interface address '%s'", + (is_internal ? "internal" : "external"), fmt_addr(addr)); + /* If we found a non-internal address, declare success. Otherwise, * keep looking. */ - if (!tor_addr_is_internal(a, 0)) + if (!is_internal) break; } SMARTLIST_FOREACH_END(a); @@ -1943,17 +2009,24 @@ parse_port_range(const char *port, uint16_t *port_min_out, } /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it - * and return a strdup of the resulting address. + * and return a strdup of the resulting address. Return NULL if + * tor_inet_ntop() fails. */ char * tor_dup_ip(uint32_t addr) { + const char *ip_str; char buf[TOR_ADDR_BUF_LEN]; struct in_addr in; in.s_addr = htonl(addr); - tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); - return tor_strdup(buf); + ip_str = tor_inet_ntop(AF_INET, &in, buf, sizeof(buf)); + + tor_assertf_nonfatal(ip_str, "Failed to duplicate IP %08X", addr); + if (ip_str) + return tor_strdup(buf); + + return NULL; } /** diff --git a/src/lib/net/address.h b/src/lib/net/address.h index 815fb02283..e5016ee4fe 100644 --- a/src/lib/net/address.h +++ b/src/lib/net/address.h @@ -104,6 +104,10 @@ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa, uint16_t *port_out); void tor_addr_make_unspec(tor_addr_t *a); void tor_addr_make_null(tor_addr_t *a, sa_family_t family); +#define tor_addr_port_make_null(addr, port, family) \ + (void)(tor_addr_make_null(addr, family), (port) = 0) +#define tor_addr_port_make_null_ap(ap, family) \ + tor_addr_port_make_null(&(ap)->addr, (ap)->port, family) char *tor_sockaddr_to_str(const struct sockaddr *sa); /** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not @@ -177,7 +181,7 @@ tor_addr_to_mapped_ipv4h(const tor_addr_t *a) } /** Return the address family of <b>a</b>. Possible values are: - * AF_INET6, AF_INET, AF_UNSPEC. */ + * AF_INET6, AF_INET, AF_UNSPEC, AF_UNIX. */ static inline sa_family_t tor_addr_family(const tor_addr_t *a) { @@ -209,6 +213,15 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u) */ #define TOR_ADDR_BUF_LEN 48 +/** Length of a buffer containing an IP address along with a port number and + * a seperating colon. + * + * This allows enough space for + * "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]:12345", + * plus a terminating NUL. + */ +#define TOR_ADDRPORT_BUF_LEN (TOR_ADDR_BUF_LEN + 6) + char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC; /** Wrapper function of fmt_addr_impl(). It does not decorate IPv6 @@ -221,7 +234,9 @@ char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC; const char *fmt_addr_impl(const tor_addr_t *addr, int decorate); const char *fmt_addrport(const tor_addr_t *addr, uint16_t port); -const char * fmt_addr32(uint32_t addr); +#define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port) +const char *fmt_addr32(uint32_t addr); +const char *fmt_addr_family(const tor_addr_t *addr); MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)); @@ -298,11 +313,12 @@ void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr); * order. */ #define tor_addr_from_ipv4h(dest, v4addr) \ tor_addr_from_ipv4n((dest), htonl(v4addr)) -void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes); +void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *bytes); /** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */ #define tor_addr_from_in(dest, in) \ tor_addr_from_ipv4n((dest), (in)->s_addr); void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6); +void tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src); int tor_addr_is_null(const tor_addr_t *addr); int tor_addr_is_loopback(const tor_addr_t *addr); @@ -393,8 +409,8 @@ STATIC struct smartlist_t *get_interface_addresses_win32(int severity, #endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */ #ifdef HAVE_IFCONF_TO_SMARTLIST -STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr, - size_t buflen); +STATIC struct smartlist_t *ifreq_to_smartlist(const uint8_t *ifr, + size_t buflen); STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity, sa_family_t family); #endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c index aa84451074..4dbf491e1a 100644 --- a/src/lib/net/buffers_net.c +++ b/src/lib/net/buffers_net.c @@ -76,7 +76,7 @@ read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, chunk->datalen += read_result; log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, (int)buf->datalen); - tor_assert(read_result < INT_MAX); + tor_assert(read_result <= BUF_MAX_LEN); return (int)read_result; } } @@ -103,9 +103,9 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most, tor_assert(reached_eof); tor_assert(SOCKET_OK(fd)); - if (BUG(buf->datalen >= INT_MAX)) + if (BUG(buf->datalen > BUF_MAX_LEN)) return -1; - if (BUG(buf->datalen >= INT_MAX - at_most)) + if (BUG(buf->datalen > BUF_MAX_LEN - at_most)) return -1; while (at_most > total_read) { @@ -127,7 +127,7 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most, check(); if (r < 0) return r; /* Error */ - tor_assert(total_read+r < INT_MAX); + tor_assert(total_read+r <= BUF_MAX_LEN); total_read += r; if ((size_t)r < readlen) { /* eof, block, or no more to read. */ break; @@ -170,7 +170,7 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz, } else { *buf_flushlen -= write_result; buf_drain(buf, write_result); - tor_assert(write_result < INT_MAX); + tor_assert(write_result <= BUF_MAX_LEN); return (int)write_result; } } @@ -217,7 +217,7 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz, if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ break; } - tor_assert(flushed < INT_MAX); + tor_assert(flushed <= BUF_MAX_LEN); return (int)flushed; } diff --git a/src/lib/net/inaddr.c b/src/lib/net/inaddr.c index 0d20d88901..d50ac2440c 100644 --- a/src/lib/net/inaddr.c +++ b/src/lib/net/inaddr.c @@ -11,7 +11,9 @@ #include "lib/net/inaddr.h" #include "lib/cc/torint.h" +#include "lib/container/smartlist.h" #include "lib/log/util_bug.h" +#include "lib/malloc/malloc.h" #include "lib/net/inaddr_st.h" #include "lib/string/compat_ctype.h" #include "lib/string/compat_string.h" @@ -39,8 +41,27 @@ tor_inet_aton(const char *str, struct in_addr *addr) { unsigned a, b, c, d; char more; + bool is_octal = false; + smartlist_t *sl = NULL; + if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a, &b, &c, &d, &more) != 4) return 0; + + /* Parse the octets and check them for leading zeros. */ + sl = smartlist_new(); + smartlist_split_string(sl, str, ".", 0, 0); + SMARTLIST_FOREACH(sl, const char *, octet, { + is_octal = (strlen(octet) > 1 && octet[0] == '0'); + if (is_octal) { + break; + } + }); + SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet)); + smartlist_free(sl); + + if (is_octal) + return 0; + if (a > 255) return 0; if (b > 255) return 0; if (c > 255) return 0; diff --git a/src/lib/net/network_sys.c b/src/lib/net/network_sys.c index 012fc56bba..e95c3ba819 100644 --- a/src/lib/net/network_sys.c +++ b/src/lib/net/network_sys.c @@ -37,9 +37,10 @@ subsys_network_shutdown(void) const subsys_fns_t sys_network = { .name = "network", + SUBSYS_DECLARE_LOCATION(), /* Network depends on logging, and a lot of other modules depend on network. */ - .level = -80, + .level = -55, .supported = true, .initialize = subsys_network_initialize, .shutdown = subsys_network_shutdown, diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c index df079d5db3..68a8c01ef4 100644 --- a/src/lib/net/resolve.c +++ b/src/lib/net/resolve.c @@ -372,11 +372,11 @@ 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, - 0.6, tor_reallocarray_, tor_free_) + 0.6, tor_reallocarray_, tor_free_); /** If true, don't try to cache getaddrinfo results. */ static int sandbox_getaddrinfo_cache_disabled = 0; diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h index 2b663e00c4..90c4305d29 100644 --- a/src/lib/net/socks5_status.h +++ b/src/lib/net/socks5_status.h @@ -37,6 +37,7 @@ typedef enum { SOCKS5_HS_MISSING_CLIENT_AUTH = 0xF4, SOCKS5_HS_BAD_CLIENT_AUTH = 0xF5, SOCKS5_HS_BAD_ADDRESS = 0xF6, + SOCKS5_HS_INTRO_TIMEDOUT = 0xF7, } socks5_reply_status_t; #endif /* !defined(TOR_SOCKS5_STATUS_H) */ diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c index ac99726f51..f7f5ede307 100644 --- a/src/lib/osinfo/uname.c +++ b/src/lib/osinfo/uname.c @@ -27,6 +27,40 @@ static char uname_result[256]; /** True iff uname_result is set. */ static int uname_result_is_set = 0; +#ifdef _WIN32 +/** Table to map claimed windows versions into human-readable windows + * versions. */ +static struct { + unsigned major; + unsigned minor; + const char *client_version; + const char *server_version; +} win_version_table[] = { + /* This table must be sorted in descending order. + * Sources: + * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions + * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ + * ns-winnt-_osversioninfoexa#remarks + */ + /* Windows Server 2019 is indistinguishable from Windows Server 2016 + * using GetVersionEx(). + { 10, 0, NULL, "Windows Server 2019" }, */ + // clang-format off + { 10, 0, "Windows 10", "Windows Server 2016" }, + { 6, 3, "Windows 8.1", "Windows Server 2012 R2" }, + { 6, 2, "Windows 8", "Windows Server 2012" }, + { 6, 1, "Windows 7", "Windows Server 2008 R2" }, + { 6, 0, "Windows Vista", "Windows Server 2008" }, + { 5, 2, "Windows XP Professional", "Windows Server 2003" }, + /* Windows XP did not have a server version, but we need something here */ + { 5, 1, "Windows XP", "Windows XP Server" }, + { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" }, + /* Earlier versions are not supported by GetVersionEx(). */ + { 0, 0, NULL, NULL } + // clang-format on +}; +#endif /* defined(_WIN32) */ + /** Return a pointer to a description of our platform. */ MOCK_IMPL(const char *, @@ -49,31 +83,6 @@ get_uname,(void)) int is_client = 0; int is_server = 0; const char *plat = NULL; - static struct { - unsigned major; unsigned minor; - const char *client_version; const char *server_version; - } win_version_table[] = { - /* This table must be sorted in descending order. - * Sources: - * https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions - * https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ - * ns-winnt-_osversioninfoexa#remarks - */ - /* Windows Server 2019 is indistinguishable from Windows Server 2016 - * using GetVersionEx(). - { 10, 0, NULL, "Windows Server 2019" }, */ - { 10, 0, "Windows 10", "Windows Server 2016" }, - { 6, 3, "Windows 8.1", "Windows Server 2012 R2" }, - { 6, 2, "Windows 8", "Windows Server 2012" }, - { 6, 1, "Windows 7", "Windows Server 2008 R2" }, - { 6, 0, "Windows Vista", "Windows Server 2008" }, - { 5, 2, "Windows XP Professional", "Windows Server 2003" }, - /* Windows XP did not have a server version, but we need something here */ - { 5, 1, "Windows XP", "Windows XP Server" }, - { 5, 0, "Windows 2000 Professional", "Windows 2000 Server" }, - /* Earlier versions are not supported by GetVersionEx(). */ - { 0, 0, NULL, NULL } - }; memset(&info, 0, sizeof(info)); info.dwOSVersionInfoSize = sizeof(info); if (! GetVersionEx((LPOSVERSIONINFO)&info)) { diff --git a/src/lib/process/include.am b/src/lib/process/include.am index af5f99617b..18876b3f54 100644 --- a/src/lib/process/include.am +++ b/src/lib/process/include.am @@ -16,8 +16,7 @@ src_lib_libtor_process_a_SOURCES = \ src/lib/process/process_win32.c \ src/lib/process/restrict.c \ src/lib/process/setuid.c \ - src/lib/process/waitpid.c \ - src/lib/process/winprocess_sys.c + src/lib/process/waitpid.c src_lib_libtor_process_testing_a_SOURCES = \ $(src_lib_libtor_process_a_SOURCES) @@ -35,5 +34,4 @@ noinst_HEADERS += \ src/lib/process/process_win32.h \ src/lib/process/restrict.h \ src/lib/process/setuid.h \ - src/lib/process/waitpid.h \ - src/lib/process/winprocess_sys.h + src/lib/process/waitpid.h diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c index 283064cbfe..c8332ba91e 100644 --- a/src/lib/process/process_sys.c +++ b/src/lib/process/process_sys.c @@ -26,7 +26,8 @@ subsys_process_shutdown(void) const subsys_fns_t sys_process = { .name = "process", - .level = -35, + SUBSYS_DECLARE_LOCATION(), + .level = -18, .supported = true, .initialize = subsys_process_initialize, .shutdown = subsys_process_shutdown diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c index a3ce52deaa..cd2a1c57b5 100644 --- a/src/lib/process/restrict.c +++ b/src/lib/process/restrict.c @@ -85,7 +85,7 @@ tor_set_max_memlock(void) { /* Future consideration for Windows is probably SetProcessWorkingSetSize * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK - * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx + * https://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx */ struct rlimit limit; @@ -128,7 +128,7 @@ tor_mlockall(void) * Future consideration for Windows may be VirtualLock * VirtualLock appears to implement mlock() but not mlockall() * - * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx + * https://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx */ #ifdef HAVE_UNIX_MLOCKALL @@ -190,7 +190,7 @@ set_max_file_descriptors(rlim_t limit, int *max_out) /* Define some maximum connections values for systems where we cannot * automatically determine a limit. Re Cygwin, see - * http://archives.seul.org/or/talk/Aug-2006/msg00210.html + * https://archives.seul.org/or/talk/Aug-2006/msg00210.html * For an iPhone, 9999 should work. For Windows and all other unknown * systems we use 15000 as the default. */ #ifndef HAVE_GETRLIMIT diff --git a/src/lib/process/waitpid.c b/src/lib/process/waitpid.c index 89ffe9fcfe..33798f65f0 100644 --- a/src/lib/process/waitpid.c +++ b/src/lib/process/waitpid.c @@ -58,9 +58,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/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index b917912f4d..d4f0da8397 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -117,6 +117,10 @@ #endif /* defined(__i386__) || ... */ +#ifdef M_SYSCALL +#define SYSCALL_NAME_DEBUGGING +#endif + /**Determines if at least one sandbox is active.*/ static int sandbox_active = 0; /** Holds the parameter list configuration for the sandbox.*/ @@ -133,6 +137,10 @@ static sandbox_cfg_t *filter_dynamic = NULL; * the high bits of the value might get masked out improperly. */ #define SCMP_CMP_MASKED(a,b,c) \ SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c)) +/* For negative constants, the rule to add depends on the glibc version. */ +#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \ + (SCMP_CMP((a), (op), (unsigned int)(b))) : \ + (SCMP_CMP_STR((a), (op), (b)))) /** Variable used for storing all syscall numbers that will be allowed with the * stage 1 general Tor sandbox. @@ -275,9 +283,18 @@ static int filter_nopar_gen[] = { SCMP_SYS(recvfrom), SCMP_SYS(sendto), SCMP_SYS(unlink), +#ifdef __NR_unlinkat + SCMP_SYS(unlinkat), +#endif SCMP_SYS(poll) }; +/* opendir is not a syscall but it will use either open or openat. We do not + * want the decision to allow open/openat to be the callers reponsability, so + * we create a phony syscall number for opendir and sb_opendir will choose the + * correct syscall. */ +#define PHONY_OPENDIR_SYSCALL -2 + /* These macros help avoid the error where the number of filters we add on a * single rule don't match the arg_cnt param. */ #define seccomp_rule_add_0(ctx,act,call) \ @@ -431,31 +448,59 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) #endif #endif -/* Return true if we think we're running with a libc that always uses - * openat on linux. */ +/* Return true the libc version is greater or equal than + * <b>major</b>.<b>minor</b>. Returns false otherwise. */ static int -libc_uses_openat_for_everything(void) +is_libc_at_least(int major, int minor) { #ifdef CHECK_LIBC_VERSION const char *version = gnu_get_libc_version(); if (version == NULL) return 0; - int major = -1; - int minor = -1; + int libc_major = -1; + int libc_minor = -1; - tor_sscanf(version, "%d.%d", &major, &minor); - if (major >= 3) + tor_sscanf(version, "%d.%d", &libc_major, &libc_minor); + if (libc_major > major) return 1; - else if (major == 2 && minor >= 26) + else if (libc_major == major && libc_minor >= minor) return 1; else return 0; #else /* !defined(CHECK_LIBC_VERSION) */ + (void)major; + (void)minor; return 0; #endif /* defined(CHECK_LIBC_VERSION) */ } +/* Return true if we think we're running with a libc that uses openat for the + * open function on linux. */ +static int +libc_uses_openat_for_open(void) +{ + return is_libc_at_least(2, 26); +} + +/* Return true if we think we're running with a libc that uses openat for the + * opendir function on linux. */ +static int +libc_uses_openat_for_opendir(void) +{ + // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive) + return is_libc_at_least(2, 27) || + (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); +} + +/* Return true if we think we're running with a libc that needs to cast + * negative arguments like AT_FDCWD for seccomp rules. */ +static int +libc_negative_constant_needs_cast(void) +{ + return is_libc_at_least(2, 27); +} + /** Allow a single file to be opened. If <b>use_openat</b> is true, * we're using a libc that remaps all the opens into openats. */ static int @@ -463,7 +508,7 @@ allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file) { if (use_openat) { return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP(0, SCMP_CMP_EQ, (unsigned int)AT_FDCWD), + SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, file)); } else { return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), @@ -481,7 +526,7 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc; sandbox_cfg_t *elem = NULL; - int use_openat = libc_uses_openat_for_everything(); + int use_openat = libc_uses_openat_for_open(); // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { @@ -599,7 +644,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) if (param != NULL && param->prot == 1 && param->syscall == SCMP_SYS(openat)) { rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY| O_CLOEXEC)); @@ -614,6 +659,30 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +static int +sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == PHONY_OPENDIR_SYSCALL) { + rc = allow_file_open(ctx, libc_uses_openat_for_opendir(), param->value); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} + /** * Function responsible for setting up the socket syscall for * the seccomp filter sandbox. @@ -1128,6 +1197,7 @@ static sandbox_filter_func_t filter_func[] = { sb_chmod, sb_open, sb_openat, + sb_opendir, sb_rename, #ifdef __NR_fcntl64 sb_fcntl64, @@ -1447,6 +1517,19 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } +int +sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) +{ + sandbox_cfg_t *elem = NULL; + + elem = new_element(PHONY_OPENDIR_SYSCALL, dir); + + elem->next = *cfg; + *cfg = elem; + + return 0; +} + /** * Function responsible for going through the parameter syscall filters and * call each function pointer in the list. @@ -1545,8 +1628,10 @@ install_syscall_filter(sandbox_cfg_t* cfg) return (rc < 0 ? -rc : rc); } +#ifdef SYSCALL_NAME_DEBUGGING #include "lib/sandbox/linux_syscalls.inc" +/** Return a string containing the name of a given syscall (if we know it) */ static const char * get_syscall_name(int syscall_num) { @@ -1564,6 +1649,28 @@ get_syscall_name(int syscall_num) } } +/** Return the syscall number from a ucontext_t that we got in a signal + * handler (if we know how to do that). */ +static int +get_syscall_from_ucontext(const ucontext_t *ctx) +{ + return (int) ctx->uc_mcontext.M_SYSCALL; +} +#else +static const char * +get_syscall_name(int syscall_num) +{ + (void) syscall_num; + return "unknown"; +} +static int +get_syscall_from_ucontext(const ucontext_t *ctx) +{ + (void) ctx; + return -1; +} +#endif + #ifdef USE_BACKTRACE #define MAX_DEPTH 256 static void *syscall_cb_buf[MAX_DEPTH]; @@ -1579,7 +1686,6 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context) { ucontext_t *ctx = (ucontext_t *) (void_context); const char *syscall_name; - int syscall; #ifdef USE_BACKTRACE size_t depth; int n_fds, i; @@ -1594,7 +1700,7 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context) if (!ctx) return; - syscall = (int) ctx->uc_mcontext.M_SYSCALL; + int syscall = get_syscall_from_ucontext(ctx); #ifdef USE_BACKTRACE depth = backtrace(syscall_cb_buf, MAX_DEPTH); @@ -1752,6 +1858,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) } int +sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir) +{ + (void)cfg; (void)dir; + return 0; +} + +int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file) { (void)cfg; (void)file; diff --git a/src/lib/sandbox/sandbox.h b/src/lib/sandbox/sandbox.h index b50df48255..a2b3227b90 100644 --- a/src/lib/sandbox/sandbox.h +++ b/src/lib/sandbox/sandbox.h @@ -136,6 +136,13 @@ int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2); int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file); /** + * Function used to add a opendir allowed filename to a supplied configuration. + * The (char*) specifies the path to the allowed dir; we steal the pointer to + * that dir. + */ +int sandbox_cfg_allow_opendir_dirname(sandbox_cfg_t **cfg, char *dir); + +/** * Function used to add a stat/stat64 allowed filename to a configuration. * The (char*) specifies the path to the allowed file; that pointer is stolen. */ diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h index c05b69af39..62c0de026d 100644 --- a/src/lib/subsys/subsys.h +++ b/src/lib/subsys/subsys.h @@ -42,6 +42,11 @@ typedef struct subsys_fns_t { const char *name; /** + * The file in which the subsystem object is declared. Used for debugging. + **/ + const char *location; + + /** * Whether this subsystem is supported -- that is, whether it is compiled * into Tor. For most subsystems, this should be true. **/ @@ -187,6 +192,14 @@ typedef struct subsys_fns_t { int (*flush_state)(void *); } subsys_fns_t; +#ifndef COCCI +/** + * Macro to declare a subsystem's location. + **/ +#define SUBSYS_DECLARE_LOCATION() \ + .location = __FILE__ +#endif /* !defined(COCCI) */ + /** * Lowest allowed subsystem level. **/ diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c index d56e8a3f76..75ade9c9f2 100644 --- a/src/lib/thread/compat_threads.c +++ b/src/lib/thread/compat_threads.c @@ -129,9 +129,8 @@ subsys_threads_initialize(void) const subsys_fns_t sys_threads = { .name = "threads", + SUBSYS_DECLARE_LOCATION(), .supported = true, - /* Threads is used by logging, which is a diagnostic feature, we want it to - * init right after low-level error handling and approx time. */ - .level = -95, + .level = -89, .initialize = subsys_threads_initialize, }; diff --git a/src/lib/time/time_sys.c b/src/lib/time/time_sys.c index 044d328f81..1c1bc4cd18 100644 --- a/src/lib/time/time_sys.c +++ b/src/lib/time/time_sys.c @@ -20,6 +20,7 @@ subsys_time_initialize(void) const subsys_fns_t sys_time = { .name = "time", + SUBSYS_DECLARE_LOCATION(), /* Monotonic time depends on logging, and a lot of other modules depend on * monotonic time. */ .level = -80, diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c index 87055744a7..b92a14d6a1 100644 --- a/src/lib/tls/buffers_tls.c +++ b/src/lib/tls/buffers_tls.c @@ -68,9 +68,9 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) check_no_tls_errors(); - IF_BUG_ONCE(buf->datalen >= INT_MAX) + IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN) return TOR_TLS_ERROR_MISC; - IF_BUG_ONCE(buf->datalen >= INT_MAX - at_most) + IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN - at_most) return TOR_TLS_ERROR_MISC; while (at_most > total_read) { @@ -90,7 +90,7 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) r = read_to_chunk_tls(buf, chunk, tls, readlen); if (r < 0) return r; /* Error */ - tor_assert(total_read+r < INT_MAX); + tor_assert(total_read+r <= BUF_MAX_LEN); total_read += r; if ((size_t)r < readlen) /* eof, block, or no more to read. */ break; @@ -177,6 +177,6 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, if (r == 0) /* Can't flush any more now. */ break; } while (sz > 0); - tor_assert(flushed < INT_MAX); + tor_assert(flushed <= BUF_MAX_LEN); return (int)flushed; } diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c index fd41a84cfa..9e70e54725 100644 --- a/src/lib/tls/tortls.c +++ b/src/lib/tls/tortls.c @@ -456,6 +456,7 @@ subsys_tortls_shutdown(void) const subsys_fns_t sys_tortls = { .name = "tortls", + SUBSYS_DECLARE_LOCATION(), .level = -50, .shutdown = subsys_tortls_shutdown }; diff --git a/src/lib/tls/tortls.h b/src/lib/tls/tortls.h index e8dbbf5279..517cdc17dd 100644 --- a/src/lib/tls/tortls.h +++ b/src/lib/tls/tortls.h @@ -81,6 +81,7 @@ void tor_tls_free_all(void); void tor_tls_init(void); void tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing); +const char *tor_tls_get_last_error_msg(const tor_tls_t *tls); int tor_tls_context_init(unsigned flags, crypto_pk_t *client_identity, crypto_pk_t *server_identity, diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c index 559df36d7b..c873367f6f 100644 --- a/src/lib/tls/tortls_nss.c +++ b/src/lib/tls/tortls_nss.c @@ -369,6 +369,8 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, (void)tls; PRErrorCode code = PORT_GetError(); + if (tls) + tls->last_error = code; const char *addr = tls ? tls->address : NULL; const char *string = PORT_ErrorToString(code); @@ -391,6 +393,17 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, with, addr); } } +const char * +tor_tls_get_last_error_msg(const tor_tls_t *tls) +{ + IF_BUG_ONCE(!tls) { + return NULL; + } + if (tls->last_error == 0) { + return NULL; + } + return PORT_ErrorToString((PRErrorCode)tls->last_error); +} tor_tls_t * tor_tls_new(tor_socket_t sock, int is_server) diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c index 68d6e2aa50..2269714141 100644 --- a/src/lib/tls/tortls_openssl.c +++ b/src/lib/tls/tortls_openssl.c @@ -245,10 +245,30 @@ tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) unsigned long err; while ((err = ERR_get_error()) != 0) { + if (tls) + tls->last_error = err; tor_tls_log_one_error(tls, err, severity, domain, doing); } } +/** + * Return a string representing more detail about the last error received + * on TLS. + * + * May return null if no error was found. + **/ +const char * +tor_tls_get_last_error_msg(const tor_tls_t *tls) +{ + IF_BUG_ONCE(!tls) { + return NULL; + } + if (tls->last_error == 0) { + return NULL; + } + return (const char*)ERR_reason_error_string(tls->last_error); +} + #define CATCH_SYSCALL 1 #define CATCH_ZERO 2 diff --git a/src/lib/tls/tortls_st.h b/src/lib/tls/tortls_st.h index 925896d493..34abe52ee3 100644 --- a/src/lib/tls/tortls_st.h +++ b/src/lib/tls/tortls_st.h @@ -67,6 +67,8 @@ struct tor_tls_t { */ unsigned long last_write_count; unsigned long last_read_count; + /** Most recent error value from ERR_get_error(). */ + unsigned long last_error; /** If set, a callback to invoke whenever the client tries to renegotiate * the handshake. */ void (*negotiated_callback)(tor_tls_t *tls, void *arg); @@ -77,6 +79,7 @@ struct tor_tls_t { /** Last values retried from tor_get_prfiledesc_byte_counts(). */ uint64_t last_write_count; uint64_t last_read_count; + long last_error; #endif }; diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c index d9f90ab2f7..c815f20e51 100644 --- a/src/lib/wallclock/approx_time.c +++ b/src/lib/wallclock/approx_time.c @@ -59,6 +59,7 @@ subsys_wallclock_initialize(void) **/ const subsys_fns_t sys_wallclock = { .name = "wallclock", + SUBSYS_DECLARE_LOCATION(), .supported = true, /* Approximate time is a diagnostic feature, we want it to init right after * low-level error handling. */ |