Add request size validation to prevent OOMDoS

This commit is contained in:
Vitaliy Filippov
2026-05-01 15:57:15 +03:00
parent a972c13571
commit 80a05c052a
6 changed files with 90 additions and 5 deletions
+7 -2
View File
@@ -50,6 +50,8 @@
#define AES_256_GCM_KEY_SIZE 32
#define AES_256_GCM_IV_SIZE 12
#define MAX_SIMPLE_PAYLOAD_SIZE 1048576
struct msgr_sendp_t
{
osd_op_t *op;
@@ -307,9 +309,12 @@ public:
timerfd_manager_t *tfd = NULL;
ring_loop_t *ringloop = NULL;
bool has_sendmsg_zc = false;
// osd_num_t is only for logging and asserts
uint64_t next_client_id = 1;
osd_num_t osd_num;
// osd_num = 0 for client messenger, osd_num > 0 for OSD messenger
osd_num_t osd_num = 0;
uint32_t clean_entry_bitmap_size = 0;
uint32_t bs_block_size = 0;
uint32_t max_write_request_size = 0;
robin_hood::unordered_flat_map<uint64_t, osd_client_t*> clients;
robin_hood::unordered_flat_map<uint64_t, osd_client_t*> osd_peers;
robin_hood::unordered_flat_map<int, osd_client_t*> clients_by_fd;
+1 -1
View File
@@ -181,7 +181,7 @@ struct __attribute__((visibility("default"))) osd_op_t
// bitmap, bitmap_len, bmp_data are only meaningful for reads
void *bitmap = NULL;
unsigned bitmap_len = 0;
unsigned bmp_data = 0;
size_t bmp_data = 0;
uint8_t *bitmap_buf = NULL;
void *rmw_buf = NULL;
std::shared_ptr<osd_op_enc_t> enc;
+62 -2
View File
@@ -731,18 +731,42 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
{
osd_op_t *cur_op = cl->read_op;
cl->read_op_size = 0;
if (cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
if (!osd_num)
{
if (log_level > 1)
fprintf(stderr, "Error: operation received from an OSD peer %ju, stopping\n", cl->client_id);
return false;
}
else if (cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE ||
cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE)
{
if (cur_op->req.sec_rw.attr_len > 0)
{
if (cur_op->req.sec_rw.attr_len > sizeof(unsigned))
if (cur_op->req.sec_rw.attr_len > clean_entry_bitmap_size)
{
if (log_level > 1)
{
fprintf(stderr, "Error: peer %ju secondary write request attr_len too large (%u > %u bytes), stopping\n", cl->client_id,
cur_op->req.sec_rw.attr_len, clean_entry_bitmap_size);
}
return false;
}
else if (cur_op->req.sec_rw.attr_len > sizeof(cur_op->bmp_data))
cur_op->bitmap = cur_op->rmw_buf = malloc_or_die(cur_op->req.sec_rw.attr_len);
else
cur_op->bitmap = &cur_op->bmp_data;
}
if (cur_op->req.sec_rw.len > 0)
{
if (cur_op->req.sec_rw.len > bs_block_size)
{
if (log_level > 1)
{
fprintf(stderr, "Error: peer %ju secondary write request size too large (%u > %u bytes), stopping\n", cl->client_id,
cur_op->req.sec_rw.len, bs_block_size);
}
return false;
}
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.sec_rw.len);
}
cl->read_op_size = cur_op->req.sec_rw.len + cur_op->req.sec_rw.attr_len;
@@ -752,6 +776,15 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
{
if (cur_op->req.sec_stab.len > 0)
{
if (cur_op->req.sec_stab.len > MAX_SIMPLE_PAYLOAD_SIZE)
{
if (log_level > 1)
{
fprintf(stderr, "Error: peer %ju stabilize request size too large (%lu > %u bytes), stopping\n", cl->client_id,
cur_op->req.sec_stab.len, MAX_SIMPLE_PAYLOAD_SIZE);
}
return false;
}
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.sec_stab.len);
}
cl->read_op_size = cur_op->req.sec_stab.len;
@@ -760,6 +793,15 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
{
if (cur_op->req.sec_read_bmp.len > 0)
{
if (cur_op->req.sec_read_bmp.len > MAX_SIMPLE_PAYLOAD_SIZE)
{
if (log_level > 1)
{
fprintf(stderr, "Error: peer %ju sec_read_bmp request size too large (%lu > %u bytes), stopping\n", cl->client_id,
cur_op->req.sec_read_bmp.len, MAX_SIMPLE_PAYLOAD_SIZE);
}
return false;
}
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.sec_read_bmp.len);
}
cl->read_op_size = cur_op->req.sec_read_bmp.len;
@@ -768,6 +810,15 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
{
if (cur_op->req.rw.len > 0)
{
if (cur_op->req.rw.len > max_write_request_size)
{
if (log_level > 1)
{
fprintf(stderr, "Error: peer %ju write request size too large (%u > %u bytes), stopping\n", cl->client_id,
cur_op->req.rw.len, max_write_request_size);
}
return false;
}
cur_op->buf = memalign_or_die(MEM_ALIGNMENT, cur_op->req.rw.len);
}
cl->read_op_size = cur_op->req.rw.len;
@@ -776,6 +827,15 @@ bool osd_messenger_t::allocate_op_buffers(osd_client_t *cl)
{
if (cur_op->req.show_conf.json_len > 0)
{
if (cur_op->req.show_conf.json_len > MAX_SIMPLE_PAYLOAD_SIZE)
{
if (log_level > 1)
{
fprintf(stderr, "Error: peer %ju show_config request length too large (%lu > %u bytes), stopping\n", cl->client_id,
cur_op->req.show_conf.json_len, MAX_SIMPLE_PAYLOAD_SIZE);
}
return false;
}
cur_op->buf = malloc_or_die(cur_op->req.show_conf.json_len+1);
((uint8_t*)cur_op->buf)[cur_op->req.show_conf.json_len] = 0;
}