api: verify message size on receipt

When a message is received, verify that it's sufficiently large to
accomodate any VLAs within message. To do that, we need a way to
calculate message size including any VLAs. This patch adds such
funcionality to vppapigen and necessary C code to use those to validate
message size on receipt. Drop messages which are malformed.

Type: improvement
Signed-off-by: Klement Sekera <ksekera@cisco.com>
Change-Id: I2903aa21dee84be6822b064795ba314de46c18f4
This commit is contained in:
Klement Sekera
2021-11-22 21:26:20 +01:00
committed by Ole Tr�an
parent 755042dec0
commit 9b7e8acf79
16 changed files with 280 additions and 88 deletions

View File

@ -132,6 +132,7 @@ typedef struct
void *print_json; /**< message print function (JSON format) */
void *tojson; /**< binary to JSON convert function */
void *fromjson; /**< JSON to binary convert function */
void *calc_size; /**< message size calculation */
int size; /**< message size */
int traced; /**< is this message to be traced? */
int replay; /**< is this message to be replayed? */
@ -170,17 +171,18 @@ VL_MSG_API_POISON (const void *a)
}
/* api_shared.c prototypes */
void vl_msg_api_handler (void *the_msg);
void vl_msg_api_handler_no_free (void *the_msg);
void vl_msg_api_handler_no_trace_no_free (void *the_msg);
void vl_msg_api_trace_only (void *the_msg);
void vl_msg_api_handler (void *the_msg, uword msg_len);
void vl_msg_api_handler_no_free (void *the_msg, uword msg_len);
void vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len);
void vl_msg_api_trace_only (void *the_msg, uword msg_len);
void vl_msg_api_cleanup_handler (void *the_msg);
void vl_msg_api_replay_handler (void *the_msg);
void vl_msg_api_socket_handler (void *the_msg);
void vl_msg_api_socket_handler (void *the_msg, uword msg_len);
void vl_msg_api_set_handlers (int msg_id, char *msg_name, void *handler,
void *cleanup, void *endian, void *print,
int msg_size, int traced, void *print_json,
void *tojson, void *fromjson);
void *tojson, void *fromjson,
void *validate_size);
void vl_msg_api_clean_handlers (int msg_id);
void vl_msg_api_config (vl_msg_api_msg_config_t *);
void vl_msg_api_set_cleanup_handler (int msg_id, void *fp);
@ -251,6 +253,9 @@ typedef struct api_main_t
/** Message convert function vector */
void *(**msg_fromjson_handlers) (cJSON *, int *);
/** Message calc size function vector */
uword (**msg_calc_size_funcs) (void *);
/** Message name vector */
const char **msg_names;

View File

