Fix: event notification capture: validate buffer length
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 28 Sep 2022 14:34:42 +0000 (10:34 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 28 Sep 2022 18:21:45 +0000 (14:21 -0400)
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 <mathieu.desnoyers@efficios.com>
Change-Id: Ifa2cdaf084e2ebee2efa052331107cb4d9095243

src/lttng-event-notifier-notification.c

index b8f01395c57bf4e7fd3954f555aa26a286acbf7a..957883a801e6651e48b307ba3320e688f740b25b 100644 (file)
@@ -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(&notif, event_notifier)) {
-               record_error(event_notifier);
-               goto end;
-       }
+       if (notification_init(&notif, event_notifier))
+               goto error;
+
+       captures_left = event_notifier->priv->num_captures;
+       if (!validate_buffer_len(&notif, 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(&notif.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(&notif, &output);
-                       else
-                               ret = notification_append_empty_capture(&notif);
-                       if (ret) {
+                       if (ret || !validate_buffer_len(&notif, 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(&notif.writer, save_pos);
+                               ret = notification_append_empty_capture(&notif);
+                               WARN_ON_ONCE(ret);
                        }
                }
        }
 
+       if (notif.has_captures && lttng_msgpack_end_array(&notif.writer))
+               goto error;
+
        /*
         * Send the notification (including the capture buffer) to the
         * sessiond.
         */
        notification_send(&notif, event_notifier);
-end:
+       return;
+
+error:
+       record_error(event_notifier);
        return;
 }
This page took 0.031046 seconds and 4 git commands to generate.