From e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 22:34:10 +0200 Subject: Adding upstream version 4.2.2. Signed-off-by: Daniel Baumann --- epan/tvbuff_composite.c | 308 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 epan/tvbuff_composite.c (limited to 'epan/tvbuff_composite.c') diff --git a/epan/tvbuff_composite.c b/epan/tvbuff_composite.c new file mode 100644 index 00000000..620b8d27 --- /dev/null +++ b/epan/tvbuff_composite.c @@ -0,0 +1,308 @@ +/* tvbuff_composite.c + * + * Copyright (c) 2000 by Gilbert Ramirez + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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: + */ -- cgit v1.2.3