Fix: ctf: fix possible use-after-free in ctf_fs_component_create
[babeltrace.git] / src / plugins / ctf / fs-src / fs.c
index 1cb42e09791fd097715dce6c0aea71d482590b5f..8036fe1598a10f5384f5a507718ce63af3c676e1 100644 (file)
@@ -405,9 +405,8 @@ struct ctf_fs_component *ctf_fs_component_create(bt_logging_level log_level,
        goto end;
 
 error:
-       if (ctf_fs) {
-               ctf_fs_destroy(ctf_fs);
-       }
+       ctf_fs_destroy(ctf_fs);
+       ctf_fs = NULL;
 
 end:
        return ctf_fs;
@@ -1770,6 +1769,15 @@ end:
        return ret;
 }
 
+static
+int decode_packet_first_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
+       struct ctf_clock_class *default_cc,
+       struct ctf_fs_ds_index_entry *index_entry, uint64_t *cs, int64_t *ts_ns)
+{
+       return decode_clock_snapshot_after_event(ctf_fs_trace, default_cc,
+               index_entry, FIRST_EVENT, cs, ts_ns);
+}
+
 static
 int decode_packet_last_event_timestamp(struct ctf_fs_trace *ctf_fs_trace,
        struct ctf_clock_class *default_cc,
@@ -1869,6 +1877,167 @@ end:
        return ret;
 }
 
