summaryrefslogtreecommitdiffstats
path: root/epan/tvbuff_composite.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/tvbuff_composite.c
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/tvbuff_composite.c')
-rw-r--r--epan/tvbuff_composite.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/epan/tvbuff_composite.c b/epan/tvbuff_composite.c
new file mode 100644
index 0000000..620b8d2
--- /dev/null
+++ b/epan/tvbuff_composite.c
@@ -0,0 +1,308 @@
+/* tvbuff_composite.c
+ *
+ * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include "tvbuff.h"
+#include "tvbuff-int.h"
+#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
+
+typedef struct {
+ GSList *tvbs;
+
+ /* Used for quick testing to see if this
+ * is the tvbuff that a COMPOSITE is
+ * interested in. */
+ guint *start_offsets;
+ guint *end_offsets;
+
+} tvb_comp_t;
+
+struct tvb_composite {
+ struct tvbuff tvb;
+
+ tvb_comp_t composite;
+};
+
+static void
+composite_free(tvbuff_t *tvb)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite = &composite_tvb->composite;
+
+ g_slist_free(composite->tvbs);
+
+ g_free(composite->start_offsets);
+ g_free(composite->end_offsets);
+ g_free((gpointer)tvb->real_data);
+}
+
+static guint
+composite_offset(const tvbuff_t *tvb _U_, const guint counter)
+{
+ return counter;
+}
+
+static const guint8*
+composite_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ guint i, num_members;
+ tvb_comp_t *composite;
+ tvbuff_t *member_tvb = NULL;
+ guint member_offset;
+ GSList *slist;
+
+ /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
+
+ /* Maybe the range specified by offset/length
+ * is contiguous inside one of the member tvbuffs */
+ composite = &composite_tvb->composite;
+ num_members = g_slist_length(composite->tvbs);
+
+ for (i = 0; i < num_members; i++) {
+ if (abs_offset <= composite->end_offsets[i]) {
+ slist = g_slist_nth(composite->tvbs, i);
+ member_tvb = (tvbuff_t *)slist->data;
+ break;
+ }
+ }
+
+ /* special case */
+ if (!member_tvb) {
+ DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
+ return "";
+ }
+
+ member_offset = abs_offset - composite->start_offsets[i];
+
+ if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
+ /*
+ * The range is, in fact, contiguous within member_tvb.
+ */
+ DISSECTOR_ASSERT(!tvb->real_data);
+ return tvb_get_ptr(member_tvb, member_offset, abs_length);
+ }
+ else {
+ /* Use a temporary variable as tvb_memcpy is also checking tvb->real_data pointer */
+ void *real_data = g_malloc(tvb->length);
+ tvb_memcpy(tvb, real_data, 0, tvb->length);
+ tvb->real_data = (const guint8 *)real_data;
+ return tvb->real_data + abs_offset;
+ }
+
+ DISSECTOR_ASSERT_NOT_REACHED();
+}
+
+static void *
+composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_length)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ guint8 *target = (guint8 *) _target;
+
+ guint i, num_members;
+ tvb_comp_t *composite;
+ tvbuff_t *member_tvb = NULL;
+ guint member_offset, member_length;
+ GSList *slist;
+
+ /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
+
+ /* Maybe the range specified by offset/length
+ * is contiguous inside one of the member tvbuffs */
+ composite = &composite_tvb->composite;
+ num_members = g_slist_length(composite->tvbs);
+
+ for (i = 0; i < num_members; i++) {
+ if (abs_offset <= composite->end_offsets[i]) {
+ slist = g_slist_nth(composite->tvbs, i);
+ member_tvb = (tvbuff_t *)slist->data;
+ break;
+ }
+ }
+
+ /* special case */
+ if (!member_tvb) {
+ DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
+ return target;
+ }
+
+ member_offset = abs_offset - composite->start_offsets[i];
+
+ if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
+ DISSECTOR_ASSERT(!tvb->real_data);
+ return tvb_memcpy(member_tvb, target, member_offset, abs_length);
+ }
+ else {
+ /* The requested data is non-contiguous inside
+ * the member tvb. We have to memcpy() the part that's in the member tvb,
+ * then iterate across the other member tvb's, copying their portions
+ * until we have copied all data.
+ */
+ member_length = tvb_captured_length_remaining(member_tvb, member_offset);
+
+ /* composite_memcpy() can't handle a member_length of zero. */
+ DISSECTOR_ASSERT(member_length > 0);
+
+ tvb_memcpy(member_tvb, target, member_offset, member_length);
+ abs_offset += member_length;
+ abs_length -= member_length;
+
+ /* Recurse */
+ if (abs_length > 0) {
+ composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
+ }
+
+ return target;
+ }
+
+ DISSECTOR_ASSERT_NOT_REACHED();
+}
+
+static const struct tvb_ops tvb_composite_ops = {
+ sizeof(struct tvb_composite), /* size */
+
+ composite_free, /* free */
+ composite_offset, /* offset */
+ composite_get_ptr, /* get_ptr */
+ composite_memcpy, /* memcpy */
+ NULL, /* find_guint8 XXX */
+ NULL, /* pbrk_guint8 XXX */
+ NULL, /* clone */
+};
+
+/*
+ * Composite tvb
+ *
+ * A composite TVB references the concatenation of one or more TVBs, each of
+ * them MUST be part of the same chain (the same memory "scope"). The
+ * caller of tvb_new_composite MUST immediately call tvb_composite_append or
+ * tvb_composite_prepend to ensure that the composite TVB is properly freed as
+ * needed.
+ *
+ * Failure to satisfy the same chain requirement can result in memory-safety
+ * issues such as use-after-free or double-free.
+ */
+tvbuff_t *
+tvb_new_composite(void)
+{
+ tvbuff_t *tvb = tvb_new(&tvb_composite_ops);
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite = &composite_tvb->composite;
+
+ composite->tvbs = NULL;
+ composite->start_offsets = NULL;
+ composite->end_offsets = NULL;
+
+ return tvb;
+}
+
+void
+tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite;
+
+ DISSECTOR_ASSERT(tvb && !tvb->initialized);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
+
+ /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
+ * and anyway it makes no sense.
+ */
+ if (member && member->length) {
+ composite = &composite_tvb->composite;
+ composite->tvbs = g_slist_append(composite->tvbs, member);
+
+ /* Attach the composite TVB to the first TVB only. */
+ if (!composite->tvbs->next) {
+ tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb);
+ }
+ }
+}
+
+void
+tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite;
+
+ DISSECTOR_ASSERT(tvb && !tvb->initialized);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
+
+ /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
+ * and anyway it makes no sense.
+ */
+ if (member && member->length) {
+ composite = &composite_tvb->composite;
+ composite->tvbs = g_slist_prepend(composite->tvbs, member);
+
+ /* Attach the composite TVB to the first TVB only. */
+ if (!composite->tvbs->next) {
+ tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb);
+ }
+ }
+}
+
+void
+tvb_composite_finalize(tvbuff_t *tvb)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ GSList *slist;
+ guint num_members;
+ tvbuff_t *member_tvb;
+ tvb_comp_t *composite;
+ int i = 0;
+
+ DISSECTOR_ASSERT(tvb && !tvb->initialized);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
+ DISSECTOR_ASSERT(tvb->length == 0);
+ DISSECTOR_ASSERT(tvb->reported_length == 0);
+ DISSECTOR_ASSERT(tvb->contained_length == 0);
+
+ composite = &composite_tvb->composite;
+ num_members = g_slist_length(composite->tvbs);
+
+ /* Dissectors should not create composite TVBs if they're not going to
+ * put at least one TVB in them.
+ * (Without this check--or something similar--we'll seg-fault below.)
+ */
+ DISSECTOR_ASSERT(num_members);
+
+ composite->start_offsets = g_new(guint, num_members);
+ composite->end_offsets = g_new(guint, num_members);
+
+ for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
+ DISSECTOR_ASSERT((guint) i < num_members);
+ member_tvb = (tvbuff_t *)slist->data;
+ composite->start_offsets[i] = tvb->length;
+ tvb->length += member_tvb->length;
+ tvb->reported_length += member_tvb->reported_length;
+ tvb->contained_length += member_tvb->contained_length;
+ composite->end_offsets[i] = tvb->length - 1;
+ i++;
+ }
+
+ tvb->initialized = TRUE;
+ tvb->ds_tvb = tvb;
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */