21#ifdef HAVE_NETINET_IN_H
22#include <netinet/in.h>
60#define MAX_UNCOMPRESSION_FACTOR 25
61#define CHECK_FOR_COMPRESSION_BOMB_AFTER (5 * 1024 * 1024)
69 if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER)
72 double compression_factor = (double)size_out / size_in;
73 if (compression_factor > MAX_UNCOMPRESSION_FACTOR) {
75 "Detected possible compression bomb with "
76 "input size = %"TOR_PRIuSZ
" and output size = %"TOR_PRIuSZ
" "
77 "(compression factor = %.2f)",
78 size_in, size_out, compression_factor);
93 (void)compression_level;
94 if (method == NO_METHOD) {
97 return (in_len < SIZE_MAX) ? in_len + 1 : in_len;
107 return MAX(in_len, 1024);
115 char **out,
size_t *out_len,
116 const char *in,
size_t in_len,
120 int protocol_warn_level)
127 if (stream == NULL) {
128 log_warn(
LD_GENERAL,
"NULL stream while %scompressing",
130 log_debug(
LD_GENERAL,
"method: %d level: %d at len: %lu",
131 method, compression_level, (
unsigned long)in_len);
135 size_t in_len_orig = in_len;
136 size_t out_remaining, out_alloc;
139 out_remaining = out_alloc =
141 *out = outptr = tor_malloc(out_remaining);
143 const int finish = complete_only || compress;
147 &outptr, &out_remaining,
148 &in, &in_len, finish)) {
149 case TOR_COMPRESS_DONE:
150 if (in_len == 0 || compress) {
166 const size_t out_so_far = (size_t)(outptr - *out);
167 const size_t in_so_far = in_len_orig - in_len;
169 log_warn(
LD_DIR,
"Possible compression bomb across concatenated "
170 "streams; abandoning.");
173 tor_compress_free(stream);
175 if (stream == NULL) {
176 log_warn(
LD_GENERAL,
"NULL stream while %scompressing",
182 case TOR_COMPRESS_OK:
183 if (compress || complete_only) {
185 "Unexpected %s while %scompressing",
186 complete_only?
"end of input":
"result",
188 log_debug(
LD_GENERAL,
"method: %d level: %d at len: %lu",
189 method, compression_level, (
unsigned long)in_len);
197 case TOR_COMPRESS_BUFFER_FULL: {
198 if (!compress && outptr < *out+out_alloc) {
202 "Possible truncated or corrupt compressed data");
206 log_warn(
LD_GENERAL,
"While %scompressing data: ran out of space.",
218 const size_t offset = outptr - *out;
220 *out = tor_realloc(*out, out_alloc);
221 outptr = *out + offset;
222 out_remaining = out_alloc - offset;
225 case TOR_COMPRESS_ERROR:
227 "Error while %scompressing data: bad input?",
239 *out_len = outptr - *out;
241 log_warn(
LD_BUG,
"We compressed something and got an insanely high "
242 "compression factor; other Tors would think this was a "
243 "compression bomb.");
248 if (out_alloc == *out_len)
249 *out = tor_realloc(*out, out_alloc + 1);
250 (*out)[*out_len] =
'\0';
262 tor_compress_free(stream);
273 const char *in,
size_t in_len,
299 const char *in,
size_t in_len,
302 int protocol_warn_level)
306 complete_only, protocol_warn_level);
316 if (in_len > 2 &&
fast_memeq(in,
"\x1f\x8b", 2)) {
318 }
else if (in_len > 2 && (in[0] & 0x0f) == 8 &&
321 }
else if (in_len > 2 &&
324 }
else if (in_len > 3 &&
328 return UNKNOWN_METHOD;
360 static unsigned supported = 0;
361 if (supported == 0) {
363 for (m = NO_METHOD; m <= UNKNOWN_METHOD; ++m) {
365 supported |= (1u << m);
378 {
"gzip", GZIP_METHOD },
379 {
"deflate", ZLIB_METHOD },
382 {
"x-tor-lzma", LZMA_METHOD },
383 {
"x-zstd" , ZSTD_METHOD },
384 {
"identity", NO_METHOD },
388 {
"x-gzip", GZIP_METHOD },
409 { NO_METHOD,
"uncompressed" },
410 { GZIP_METHOD,
"gzipped" },
411 { ZLIB_METHOD,
"deflated" },
412 { LZMA_METHOD,
"LZMA compressed" },
413 { ZSTD_METHOD,
"Zstandard compressed" },
414 { UNKNOWN_METHOD,
"unknown encoding" },
440 return UNKNOWN_METHOD;
525 if (zlib_state == NULL)
528 state->
u.zlib_state = zlib_state;
535 if (lzma_state == NULL)
538 state->
u.lzma_state = lzma_state;
545 if (zstd_state == NULL)
548 state->
u.zstd_state = zstd_state;
580 char **out,
size_t *out_len,
581 const char **in,
size_t *in_len,
585 const size_t in_len_orig = *in_len;
586 const size_t out_len_orig = *out_len;
589 if (*out_len == 0 && (*in_len > 0 || finish)) {
593 return TOR_COMPRESS_BUFFER_FULL;
600 out, out_len, in, in_len,
605 out, out_len, in, in_len,
610 out, out_len, in, in_len,
621 if (BUG((rv == TOR_COMPRESS_OK) &&
622 *in_len == in_len_orig &&
623 *out_len == out_len_orig)) {
625 "More info on the bug: method == %s, finish == %d, "
626 " *in_len == in_len_orig == %lu, "
627 "*out_len == out_len_orig == %lu",
629 (
unsigned long)in_len_orig, (
unsigned long)out_len_orig);
630 return TOR_COMPRESS_ERROR;
635 return TOR_COMPRESS_ERROR;
648 tor_zlib_compress_free(state->
u.zlib_state);
651 tor_lzma_compress_free(state->
u.lzma_state);
654 tor_zstd_compress_free(state->
u.zstd_state);
720subsys_compress_initialize(
void)
730 .initialize = subsys_compress_initialize,
Inline functions for reading and writing multibyte values from the middle of strings,...
static uint16_t get_uint16(const void *cp)
static uint16_t tor_ntohs(uint16_t a)
Macro definitions for MIN, MAX, and CLAMP.
void atomic_counter_init(atomic_counter_t *counter)
void atomic_counter_sub(atomic_counter_t *counter, size_t sub)
void atomic_counter_add(atomic_counter_t *counter, size_t add)
size_t atomic_counter_get(atomic_counter_t *counter)
const char * tor_compress_version_str(compress_method_t method)
int tor_compress_init(void)
static const struct @29 compression_method_human_names[]
tor_compress_output_t tor_compress_process(tor_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
int tor_compress_supports_method(compress_method_t method)
static size_t guess_compress_size(int compress, compress_method_t method, compression_level_t compression_level, size_t in_len)
compress_method_t compression_method_get_by_name(const char *name)
int tor_compress_is_compression_bomb(size_t size_in, size_t size_out)
const char * tor_compress_header_version_str(compress_method_t method)
static atomic_counter_t total_compress_allocation
void tor_compress_free_(tor_compress_state_t *state)
unsigned tor_compress_get_supported_method_bitmask(void)
size_t tor_compress_state_size(const tor_compress_state_t *state)
static int tor_compress_impl(int compress, char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method, compression_level_t compression_level, int complete_only, int protocol_warn_level)
void tor_compress_log_init_warnings(void)
int tor_compress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method)
compress_method_t detect_compression_method(const char *in, size_t in_len)
tor_compress_state_t * tor_compress_new(int compress, compress_method_t method, compression_level_t compression_level)
int tor_uncompress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method, int complete_only, int protocol_warn_level)
const char * compression_method_get_name(compress_method_t method)
size_t tor_compress_get_total_allocation(void)
static const struct @28 compression_method_names[]
const char * compression_method_get_human_name(compress_method_t method)
tor_lzma_compress_state_t * tor_lzma_compress_new(int compress, compress_method_t method, compression_level_t level)
const char * tor_lzma_get_version_str(void)
int tor_lzma_method_supported(void)
const char * tor_lzma_get_header_version_str(void)
tor_compress_output_t tor_lzma_compress_process(tor_lzma_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
size_t tor_lzma_compress_state_size(const tor_lzma_compress_state_t *state)
size_t tor_lzma_get_total_allocation(void)
Header for compress_lzma.c.
tor_compress_output_t tor_cnone_compress_process(char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
Header for compress_none.c.
Declare subsystem object for the compress module.
const char * tor_zlib_get_header_version_str(void)
const char * tor_zlib_get_version_str(void)
int tor_zlib_method_supported(void)
tor_zlib_compress_state_t * tor_zlib_compress_new(int compress_, compress_method_t method, compression_level_t compression_level)
size_t tor_zlib_get_total_allocation(void)
size_t tor_zlib_compress_state_size(const tor_zlib_compress_state_t *state)
tor_compress_output_t tor_zlib_compress_process(tor_zlib_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
Header for compress_zlib.c.
const char * tor_zstd_get_header_version_str(void)
int tor_zstd_method_supported(void)
const char * tor_zstd_get_version_str(void)
tor_zstd_compress_state_t * tor_zstd_compress_new(int compress, compress_method_t method, compression_level_t level)
tor_compress_output_t tor_zstd_compress_process(tor_zstd_compress_state_t *state, char **out, size_t *out_len, const char **in, size_t *in_len, int finish)
size_t tor_zstd_get_total_allocation(void)
size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state)
void tor_zstd_warn_if_version_mismatched(void)
Header for compress_zstd.c.
#define fast_memeq(a, b, c)
#define log_fn(severity, domain, args,...)
Headers for util_malloc.c.
union tor_compress_state_t::@30 u
Types used to declare a subsystem.
#define SUBSYS_DECLARE_LOCATION()
#define MOCK_IMPL(rv, funcname, arglist)
Integer definitions used throughout Tor.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert_nonfatal_unreached()