@ -500,8 +500,8 @@ vl_msg_api_barrier_release (void)
}
always_inline void
msg_handler_internal (api_main_t * am,
void *the_msg, int trace_it, int do_it, int free_it)
msg_handler_internal (api_main_t *am, void *the_msg, uword msg_len,
int trace_it, int do_it, int free_it)
{
u16 id = clib_net_to_host_u16 (*((u16 *) the_msg));
u8 *(*print_fp) (void *, void *);
@ -545,8 +545,35 @@ msg_handler_internal (api_main_t * am,
}
}
if (do_it)
uword calc_size = 0;
uword (*calc_size_fp) (void *);
calc_size_fp = am->msg_calc_size_funcs[id];
ASSERT (NULL != calc_size_fp);
if (calc_size_fp)
{
calc_size = (*calc_size_fp) (the_msg);
ASSERT (calc_size <= msg_len);
if (calc_size > msg_len)
{
clib_warning (
"Truncated message '%s' (id %u) received, calculated size "
"%lu is bigger than actual size %llu, message dropped.",
am->msg_names[id], id, calc_size, msg_len);
}
}
else
{
clib_warning ("Message '%s' (id %u) has NULL calc_size_func, cannot "
"verify message size is correct",
am->msg_names[id], id);
}
/* don't process message if it's truncated, otherwise byte swaps
* and stuff could corrupt memory even beyond message if it's malicious
* e.g. VLA length field set to 1M elements, but VLA empty */
if (do_it && calc_size <= msg_len)
{
if (!am->is_mp_safe[id])
{
vl_msg_api_barrier_trace_context (am->msg_names[id]);
@ -569,6 +596,7 @@ msg_handler_internal (api_main_t * am,
if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0))
clib_call_callbacks (am->perf_counter_cbs, am, id,
1 /* after */ );
if (!am->is_mp_safe[id])
vl_msg_api_barrier_release ();
}
@ -767,32 +795,30 @@ vl_msg_api_handler_with_vm_node (api_main_t * am, svm_region_t * vlib_rp,
}
void
vl_msg_api_handler (void *the_msg)
vl_msg_api_handler (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
msg_handler_internal (am, the_msg,
(am->rx_trace
&& am->rx_trace->enabled) /* trace_it */ ,
1 /* do_it */ , 1 /* free_it */ );
msg_handler_internal (am, the_msg, msg_len,
(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
1 /* do_it */, 1 /* free_it */);
}
void
vl_msg_api_handler_no_free (void *the_msg)
vl_msg_api_handler_no_free (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
msg_handler_internal (am, the_msg,
(am->rx_trace
&& am->rx_trace->enabled) /* trace_it */ ,
1 /* do_it */ , 0 /* free_it */ );
msg_handler_internal (am, the_msg, msg_len,
(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
1 /* do_it */, 0 /* free_it */);
}
void
vl_msg_api_handler_no_trace_no_free (void *the_msg)
vl_msg_api_handler_no_trace_no_free (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
0 /* free_it */ );
msg_handler_internal (am, the_msg, msg_len, 0 /* trace_it */, 1 /* do_it */,
0 /* free_it */);
}
/*
@ -805,14 +831,13 @@ vl_msg_api_handler_no_trace_no_free (void *the_msg)
*
*/
void
vl_msg_api_trace_only (void *the_msg)
vl_msg_api_trace_only (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
msg_handler_internal (am, the_msg,
(am->rx_trace
&& am->rx_trace->enabled) /* trace_it */ ,
0 /* do_it */ , 0 /* free_it */ );
msg_handler_internal (am, the_msg, msg_len,
(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
0 /* do_it */, 0 /* free_it */);
}
void
@ -863,14 +888,13 @@ vl_msg_api_get_msg_length (void *msg_arg)
* vl_msg_api_socket_handler
*/
void
vl_msg_api_socket_handler (void *the_msg)
vl_msg_api_socket_handler (void *the_msg, uword msg_len)
{
api_main_t *am = vlibapi_get_main ();
msg_handler_internal (am, the_msg,
(am->rx_trace
&& am->rx_trace->enabled) /* trace_it */ ,
1 /* do_it */ , 0 /* free_it */ );
msg_handler_internal (am, the_msg, msg_len,
(am->rx_trace && am->rx_trace->enabled) /* trace_it */,
1 /* do_it */, 0 /* free_it */);
}
#define foreach_msg_api_vector \
@ -882,6 +906,7 @@ vl_msg_api_socket_handler (void *the_msg)
_ (msg_print_json_handlers) \
_ (msg_tojson_handlers) \
_ (msg_fromjson_handlers) \
_ (msg_calc_size_funcs) \
_ (api_trace_cfg) \
_ (message_bounce) \
_ (is_mp_safe) \
@ -927,6 +952,7 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c)
am->msg_print_json_handlers[c->id] = c->print_json;
am->msg_tojson_handlers[c->id] = c->tojson;
am->msg_fromjson_handlers[c->id] = c->fromjson;
am->msg_calc_size_funcs[c->id] = c->calc_size;
am->message_bounce[c->id] = c->message_bounce;
am->is_mp_safe[c->id] = c->is_mp_safe;
am->is_autoendian[c->id] = c->is_autoendian;
@ -948,7 +974,8 @@ vl_msg_api_config (vl_msg_api_msg_config_t * c)
void
vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
void *endian, void *print, int size, int traced,
void *print_json, void *tojson, void *fromjson)
void *print_json, void *tojson, void *fromjson,
void *calc_size)
{
vl_msg_api_msg_config_t cfg;
vl_msg_api_msg_config_t *c = &cfg;
@ -969,6 +996,7 @@ vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
c->tojson = tojson;
c->fromjson = fromjson;
c->print_json = print_json;
c->calc_size = calc_size;
vl_msg_api_config (c);
}
@ -999,8 +1027,11 @@ vl_msg_api_queue_handler (svm_queue_t * q)
{
uword msg;
while (!svm_queue_sub (q, (u8 *) & msg, SVM_Q_WAIT, 0))
vl_msg_api_handler ((void *) msg);
while (!svm_queue_sub (q, (u8 *) &msg, SVM_Q_WAIT, 0))
{
msgbuf_t *msgbuf = (msgbuf_t *) ((u8 *) msg - offsetof (msgbuf_t, data));
vl_msg_api_handler ((void *) msg, ntohl (msgbuf->data_len));
}
}
u32