Observed issue
==============
Applications traced with LTTng-UST are expected to all provide the exact
same layout for their channel's context fields, else it leads to
corrupted traces. This is only enforced within LTTng-UST. There is
nothing in the session daemon that prevents this scenario, and it is
only observable when reading the corrupted trace.
This makes the entire trace unreadable from the point where it is
corrupted.
Cause
=====
Even though LTTng-UST sends the entire description of its context fields
along with the channel registration notification, there is no validation
of the context fields' content against the context fields present in the
ust registry.
Solution
========
Validate each registered UST channel context fields against the fields
present in the registry. Reject the application if there is a mismatch.
Known drawbacks
===============
None.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I8b49032bf4f766e549dfccfafdce8cddcbb2873f
#include "rotate.h"
#include "event.h"
#include "event-notifier-error-accounting.h"
#include "rotate.h"
#include "event.h"
#include "event-notifier-error-accounting.h"
+#include "ust-field-utils.h"
struct lttng_ht *ust_app_ht;
struct lttng_ht *ust_app_ht_by_sock;
struct lttng_ht *ust_app_ht;
struct lttng_ht *ust_app_ht_by_sock;
ust_reg_chan = ust_registry_channel_find(registry, chan_reg_key);
LTTNG_ASSERT(ust_reg_chan);
ust_reg_chan = ust_registry_channel_find(registry, chan_reg_key);
LTTNG_ASSERT(ust_reg_chan);
+ /* Channel id is set during the object creation. */
+ chan_id = ust_reg_chan->chan_id;
+
if (!ust_reg_chan->register_done) {
/*
* TODO: eventually use the registry event count for
if (!ust_reg_chan->register_done) {
/*
* TODO: eventually use the registry event count for
} else {
/* Get current already assigned values. */
type = ust_reg_chan->header_type;
} else {
/* Get current already assigned values. */
type = ust_reg_chan->header_type;
+ /*
+ * Validate that the context fields match between
+ * registry and newcoming application.
+ */
+ if (!match_lttng_ust_ctl_field_array(ust_reg_chan->ctx_fields,
+ ust_reg_chan->nr_ctx_fields,
+ fields, nr_fields)) {
+ ERR("Registering application channel due to context field mismatch: pid = %d, sock = %d",
+ app->pid, app->sock);
+ ret_code = -EINVAL;
+ goto reply;
+ }
- /* Channel id is set during the object creation. */
- chan_id = ust_reg_chan->chan_id;
/* Append to metadata */
if (!ust_reg_chan->metadata_dumped) {
/* Append to metadata */
if (!ust_reg_chan->metadata_dumped) {
no_match:
return false;
}
no_match:
return false;
}
+
+/*
+ * Compare two arrays of UST fields.
+ * Return true if both arrays have identical field definitions, false otherwise.
+ */
+bool match_lttng_ust_ctl_field_array(const struct lttng_ust_ctl_field *first,
+ size_t nr_first,
+ const struct lttng_ust_ctl_field *second,
+ size_t nr_second)
+{
+ size_t i;
+ const size_t nr_fields = nr_first;
+
+ /* Compare the array lengths. */
+ if (nr_first != nr_second) {
+ goto no_match;
+ }
+
+ /* Compare each field individually. */
+ for (i = 0; i < nr_fields; i++) {
+ if (!match_lttng_ust_ctl_field(&first[i], &second[i])) {
+ goto no_match;
+ }
+ }
+
+ return true;
+
+no_match:
+ return false;
+}
int match_lttng_ust_ctl_field(const struct lttng_ust_ctl_field *first,
const struct lttng_ust_ctl_field *second);
int match_lttng_ust_ctl_field(const struct lttng_ust_ctl_field *first,
const struct lttng_ust_ctl_field *second);
+/*
+ * Compare two arrays of UST fields.
+ * Return true if both arrays have identical field definitions, false otherwise.
+ */
+bool match_lttng_ust_ctl_field_array(const struct lttng_ust_ctl_field *first,
+ size_t nr_first,
+ const struct lttng_ust_ctl_field *second,
+ size_t nr_second);
+
#endif /* LTTNG_UST_FIELD_UTILS_H */
#endif /* LTTNG_UST_FIELD_UTILS_H */
#include "lttng-sessiond.h"
#include "notification-thread-commands.h"
#include "lttng-sessiond.h"
#include "notification-thread-commands.h"
/*
* Hash table match function for event in the registry.
*/
/*
* Hash table match function for event in the registry.
*/
{
const struct ust_registry_event *key;
struct ust_registry_event *event;
{
const struct ust_registry_event *key;
struct ust_registry_event *event;
LTTNG_ASSERT(node);
LTTNG_ASSERT(_key);
LTTNG_ASSERT(node);
LTTNG_ASSERT(_key);
- /* Compare the number of fields. */
- if (event->nr_fields != key->nr_fields) {
+ /* Compare the arrays of fields. */
+ if (!match_lttng_ust_ctl_field_array(event->fields, event->nr_fields,
+ key->fields, key->nr_fields)) {
- /* Compare each field individually. */
- for (i = 0; i < event->nr_fields; i++) {
- if (!match_lttng_ust_ctl_field(&event->fields[i], &key->fields[i])) {
- goto no_match;
- }
- }
-
/* Compare model URI. */
if (event->model_emf_uri != NULL && key->model_emf_uri == NULL) {
goto no_match;
/* Compare model URI. */
if (event->model_emf_uri != NULL && key->model_emf_uri == NULL) {
goto no_match;