3 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "tvbuff-int.h"
16 #include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
21 /* Used for quick testing to see if this
22 * is the tvbuff that a COMPOSITE is
24 unsigned *start_offsets
;
25 unsigned *end_offsets
;
29 struct tvb_composite
{
36 composite_free(tvbuff_t
*tvb
)
38 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
39 tvb_comp_t
*composite
= &composite_tvb
->composite
;
41 g_queue_free(composite
->tvbs
);
43 g_free(composite
->start_offsets
);
44 g_free(composite
->end_offsets
);
45 g_free((void *)tvb
->real_data
);
49 composite_offset(const tvbuff_t
*tvb _U_
, const unsigned counter
)
55 composite_get_ptr(tvbuff_t
*tvb
, unsigned abs_offset
, unsigned abs_length
)
57 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
59 tvb_comp_t
*composite
;
60 tvbuff_t
*member_tvb
= NULL
;
61 unsigned member_offset
;
63 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
65 /* Maybe the range specified by offset/length
66 * is contiguous inside one of the member tvbuffs */
67 composite
= &composite_tvb
->composite
;
68 GList
*item
= (GList
*)composite
->tvbs
->head
;
71 for (i
= 0; i
< g_queue_get_length(composite
->tvbs
); i
++, item
=item
->next
) {
72 if (abs_offset
<= composite
->end_offsets
[i
]) {
73 member_tvb
= (tvbuff_t
*)item
->data
;
80 DISSECTOR_ASSERT(abs_offset
== tvb
->length
&& abs_length
== 0);
84 member_offset
= abs_offset
- composite
->start_offsets
[i
];
86 if (tvb_bytes_exist(member_tvb
, member_offset
, abs_length
)) {
88 * The range is, in fact, contiguous within member_tvb.
90 DISSECTOR_ASSERT(!tvb
->real_data
);
91 return tvb_get_ptr(member_tvb
, member_offset
, abs_length
);
94 /* Use a temporary variable as tvb_memcpy is also checking tvb->real_data pointer */
95 void *real_data
= g_malloc(tvb
->length
);
96 tvb_memcpy(tvb
, real_data
, 0, tvb
->length
);
97 tvb
->real_data
= (const uint8_t *)real_data
;
98 return tvb
->real_data
+ abs_offset
;
101 DISSECTOR_ASSERT_NOT_REACHED();
105 composite_memcpy(tvbuff_t
*tvb
, void* _target
, unsigned abs_offset
, unsigned abs_length
)
107 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
108 uint8_t *target
= (uint8_t *) _target
;
111 tvb_comp_t
*composite
;
112 tvbuff_t
*member_tvb
= NULL
;
113 unsigned member_offset
, member_length
;
115 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
117 /* Maybe the range specified by offset/length
118 * is contiguous inside one of the member tvbuffs */
119 composite
= &composite_tvb
->composite
;
121 GList
*item
= (GList
*)composite
->tvbs
->head
;
122 for (i
= 0; i
< g_queue_get_length(composite
->tvbs
); i
++, item
=item
->next
) {
123 if (abs_offset
<= composite
->end_offsets
[i
]) {
124 member_tvb
= (tvbuff_t
*)item
->data
;
131 DISSECTOR_ASSERT(abs_offset
== tvb
->length
&& abs_length
== 0);
135 member_offset
= abs_offset
- composite
->start_offsets
[i
];
137 if (tvb_bytes_exist(member_tvb
, member_offset
, abs_length
)) {
138 DISSECTOR_ASSERT(!tvb
->real_data
);
139 return tvb_memcpy(member_tvb
, target
, member_offset
, abs_length
);
142 /* The requested data is non-contiguous inside
143 * the member tvb. We have to memcpy() the part that's in the member tvb,
144 * then iterate across the other member tvb's, copying their portions
145 * until we have copied all data.
147 member_length
= tvb_captured_length_remaining(member_tvb
, member_offset
);
149 /* composite_memcpy() can't handle a member_length of zero. */
150 DISSECTOR_ASSERT(member_length
> 0);
152 tvb_memcpy(member_tvb
, target
, member_offset
, member_length
);
153 abs_offset
+= member_length
;
154 abs_length
-= member_length
;
157 if (abs_length
> 0) {
158 composite_memcpy(tvb
, target
+ member_length
, abs_offset
, abs_length
);
164 DISSECTOR_ASSERT_NOT_REACHED();
167 static const struct tvb_ops tvb_composite_ops
= {
168 sizeof(struct tvb_composite
), /* size */
170 composite_free
, /* free */
171 composite_offset
, /* offset */
172 composite_get_ptr
, /* get_ptr */
173 composite_memcpy
, /* memcpy */
174 NULL
, /* find_uint8 XXX */
175 NULL
, /* pbrk_uint8 XXX */
182 * A composite TVB references the concatenation of one or more TVBs, each of
183 * them MUST be part of the same chain (the same memory "scope"). The
184 * caller of tvb_new_composite MUST immediately call tvb_composite_append or
185 * tvb_composite_prepend to ensure that the composite TVB is properly freed as
188 * Failure to satisfy the same chain requirement can result in memory-safety
189 * issues such as use-after-free or double-free.
192 tvb_new_composite(void)
194 tvbuff_t
*tvb
= tvb_new(&tvb_composite_ops
);
195 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
196 tvb_comp_t
*composite
= &composite_tvb
->composite
;
198 composite
->tvbs
= g_queue_new();
199 composite
->start_offsets
= NULL
;
200 composite
->end_offsets
= NULL
;
206 tvb_composite_append(tvbuff_t
*tvb
, tvbuff_t
*member
)
208 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
209 tvb_comp_t
*composite
;
211 DISSECTOR_ASSERT(tvb
&& !tvb
->initialized
);
212 DISSECTOR_ASSERT(tvb
->ops
== &tvb_composite_ops
);
214 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
215 * and anyway it makes no sense.
217 if (member
&& member
->length
) {
218 composite
= &composite_tvb
->composite
;
219 g_queue_push_tail(composite
->tvbs
, member
);
221 /* Attach the composite TVB to the first TVB only. */
222 if (g_queue_get_length(composite
->tvbs
) == 1) {
223 tvb_add_to_chain((tvbuff_t
*)g_queue_peek_head(composite
->tvbs
), tvb
);
229 tvb_composite_prepend(tvbuff_t
*tvb
, tvbuff_t
*member
)
231 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
232 tvb_comp_t
*composite
;
234 DISSECTOR_ASSERT(tvb
&& !tvb
->initialized
);
235 DISSECTOR_ASSERT(tvb
->ops
== &tvb_composite_ops
);
237 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
238 * and anyway it makes no sense.
240 if (member
&& member
->length
) {
241 composite
= &composite_tvb
->composite
;
242 g_queue_push_head(composite
->tvbs
, member
);
244 /* Attach the composite TVB to the first TVB only. */
245 if (g_queue_get_length(composite
->tvbs
) == 1) {
246 tvb_add_to_chain((tvbuff_t
*)g_queue_peek_head(composite
->tvbs
), tvb
);
252 tvb_composite_finalize(tvbuff_t
*tvb
)
254 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
256 unsigned num_members
;
257 tvbuff_t
*member_tvb
;
258 tvb_comp_t
*composite
;
261 DISSECTOR_ASSERT(tvb
&& !tvb
->initialized
);
262 DISSECTOR_ASSERT(tvb
->ops
== &tvb_composite_ops
);
263 DISSECTOR_ASSERT(tvb
->length
== 0);
264 DISSECTOR_ASSERT(tvb
->reported_length
== 0);
265 DISSECTOR_ASSERT(tvb
->contained_length
== 0);
267 composite
= &composite_tvb
->composite
;
269 num_members
= g_queue_get_length(composite
->tvbs
);
271 /* Dissectors should not create composite TVBs if they're not going to
272 * put at least one TVB in them.
273 * (Without this check--or something similar--we'll seg-fault below.)
275 DISSECTOR_ASSERT(num_members
);
277 composite
->start_offsets
= g_new(unsigned, num_members
);
278 composite
->end_offsets
= g_new(unsigned, num_members
);
280 GList
*item
= (GList
*)composite
->tvbs
->head
;
281 for (i
=0; i
< num_members
; i
++, item
=item
->next
) {
282 member_tvb
= (tvbuff_t
*)item
->data
;
283 composite
->start_offsets
[i
] = tvb
->length
;
284 tvb
->length
+= member_tvb
->length
;
285 tvb
->reported_length
+= member_tvb
->reported_length
;
286 tvb
->contained_length
+= member_tvb
->contained_length
;
287 composite
->end_offsets
[i
] = tvb
->length
- 1;
290 tvb
->initialized
= true;
295 * Editor modelines - https://www.wireshark.org/tools/modelines.html
300 * indent-tabs-mode: t
303 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
304 * :indentSize=8:tabSize=8:noTabs=false: