diff --git a/bufferevent_ratelim.c b/bufferevent_ratelim.c index d4624615..d04662ce 100644 --- a/bufferevent_ratelim.c +++ b/bufferevent_ratelim.c @@ -154,7 +154,17 @@ ev_token_bucket_cfg_new(size_t read_rate, size_t read_burst, tick_len = &g; } - msec_per_tick = (tick_len->tv_sec * 1000) + + /* Avoid possible overflow. + * - there is no point in accepting values larger then INT_MAX/1000 anyway + * - on windows tv_sec (tv_usec) is long, which is int, which has upper value limit INT_MAX + * - and also negative values does not make any sense + */ + if (tick_len->tv_sec < 0 || tick_len->tv_sec > INT_MAX/1000) + return NULL; + + /* Note, overflow with tv_usec is not possible since tv_sec is limited to + * INT_MAX/1000 anyway */ + msec_per_tick = (unsigned)(tick_len->tv_sec * 1000) + (tick_len->tv_usec & COMMON_TIMEOUT_MICROSECONDS_MASK)/1000; if (!msec_per_tick) return NULL; diff --git a/test/regress_bufferevent.c b/test/regress_bufferevent.c index f069f4b8..cb23319d 100644 --- a/test/regress_bufferevent.c +++ b/test/regress_bufferevent.c @@ -57,6 +57,7 @@ #include #include #include +#include #ifdef EVENT__HAVE_ARPA_INET_H #include @@ -203,13 +204,52 @@ static void test_bufferevent_pair_flush_normal(void) { test_bufferevent_impl(1, static void test_bufferevent_pair_flush_flush(void) { test_bufferevent_impl(1, BEV_FLUSH); } static void test_bufferevent_pair_flush_finished(void) { test_bufferevent_impl(1, BEV_FINISHED); } -static void test_bufferevent_ratelimit_fuzz(void) +static void test_bufferevent_ratelimit_div_by_zero(void) { struct timeval cfg_tick = {0, 0}; struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); tt_ptr_op(cfg, ==, NULL); test_ok = 1; +end: + ; +} +static void test_bufferevent_ratelimit_overflow(void) +{ + { + struct timeval cfg_tick = {LONG_MAX, 0}; + struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); + tt_ptr_op(cfg, ==, NULL); + } + { + struct timeval cfg_tick = {UINT_MAX-1, 0}; + struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); + tt_ptr_op(cfg, ==, NULL); + } + { + struct timeval cfg_tick = {INT_MAX, 0}; + struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); + tt_ptr_op(cfg, ==, NULL); + } + { + struct timeval cfg_tick = {INT_MAX/1000+1, 0}; + struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); + tt_ptr_op(cfg, ==, NULL); + } + { + struct timeval cfg_tick = {INT_MAX/1000, 0}; + struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); + tt_ptr_op(cfg, !=, NULL); + ev_token_bucket_cfg_free(cfg); + } + { + struct timeval cfg_tick = {INT_MAX/1000-1, 0}; + struct ev_token_bucket_cfg *cfg = ev_token_bucket_cfg_new(1, 1, 1, 1, &cfg_tick); + tt_ptr_op(cfg, !=, NULL); + ev_token_bucket_cfg_free(cfg); + } + test_ok = 1; + end: ; } @@ -1474,7 +1514,8 @@ struct testcase_t bufferevent_testcases[] = { test_bufferevent_read_failed, TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, NULL }, - LEGACY(bufferevent_ratelimit_fuzz, TT_ISOLATED), + LEGACY(bufferevent_ratelimit_div_by_zero, TT_ISOLATED), + LEGACY(bufferevent_ratelimit_overflow, TT_ISOLATED), END_OF_TESTCASES, };