Merge pull request #1558 from azat/ratelimit-fixes

Fix few issues found by oss-fuzz in bufferevent ratelimits
This commit is contained in:
Azat Khuzhin 2024-03-03 23:10:48 +01:00 committed by GitHub
commit f2b3ce6b55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 73 additions and 2 deletions

View File

@ -146,11 +146,29 @@ ev_token_bucket_cfg_new(size_t read_rate, size_t read_burst,
{
struct ev_token_bucket_cfg *r;
struct timeval g;
unsigned msec_per_tick;
if (! tick_len) {
g.tv_sec = 1;
g.tv_usec = 0;
tick_len = &g;
}
/* 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;
if (read_rate > read_burst || write_rate > write_burst ||
read_rate < 1 || write_rate < 1)
return NULL;
@ -167,8 +185,7 @@ ev_token_bucket_cfg_new(size_t read_rate, size_t read_burst,
r->read_maximum = read_burst;
r->write_maximum = write_burst;
memcpy(&r->tick_timeout, tick_len, sizeof(struct timeval));
r->msec_per_tick = (tick_len->tv_sec * 1000) +
(tick_len->tv_usec & COMMON_TIMEOUT_MICROSECONDS_MASK)/1000;
r->msec_per_tick = msec_per_tick;
return r;
}

View File

@ -57,6 +57,7 @@
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <limits.h>
#ifdef EVENT__HAVE_ARPA_INET_H
#include <arpa/inet.h>
@ -203,6 +204,56 @@ 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_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:
;
}
#if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED)
/**
* Trace lock/unlock/alloc/free for locks.
@ -1463,6 +1514,9 @@ struct testcase_t bufferevent_testcases[] = {
test_bufferevent_read_failed,
TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, &basic_setup, NULL },
LEGACY(bufferevent_ratelimit_div_by_zero, TT_ISOLATED),
LEGACY(bufferevent_ratelimit_overflow, TT_ISOLATED),
END_OF_TESTCASES,
};