From f125ded468c0897642e1a5608cee3c9c8398cdc5 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 28 Sep 2022 10:34:42 -0400 Subject: [PATCH] Fix: event notification capture: validate buffer length Validate that the buffer length is large enough to hold empty capture fields. If the buffer is initially not large enough to hold empty capture fields for each field to capture, discard the notification. If after capturing a field there is not enough room anymore in the buffer to write empty capture fields, skip the offending large field by writing an empty capture field in its place. Signed-off-by: Mathieu Desnoyers Change-Id: Ifa2cdaf084e2ebee2efa052331107cb4d9095243 --- src/lttng-event-notifier-notification.c | 50 +++++++++++++++++++------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/lttng-event-notifier-notification.c b/src/lttng-event-notifier-notification.c index b8f01395..957883a8 100644 --- a/src/lttng-event-notifier-notification.c +++ b/src/lttng-event-notifier-notification.c @@ -25,6 +25,8 @@ */ #define CAPTURE_BUFFER_SIZE 512 +#define MSG_WRITE_NIL_LEN 1 + struct lttng_event_notifier_notification { int notification_fd; uint64_t event_notifier_token; @@ -442,20 +444,34 @@ void notification_send(struct lttng_event_notifier_notification *notif, irq_work_queue(&event_notifier_group->wakeup_pending); } +/* + * Validate that the buffer has enough room to hold empty capture fields. + */ +static +bool validate_buffer_len(struct lttng_event_notifier_notification *notif, size_t captures_left) +{ + if (notif->writer.end_write_pos - notif->writer.write_pos < MSG_WRITE_NIL_LEN * captures_left) + return false; + return true; +} + void lttng_event_notifier_notification_send(struct lttng_kernel_event_notifier *event_notifier, const char *stack_data, struct lttng_kernel_probe_ctx *probe_ctx, struct lttng_kernel_notification_ctx *notif_ctx) { struct lttng_event_notifier_notification notif = { 0 }; + size_t captures_left; if (unlikely(!READ_ONCE(event_notifier->parent.enabled))) return; - if (notification_init(¬if, event_notifier)) { - record_error(event_notifier); - goto end; - } + if (notification_init(¬if, event_notifier)) + goto error; + + captures_left = event_notifier->priv->num_captures; + if (!validate_buffer_len(¬if, captures_left)) + goto error; if (unlikely(notif_ctx->eval_capture)) { struct lttng_kernel_bytecode_runtime *capture_bc_runtime; @@ -470,30 +486,40 @@ void lttng_event_notifier_notification_send(struct lttng_kernel_event_notifier * &event_notifier->priv->capture_bytecode_runtime_head, node) { struct lttng_interpreter_output output; uint8_t *save_pos; - int ret; + int ret = -1; lttng_msgpack_save_writer_pos(¬if.writer, &save_pos); + captures_left--; if (capture_bc_runtime->interpreter_func(capture_bc_runtime, stack_data, probe_ctx, &output) == LTTNG_KERNEL_BYTECODE_INTERPRETER_OK) ret = notification_append_capture(¬if, &output); - else - ret = notification_append_empty_capture(¬if); - if (ret) { + if (ret || !validate_buffer_len(¬if, captures_left)) { /* - * On append capture error, skip the field - * capture by restoring the msgpack writer - * position. + * On append capture error or if the generated + * buffer data would not leave enough room to + * write empty capture fields for the remaining + * fields, skip the field capture by restoring + * the msgpack writer position and writing an + * empty capture field. */ lttng_msgpack_restore_writer_pos(¬if.writer, save_pos); + ret = notification_append_empty_capture(¬if); + WARN_ON_ONCE(ret); } } } + if (notif.has_captures && lttng_msgpack_end_array(¬if.writer)) + goto error; + /* * Send the notification (including the capture buffer) to the * sessiond. */ notification_send(¬if, event_notifier); -end: + return; + +error: + record_error(event_notifier); return; } -- 2.34.1