+/*
+ * Fix up packet index entries for barectf's "event-before-packet" bug.
+ * Some buggy barectf tracer versions may emit events with a timestamp that is
+ * less than the timestamp_begin of the their packets.
+ *
+ * To fix up this erroneous data we do the following:
+ *  1. Starting at the second index entry, set the timestamp_begin of the
+ *     current entry to the timestamp of the first event of the packet.
+ *  2. Set the previous entry's timestamp_end to the timestamp_begin of the
+ *     current packet.
+ *
+ * Known buggy tracer versions:
+ *  - before barectf 2.3.1
+ */
+static
+int fix_index_barectf_event_before_packet_bug(struct ctf_fs_trace *trace)
+{
+       int ret = 0;
+       guint ds_file_group_i;
+       GPtrArray *ds_file_groups = trace->ds_file_groups;
+       bt_logging_level log_level = trace->log_level;
+
+       for (ds_file_group_i = 0; ds_file_group_i < ds_file_groups->len;
+                       ds_file_group_i++) {
+               guint entry_i;
+               struct ctf_clock_class *default_cc;
+               struct ctf_fs_ds_file_group *ds_file_group =
+                       g_ptr_array_index(ds_file_groups, ds_file_group_i);
+
+               struct ctf_fs_ds_index *index = ds_file_group->index;
+
+               BT_ASSERT(index);
+               BT_ASSERT(index->entries);
+               BT_ASSERT(index->entries->len > 0);
+
+               BT_ASSERT(ds_file_group->sc->default_clock_class);
+               default_cc = ds_file_group->sc->default_clock_class;
+
+               /*
+                * 1. Iterate over the index, starting from the second entry
+                * (index = 1).
+                */
+               for (entry_i = 1; entry_i < index->entries->len;
+                               entry_i++) {
+                       struct ctf_fs_ds_index_entry *curr_entry, *prev_entry;
+                       prev_entry = g_ptr_array_index(index->entries, entry_i - 1);
+                       curr_entry = g_ptr_array_index(index->entries, entry_i);
+                       /*
+                        * 2. Set the current entry `begin` timestamp to the
+                        * timestamp of the first event of the current packet.
+                        */
+                       ret = decode_packet_first_event_timestamp(trace, default_cc,
+                               curr_entry, &curr_entry->timestamp_begin,
+                               &curr_entry->timestamp_begin_ns);
+                       if (ret) {
+                               BT_LOGE_STR("Failed to decode first event's clock snapshot");
+                               goto end;
+                       }
+
+                       /*
+                        * 3. Set the previous entry `end` timestamp to the
+                        * timestamp of the first event of the current packet.
+                        */
+                       prev_entry->timestamp_end = curr_entry->timestamp_begin;
+                       prev_entry->timestamp_end_ns = curr_entry->timestamp_begin_ns;
+               }
+       }
+end:
+       return ret;
+}
+
+/*
+ * When using the lttng-crash feature it's likely that the last packets of each
+ * stream have their timestamp_end set to zero. This is caused by the fact that
+ * the tracer crashed and was not able to properly close the packets.
+ *
+ * To fix up this erroneous data we do the following:
+ * For each index entry, if the entry's timestamp_end is 0 and the
+ * timestamp_begin is not 0:
+ *  - If it's the stream file's last packet: set the packet index entry's end
+ *    time to the packet's last event's time, if any, or to the packet's
+ *    beginning time otherwise.
+ *  - If it's not the stream file's last packet: set the packet index
+ *    entry's end time to the next packet's beginning time.
+ *
+ * Affected versions:
+ * - All current and future lttng-ust and lttng-modules versions.
+ */
+static
+int fix_index_lttng_crash_quirk(struct ctf_fs_trace *trace)
+{
+       int ret = 0;
+       guint ds_file_group_idx;
+       GPtrArray *ds_file_groups = trace->ds_file_groups;
+       bt_logging_level log_level = trace->log_level;
+
+       for (ds_file_group_idx = 0; ds_file_group_idx < ds_file_groups->len;
+                       ds_file_group_idx++) {
+               guint entry_idx;
+               struct ctf_clock_class *default_cc;
+               struct ctf_fs_ds_index_entry *last_entry;
+               struct ctf_fs_ds_index *index;
+
+               struct ctf_fs_ds_file_group *ds_file_group =
+                       g_ptr_array_index(ds_file_groups, ds_file_group_idx);
+
+               BT_ASSERT(ds_file_group);
+               index = ds_file_group->index;
+
+               BT_ASSERT(ds_file_group->sc->default_clock_class);
+               default_cc = ds_file_group->sc->default_clock_class;
+
+               BT_ASSERT(index);
+               BT_ASSERT(index->entries);
+               BT_ASSERT(index->entries->len > 0);
+
+               last_entry = g_ptr_array_index(index->entries,
+                       index->entries->len - 1);
+               BT_ASSERT(last_entry);
+
+
+               /* 1. Fix the last entry first. */
+               if (last_entry->timestamp_end == 0 &&
+                               last_entry->timestamp_begin != 0) {
+                       /*
+                        * Decode packet to read the timestamp of the
+                        * last event of the stream file.
+                        */
+                       ret = decode_packet_last_event_timestamp(trace,
+                               default_cc, last_entry,
+                               &last_entry->timestamp_end,
+                               &last_entry->timestamp_end_ns);
+                       if (ret) {
+                               BT_LOGE_STR("Failed to decode last event's clock snapshot");
+                               goto end;
+                       }
+               }
+
+               /* Iterate over all entries but the last one. */
+               for (entry_idx = 0; entry_idx < index->entries->len - 1;
+                               entry_idx++) {
+                       struct ctf_fs_ds_index_entry *curr_entry, *next_entry;
+                       curr_entry = g_ptr_array_index(index->entries, entry_idx);
+                       next_entry = g_ptr_array_index(index->entries, entry_idx + 1);
+
+                       if (curr_entry->timestamp_end == 0 &&
+                                       curr_entry->timestamp_begin != 0) {
+                               /*
+                                * 2. Set the current index entry `end` timestamp to
+                                * the next index entry `begin` timestamp.
+                                */
+                               curr_entry->timestamp_end = next_entry->timestamp_begin;
+                               curr_entry->timestamp_end_ns = next_entry->timestamp_begin_ns;
+                       }
+               }
+       }
+
+end:
+       return ret;
+}
+
 /*
  * Extract the tracer information necessary to compare versions.
  * Returns 0 on success, and -1 if the extraction is not successful because the
@@ -1982,6 +2151,46 @@ bool is_tracer_affected_by_lttng_event_after_packet_bug(
        return is_affected;
 }
 
+static
+bool is_tracer_affected_by_barectf_event_before_packet_bug(
+               struct tracer_info *curr_tracer_info)
+{
+       bool is_affected = false;
+
+       if (strcmp(curr_tracer_info->name, "barectf") == 0) {
+               if (curr_tracer_info->major < 2) {
+                       is_affected = true;
+               } else if (curr_tracer_info->major == 2) {
+                       if (curr_tracer_info->minor < 3) {
+                               is_affected = true;
+                       } else if (curr_tracer_info->minor == 3) {
+                               /* fixed in barectf 2.3.1 */
+                               if (curr_tracer_info->patch < 1) {
+                                       is_affected = true;
+                               }
+                       }
+               }
+       }
+
+       return is_affected;
+}
+
+static
+bool is_tracer_affected_by_lttng_crash_quirk(
+               struct tracer_info *curr_tracer_info)
+{
+       bool is_affected = false;
+
+       /* All LTTng tracer may be affected by this lttng crash quirk. */
+       if (strcmp(curr_tracer_info->name, "lttng-ust") == 0) {
+               is_affected = true;
+       } else if (strcmp(curr_tracer_info->name, "lttng-modules") == 0) {
+               is_affected = true;
+       }
+
+       return is_affected;
+}
+
 /*
  * Looks for trace produced by known buggy tracers and fix up the index
  * produced earlier.
@@ -2026,6 +2235,28 @@ int fix_packet_index_tracer_bugs(struct ctf_fs_component *ctf_fs)
                                BT_LOGE_STR("Failed to fix LTTng event-after-packet bug.");
                                goto end;
                        }
+                       trace->metadata->tc->quirks.lttng_event_after_packet = true;
+               }
+
+               if (is_tracer_affected_by_barectf_event_before_packet_bug(
+                               &current_tracer_info)) {
+                       BT_LOGI_STR("Trace may be affected by barectf tracer packet timestamp bug. Fixing up.");
+                       ret = fix_index_barectf_event_before_packet_bug(trace);
+                       if (ret) {
+                               BT_LOGE_STR("Failed to fix barectf event-before-packet bug.");
+                               goto end;
+                       }
+                       trace->metadata->tc->quirks.barectf_event_before_packet = true;
+               }
+
+               if (is_tracer_affected_by_lttng_crash_quirk(
+                               &current_tracer_info)) {
+                       ret = fix_index_lttng_crash_quirk(trace);
+                       if (ret) {
+                               BT_LOGE_STR("Failed to fix lttng-crash timestamp quirks.");
+                               goto end;
+                       }
+                       trace->metadata->tc->quirks.lttng_crash = true;
                }
        }
 end:
This page took 0.041436 seconds and 4 git commands to generate.