X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=src%2Flttng-event-notifier-notification.c;h=ecbc0676291c4e9f425cdbbb86ad1ea37656c04a;hb=a27c8df7d7ff43a3bba67e8b0ea29ebbf29f674e;hp=52b5593ac9325b5324c9169f72ff736044a49cac;hpb=6657edecc8dd4f294c42339645151006f60b3811;p=lttng-modules.git diff --git a/src/lttng-event-notifier-notification.c b/src/lttng-event-notifier-notification.c index 52b5593a..ecbc0676 100644 --- a/src/lttng-event-notifier-notification.c +++ b/src/lttng-event-notifier-notification.c @@ -5,13 +5,15 @@ * Copyright (C) 2020 Francis Deslauriers */ +#include #include #include #include #include #include -#include +#include +#include /* * The capture buffer size needs to be below 1024 bytes to avoid the @@ -23,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; @@ -44,25 +48,21 @@ int capture_enum(struct lttng_msgpack_writer *writer, */ ret = lttng_msgpack_begin_map(writer, 2); if (ret) { - WARN_ON_ONCE(1); goto end; } ret = lttng_msgpack_write_str(writer, "type"); if (ret) { - WARN_ON_ONCE(1); goto end; } ret = lttng_msgpack_write_str(writer, "enum"); if (ret) { - WARN_ON_ONCE(1); goto end; } ret = lttng_msgpack_write_str(writer, "value"); if (ret) { - WARN_ON_ONCE(1); goto end; } @@ -70,170 +70,234 @@ int capture_enum(struct lttng_msgpack_writer *writer, case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM: ret = lttng_msgpack_write_signed_integer(writer, output->u.s); if (ret) { - WARN_ON_ONCE(1); goto end; } break; case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM: ret = lttng_msgpack_write_signed_integer(writer, output->u.u); if (ret) { - WARN_ON_ONCE(1); goto end; } break; default: - WARN_ON(1); + WARN_ON_ONCE(1); + ret = -1; + goto end; } ret = lttng_msgpack_end_map(writer); - if (ret) - WARN_ON_ONCE(1); - end: return ret; } static -int64_t capture_sequence_element_signed(uint8_t *ptr, - const struct lttng_integer_type *type) +int capture_sequence_element_signed(uint8_t *ptr, + const struct lttng_kernel_type_integer *type, + int64_t *_value) { int64_t value = 0; unsigned int size = type->size; + bool user = type->user; bool byte_order_reversed = type->reverse_byte_order; switch (size) { case 8: - value = *ptr; + { + int8_t tmp; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(int8_t))) + return -1; + } else { + tmp = *ptr; + } + value = tmp; break; + } case 16: { int16_t tmp; - tmp = *(int16_t *) ptr; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(int16_t))) + return -1; + } else { + tmp = *(int16_t *) ptr; + } if (byte_order_reversed) __swab16s(&tmp); - value = tmp; break; } case 32: { int32_t tmp; - tmp = *(int32_t *) ptr; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(int32_t))) + return -1; + } else { + tmp = *(int32_t *) ptr; + } if (byte_order_reversed) __swab32s(&tmp); - value = tmp; break; } case 64: { int64_t tmp; - tmp = *(int64_t *) ptr; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(int64_t))) + return -1; + } else { + tmp = *(int64_t *) ptr; + } if (byte_order_reversed) __swab64s(&tmp); - value = tmp; break; } default: - WARN_ON(1); + WARN_ON_ONCE(1); + return -1; } - return value; + *_value = value; + return 0; } static -uint64_t capture_sequence_element_unsigned(uint8_t *ptr, - const struct lttng_integer_type *type) +int capture_sequence_element_unsigned(uint8_t *ptr, + const struct lttng_kernel_type_integer *type, + uint64_t *_value) { uint64_t value = 0; unsigned int size = type->size; + bool user = type->user; bool byte_order_reversed = type->reverse_byte_order; switch (size) { case 8: - value = *ptr; + { + uint8_t tmp; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(uint8_t))) + return -1; + } else { + tmp = *ptr; + } + value = tmp; break; + } case 16: { uint16_t tmp; - tmp = *(uint16_t *) ptr; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(uint16_t))) + return -1; + } else { + tmp = *(uint16_t *) ptr; + } if (byte_order_reversed) __swab16s(&tmp); - value = tmp; break; } case 32: { uint32_t tmp; - tmp = *(uint32_t *) ptr; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(uint32_t))) + return -1; + } else { + tmp = *(uint32_t *) ptr; + } if (byte_order_reversed) __swab32s(&tmp); - value = tmp; break; } case 64: { uint64_t tmp; - tmp = *(uint64_t *) ptr; + + if (user) { + if (lttng_copy_from_user_check_nofault(&tmp, ptr, sizeof(uint64_t))) + return -1; + } else { + tmp = *(uint64_t *) ptr; + } if (byte_order_reversed) __swab64s(&tmp); - value = tmp; break; } default: - WARN_ON(1); + WARN_ON_ONCE(1); + return -1; } - return value; + *_value = value; + return 0; } int capture_sequence(struct lttng_msgpack_writer *writer, struct lttng_interpreter_output *output) { - const struct lttng_integer_type *integer_type = NULL; - const struct lttng_type *nested_type; + const struct lttng_kernel_type_integer *integer_type = NULL; + const struct lttng_kernel_type_common *nested_type; uint8_t *ptr; bool signedness; int ret, i; ret = lttng_msgpack_begin_array(writer, output->u.sequence.nr_elem); if (ret) { - WARN_ON_ONCE(1); goto end; } ptr = (uint8_t *) output->u.sequence.ptr; nested_type = output->u.sequence.nested_type; - switch (nested_type->atype) { - case atype_integer: - integer_type = &nested_type->u.integer; + switch (nested_type->type) { + case lttng_kernel_type_integer: + integer_type = lttng_kernel_get_type_integer(nested_type); break; - case atype_enum_nestable: + case lttng_kernel_type_enum: /* Treat enumeration as an integer. */ - integer_type = &nested_type->u.enum_nestable.container_type->u.integer; + integer_type = lttng_kernel_get_type_integer(lttng_kernel_get_type_enum(nested_type)->container_type); break; default: /* Capture of array of non-integer are not supported. */ - WARN_ON(1); + WARN_ON_ONCE(1); + ret = -1; + goto end; } signedness = integer_type->signedness; for (i = 0; i < output->u.sequence.nr_elem; i++) { if (signedness) { - ret = lttng_msgpack_write_signed_integer(writer, - capture_sequence_element_signed(ptr, integer_type)); + int64_t v; + + ret = capture_sequence_element_signed(ptr, integer_type, &v); + if (ret) { + goto end; + } + ret = lttng_msgpack_write_signed_integer(writer, v); if (ret) { - WARN_ON_ONCE(1); goto end; } } else { - ret = lttng_msgpack_write_unsigned_integer(writer, - capture_sequence_element_unsigned(ptr, integer_type)); + uint64_t v; + + ret = capture_sequence_element_unsigned(ptr, integer_type, &v); + if (ret) { + goto end; + } + ret = lttng_msgpack_write_unsigned_integer(writer, v); if (ret) { - WARN_ON_ONCE(1); goto end; } } @@ -245,15 +309,13 @@ int capture_sequence(struct lttng_msgpack_writer *writer, * take into account that the next element might be further * away. */ - WARN_ON(integer_type->alignment > integer_type->size); + WARN_ON_ONCE(integer_type->alignment > integer_type->size); /* Size is in number of bits. */ ptr += (integer_type->size / CHAR_BIT) ; } ret = lttng_msgpack_end_array(writer); - if (ret) - WARN_ON_ONCE(1); end: return ret; } @@ -269,45 +331,28 @@ int notification_append_capture( switch (output->type) { case LTTNG_INTERPRETER_TYPE_S64: ret = lttng_msgpack_write_signed_integer(writer, output->u.s); - if (ret) { - WARN_ON_ONCE(1); - goto end; - } break; case LTTNG_INTERPRETER_TYPE_U64: ret = lttng_msgpack_write_unsigned_integer(writer, output->u.u); - if (ret) { - WARN_ON_ONCE(1); - goto end; - } break; case LTTNG_INTERPRETER_TYPE_STRING: - ret = lttng_msgpack_write_str(writer, output->u.str.str); - if (ret) { - WARN_ON_ONCE(1); - goto end; + if (output->u.str.user) { + ret = lttng_msgpack_write_user_str(writer, output->u.str.user_str); + } else { + ret = lttng_msgpack_write_str(writer, output->u.str.str); } break; case LTTNG_INTERPRETER_TYPE_SEQUENCE: ret = capture_sequence(writer, output); - if (ret) { - WARN_ON_ONCE(1); - goto end; - } break; case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM: case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM: ret = capture_enum(writer, output); - if (ret) { - WARN_ON_ONCE(1); - goto end; - } break; default: ret = -1; - WARN_ON(1); + WARN_ON_ONCE(1); } -end: return ret; } @@ -315,29 +360,24 @@ static int notification_append_empty_capture( struct lttng_event_notifier_notification *notif) { - int ret = lttng_msgpack_write_nil(¬if->writer); - if (ret) - WARN_ON_ONCE(1); - - return ret; + return lttng_msgpack_write_nil(¬if->writer); } static int notification_init(struct lttng_event_notifier_notification *notif, - struct lttng_event_notifier *event_notifier) + struct lttng_kernel_event_notifier *event_notifier) { struct lttng_msgpack_writer *writer = ¬if->writer; int ret = 0; notif->has_captures = false; - if (event_notifier->num_captures > 0) { + if (event_notifier->priv->num_captures > 0) { lttng_msgpack_writer_init(writer, notif->capture_buf, CAPTURE_BUFFER_SIZE); - ret = lttng_msgpack_begin_array(writer, event_notifier->num_captures); + ret = lttng_msgpack_begin_array(writer, event_notifier->priv->num_captures); if (ret) { - WARN_ON_ONCE(1); goto end; } @@ -349,25 +389,25 @@ end: } static -void record_error(struct lttng_event_notifier *event_notifier) +void record_error(struct lttng_kernel_event_notifier *event_notifier) { - struct lttng_event_notifier_group *event_notifier_group = event_notifier->group; + struct lttng_event_notifier_group *event_notifier_group = event_notifier->priv->group; struct lttng_counter *error_counter; size_t dimension_index[1]; int ret; /* - * lttng_smp_load_acquire paired with lttng_smp_store_release orders - * creation of the error counter and setting error_counter_len - * before the error_counter is used. + * smp_load_acquire paired with smp_store_release orders creation of + * the error counter and setting error_counter_len before the + * error_counter is used. */ - error_counter = lttng_smp_load_acquire(&event_notifier_group->error_counter); + error_counter = smp_load_acquire(&event_notifier_group->error_counter); /* This group may not have an error counter attached to it. */ if (!error_counter) return; - dimension_index[0] = event_notifier->error_counter_index; + dimension_index[0] = event_notifier->priv->error_counter_index; ret = error_counter->ops->counter_add(error_counter->counter, dimension_index, 1); @@ -377,16 +417,16 @@ void record_error(struct lttng_event_notifier *event_notifier) static void notification_send(struct lttng_event_notifier_notification *notif, - struct lttng_event_notifier *event_notifier) + struct lttng_kernel_event_notifier *event_notifier) { - struct lttng_event_notifier_group *event_notifier_group = event_notifier->group; - struct lib_ring_buffer_ctx ctx; - struct lttng_kernel_event_notifier_notification kernel_notif; + struct lttng_event_notifier_group *event_notifier_group = event_notifier->priv->group; + struct lttng_kernel_ring_buffer_ctx ctx; + struct lttng_kernel_abi_event_notifier_notification kernel_notif; size_t capture_buffer_content_len, reserve_size; int ret; reserve_size = sizeof(kernel_notif); - kernel_notif.token = event_notifier->user_token; + kernel_notif.token = event_notifier->priv->parent.user_token; if (notif->has_captures) { capture_buffer_content_len = notif->writer.write_pos - notif->writer.buffer; @@ -399,49 +439,57 @@ void notification_send(struct lttng_event_notifier_notification *notif, reserve_size += capture_buffer_content_len; kernel_notif.capture_buf_size = capture_buffer_content_len; - lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL, reserve_size, - lttng_alignof(kernel_notif), -1); - ret = event_notifier_group->ops->event_reserve(&ctx, 0); + lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, reserve_size, + lttng_alignof(kernel_notif), NULL); + ret = event_notifier_group->ops->event_reserve(&ctx); if (ret < 0) { record_error(event_notifier); return; } - lib_ring_buffer_align_ctx(&ctx, lttng_alignof(kernel_notif)); - /* Write the notif structure. */ event_notifier_group->ops->event_write(&ctx, &kernel_notif, - sizeof(kernel_notif)); + sizeof(kernel_notif), lttng_alignof(kernel_notif)); /* * Write the capture buffer. No need to realigned as the below is a raw * char* buffer. */ event_notifier_group->ops->event_write(&ctx, ¬if->capture_buf, - capture_buffer_content_len); + capture_buffer_content_len, 1); event_notifier_group->ops->event_commit(&ctx); irq_work_queue(&event_notifier_group->wakeup_pending); } -void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier, - struct lttng_probe_ctx *lttng_probe_ctx, - const char *stack_data) +/* + * 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 }; - int ret; + size_t captures_left; - if (unlikely(!READ_ONCE(event_notifier->enabled))) - return; + if (notification_init(¬if, event_notifier)) + goto error; - ret = notification_init(¬if, event_notifier); - if (ret) { - WARN_ON_ONCE(1); - goto end; - } + captures_left = event_notifier->priv->num_captures; + if (!validate_buffer_len(¬if, captures_left)) + goto error; - if (unlikely(!list_empty(&event_notifier->capture_bytecode_runtime_head))) { - struct lttng_bytecode_runtime *capture_bc_runtime; + if (unlikely(notif_ctx->eval_capture)) { + struct lttng_kernel_bytecode_runtime *capture_bc_runtime; /* * Iterate over all the capture bytecodes. If the interpreter @@ -449,26 +497,44 @@ void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_n * `output` parameter to the capture buffer. If the interpreter * fails, append an empty capture to the buffer. */ - list_for_each_entry(capture_bc_runtime, - &event_notifier->capture_bytecode_runtime_head, node) { + list_for_each_entry_rcu(capture_bc_runtime, + &event_notifier->priv->capture_bytecode_runtime_head, node) { struct lttng_interpreter_output output; + uint8_t *save_pos; + int ret = -1; - if (capture_bc_runtime->interpreter_funcs.capture(capture_bc_runtime, - lttng_probe_ctx, stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG) + 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 + if (ret || !validate_buffer_len(¬if, captures_left)) { + /* + * 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); - - if (ret) - printk(KERN_WARNING "Error appending capture to notification"); + 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; }