wireshark: Fix multiple CVEs

Backport fixes for :

* CVE-2024-8645  - Upstream-Status: Backport from https://gitlab.com/wireshark/wireshark/-/commit/8e5f8de8836d3a81276ae5b9bf78cbac58bb6108
* CVE-2026-0960  - Upstream-Status: Backport from https://gitlab.com/wireshark/wireshark/-/commit/f31123dcdbac37272046b58b2f7941bc7fb42934
* CVE-2025-13945 - Upstream-Status: Backport from https://gitlab.com/wireshark/wireshark/-/commit/9139917bd8e2c80a5db7079993d5528db74e3519

Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
This commit is contained in:
Hitendra Prajapati
2026-02-17 10:40:29 +05:30
committed by Gyorgy Sarvari
parent 8a598a2bc9
commit 42774277a4
4 changed files with 473 additions and 0 deletions
@@ -0,0 +1,88 @@
From 15c4d1f9078b484cb95ef645a7d4dc68212849f7 Mon Sep 17 00:00:00 2001
From: John Thacker <johnthacker@gmail.com>
Date: Wed, 29 May 2024 14:23:04 +0000
Subject: SPRT: Fix crash
SDP can setup a RTP conversation with a setup frame before the current
frame, which changes the dissection on the second pass. If in the period
in the middle there is a SPRT packet, it can be dissected differently on
the second pass, and the SPRT conversation data won't be found on the
second pass.
Fix #19559 (at least prevent the crash. There's some more cleanup that
should happen.)
(cherry picked from commit 05f6364cbd766e8758f98c5ee2070aef27c1ffef)
CVE: CVE-2024-8645
Upstream-Status: Backport [https://gitlab.com/wireshark/wireshark/-/commit/8e5f8de8836d3a81276ae5b9bf78cbac58bb6108]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
epan/dissectors/packet-rtp.c | 3 +++
epan/dissectors/packet-sprt.c | 29 +++++++++++++++++------------
2 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/epan/dissectors/packet-rtp.c b/epan/dissectors/packet-rtp.c
index e96d994..ed4a78a 100644
--- a/epan/dissectors/packet-rtp.c
+++ b/epan/dissectors/packet-rtp.c
@@ -1092,6 +1092,9 @@ srtp_add_address(packet_info *pinfo, const port_type ptype, address *addr, int p
* If not, create a new conversation.
*/
if (!p_conv || p_conv->setup_frame != setup_frame_number) {
+ /* XXX - If setup_frame_number < pinfo->num, creating this conversation
+ * can mean that the dissection is different on later passes.
+ */
p_conv = conversation_new(setup_frame_number, addr, &null_addr, conversation_pt_to_endpoint_type(ptype),
(guint32)port, (guint32)other_port,
NO_ADDR2 | (!other_port ? NO_PORT2 : 0));
diff --git a/epan/dissectors/packet-sprt.c b/epan/dissectors/packet-sprt.c
index 17bf329..726cbf0 100644
--- a/epan/dissectors/packet-sprt.c
+++ b/epan/dissectors/packet-sprt.c
@@ -1341,6 +1341,23 @@ dissect_sprt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
/*guint16 tcn;*/
/*guint16 sqn;*/
+ /* Get conversation data, or create it if not found */
+ p_conv_data = find_sprt_conversation_data(pinfo);
+ if (!p_conv_data)
+ {
+ sprt_add_address(pinfo,
+ &pinfo->src, pinfo->srcport,
+ 0,
+ "SPRT stream",
+ pinfo->num);
+ p_conv_data = find_sprt_conversation_data(pinfo);
+ if (!p_conv_data) {
+ // This shouldn't happen; likely a new RTP conversation was set up
+ // after this frame but with a setup frame before this one.
+ return 0;
+ }
+ }
+
/* Make entries in Protocol column and Info column on summary display */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPRT");
col_clear(pinfo->cinfo, COL_INFO);
@@ -1395,18 +1412,6 @@ dissect_sprt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_
noa = (tvb_get_ntohs(tvb, offset + 4) & 0xC000) >> 14;
- /* Get conversation data, or create it if not found */
- p_conv_data = find_sprt_conversation_data(pinfo);
- if (!p_conv_data)
- {
- sprt_add_address(pinfo,
- &pinfo->src, pinfo->srcport,
- 0,
- "SPRT stream",
- pinfo->num);
- p_conv_data = find_sprt_conversation_data(pinfo);
- }
-
proto_tree_add_item(sprt_tree, hf_sprt_header_extension_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item(sprt_tree, hf_sprt_subsession_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
--
2.50.1
@@ -0,0 +1,339 @@
From: John Thacker <johnthacker@gmail.com>
Date: Fri, 14 Nov 2025 20:20:44 -0500
Subject: epan: Use a GSequence for tvb_composite and make it non-recursive
To speed up tvb_composites consisting of many child tvbuffs,
use a GSequence. This is a data structure that internally has
a balanced binary tree. It differs from GTree in that one can
do initial insertions without sorting. In our case, the ordering
at the time of tvb_composite_finalize is *the* ordering, and is
the same ordering that comparing according to the calculated
end offsets will have, so this is faster on insert than a GTree.
Like a GTree, it is much faster O(log N) vs O(N) on lookup to find
the location of the TVB with end offset greater than or equal to
the desired offset than using a GQueue.
Also, make composite_memcpy iterative instead of recursive, which
removes the current hard limit of 500 without causing stack overflow
with very large numbers of child TVBs.
The file in #20860 works fine now but there could still be limits
imposed (at least on the total number of bytes?) for a compression
bomb more similar to the file found in #12077.
(backported from commit 9139917bd8e2c80a5db7079993d5528db74e3519)
origin: https://gitlab.com/wireshark/wireshark/-/merge_requests/22318
CVE: CVE-2025-13945
Upstream-Status: Backport [https://gitlab.com/wireshark/wireshark/-/commit/9139917bd8e2c80a5db7079993d5528db74e3519]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
epan/tvbuff_composite.c | 177 ++++++++++++++++++++++++++--------------
1 file changed, 114 insertions(+), 63 deletions(-)
diff --git a/epan/tvbuff_composite.c b/epan/tvbuff_composite.c
index 3ba1999..5296fa0 100644
--- a/epan/tvbuff_composite.c
+++ b/epan/tvbuff_composite.c
@@ -16,14 +16,49 @@
#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
typedef struct {
- GSList *tvbs;
-
+ tvbuff_t *tvb;
/* Used for quick testing to see if this
* is the tvbuff that a COMPOSITE is
* interested in. */
- guint *start_offsets;
- guint *end_offsets;
+ unsigned start_offset;
+ unsigned end_offset;
+} tvb_comp_member_t;
+
+static int
+tvb_comp_off_compare(const void *a, const void *b, void *user_data)
+{
+ tvb_comp_member_t* off_a = (tvb_comp_member_t*)a;
+ tvb_comp_member_t* off_b = (tvb_comp_member_t*)b;
+ tvb_comp_member_t* key = (tvb_comp_member_t*)user_data;
+
+ if (off_a->end_offset < off_b->end_offset)
+ return -1;
+ else if (off_a->end_offset > off_b->end_offset)
+ return 1;
+
+ /* This is a hack to ensure that in cases of ties, key is always
+ * sorted first. This ensures that g_sequence_search returns an
+ * iterator pointing to the tvb in the sequence with a matching
+ * offset instead of the node after it. (It would be simpler but
+ * somewhat slower to have the natural comparison function and
+ * call g_sequence_lookup followed by g_sequence_search in case
+ * of failure.)
+ *
+ * If we allowed zero length TVBs to be part of the composite,
+ * we might have to search through all the TVBs with the same
+ * end_offset to find the right one. (Or maybe we could just
+ * no-op and not add the zero length TVBs?)
+ */
+ if (off_a == key) {
+ return -1;
+ } else if (off_b == key) {
+ return 1;
+ }
+ return 0;
+}
+typedef struct {
+ GSequence *tvbs;
} tvb_comp_t;
struct tvb_composite {
@@ -38,11 +73,9 @@ 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_sequence_free(composite->tvbs);
- g_free(composite->start_offsets);
- g_free(composite->end_offsets);
- g_free((gpointer)tvb->real_data);
+ g_free((void *)tvb->real_data);
}
static guint
@@ -55,8 +88,8 @@ 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;
+ tvb_comp_member_t *member = NULL;
tvbuff_t *member_tvb = NULL;
guint member_offset;
GSList *slist;
@@ -66,23 +99,19 @@ composite_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
/* 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;
- }
- }
+ tvb_comp_member_t key = { .end_offset = abs_offset };
+ GSequenceIter *iter = g_sequence_search(composite->tvbs, &key, tvb_comp_off_compare, &key);
/* special case */
- if (!member_tvb) {
+ if (g_sequence_iter_is_end(iter)) {
DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
return "";
}
- member_offset = abs_offset - composite->start_offsets[i];
+ member = (tvb_comp_member_t *)g_sequence_get(iter);
+ member_tvb = member->tvb;
+ member_offset = abs_offset - member->start_offset;
if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
/*
@@ -108,8 +137,8 @@ composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_lengt
struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
guint8 *target = (guint8 *) _target;
- guint i, num_members;
tvb_comp_t *composite;
+ tvb_comp_member_t *member = NULL;
tvbuff_t *member_tvb = NULL;
guint member_offset, member_length;
GSList *slist;
@@ -119,23 +148,18 @@ composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_lengt
/* 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;
- }
- }
+ tvb_comp_member_t key = { .end_offset = abs_offset };
+ GSequenceIter *iter = g_sequence_search(composite->tvbs, &key, tvb_comp_off_compare, &key);
/* special case */
- if (!member_tvb) {
+ if (g_sequence_iter_is_end(iter)) {
DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
return target;
}
- member_offset = abs_offset - composite->start_offsets[i];
+ member = (tvb_comp_member_t *)g_sequence_get(iter);
+ member_tvb = member->tvb;
+ member_offset = abs_offset - member->start_offset;
if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
DISSECTOR_ASSERT(!tvb->real_data);
@@ -147,18 +171,32 @@ composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_lengt
* 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);
+ unsigned target_offset = 0;
+ while (abs_length) {
- tvb_memcpy(member_tvb, target, member_offset, member_length);
- abs_offset += member_length;
- abs_length -= member_length;
+ member_length = tvb_captured_length_remaining(member_tvb, member_offset);
- /* Recurse */
- if (abs_length > 0) {
- composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
+ /* composite_memcpy() can't handle a member_length of zero. */
+ DISSECTOR_ASSERT(member_length > 0);
+
+ member_length = MIN(member_length, abs_length);
+
+ tvb_memcpy(member_tvb, target + target_offset, member_offset, member_length);
+ target_offset += member_length;
+ abs_offset += member_length;
+ abs_length -= member_length;
+
+ if (!abs_length)
+ break;
+ iter = g_sequence_iter_next(iter);
+ /* tvb_memcpy calls check_offset_length and so there
+ * should be enough captured length to copy. */
+ DISSECTOR_ASSERT(!g_sequence_iter_is_end(iter));
+
+ member = (tvb_comp_member_t *)g_sequence_get(iter);
+ member_tvb = member->tvb;
+ member_offset = 0;
}
return target;
@@ -198,9 +236,7 @@ tvb_new_composite(void)
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;
+ composite->tvbs = g_sequence_new(g_free);
return tvb;
}
@@ -220,12 +256,15 @@ tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
DISSECTOR_ASSERT(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);
+ if (g_sequence_is_empty(composite->tvbs)) {
+ tvb_add_to_chain(member, tvb);
}
+ tvb_comp_member_t *new_member = g_new(tvb_comp_member_t, 1);
+ new_member->tvb = member;
+ new_member->start_offset = 0;
+ new_member->end_offset = 0;
+ g_sequence_append(composite->tvbs, new_member);
}
void
@@ -243,20 +282,24 @@ tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
DISSECTOR_ASSERT(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);
+ if (g_sequence_is_empty(composite->tvbs)) {
+ tvb_add_to_chain(member, tvb);
}
+ tvb_comp_member_t *new_member = g_new(tvb_comp_member_t, 1);
+ new_member->tvb = member;
+ new_member->start_offset = 0;
+ new_member->end_offset = 0;
+ g_sequence_prepend(composite->tvbs, new_member);
}
void
tvb_composite_finalize(tvbuff_t *tvb)
{
struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
- GSList *slist;
- guint num_members;
+
+ unsigned num_members;
+ tvb_comp_member_t *member;
tvbuff_t *member_tvb;
tvb_comp_t *composite;
int i = 0;
@@ -268,26 +311,34 @@ tvb_composite_finalize(tvbuff_t *tvb)
DISSECTOR_ASSERT(tvb->contained_length == 0);
composite = &composite_tvb->composite;
- num_members = g_slist_length(composite->tvbs);
+
+ num_members = g_sequence_get_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.)
+ * (XXX - Now with a GSequence we shouldn't segfault, we'll get the
+ * end iterator and it should work, so we could remove this and some
+ * checks in dissectors to simplify their code.)
*/
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;
+ /* Record the offsets - we have to do that now because it's possible
+ * to prepend TVBs. Note that the GSequence is already sorted according
+ * to these offsets, we're just noting them, so we don't need to sort.
+ */
+ GSequenceIter *iter = g_sequence_get_begin_iter(composite->tvbs);
+ for (i=0; i < num_members; i++, iter=g_sequence_iter_next(iter)) {
+ member = (tvb_comp_member_t *)g_sequence_get(iter);
+ member_tvb = member->tvb;
+ member->start_offset = tvb->length;
tvb->length += member_tvb->length;
+ /* XXX - What does it mean to make a composite TVB out of
+ * TVBs with length shorter than their reported length?
+ */
tvb->reported_length += member_tvb->reported_length;
tvb->contained_length += member_tvb->contained_length;
- composite->end_offsets[i] = tvb->length - 1;
- i++;
+ member->end_offset = tvb->length - 1;
}
tvb->initialized = TRUE;
--
2.50.1
@@ -0,0 +1,43 @@
From: John Thacker <johnthacker@gmail.com>
Date: Mon, 12 Jan 2026 15:28:22 +0000
Subject: QUIC: Update reassembly ID for a new MSP
When a QUIC frame has more than one MSP, the reassembly id for the
second MSP has to be used when adding or looking it up, instead of
the original reassembly id of the first MSP.
Fixes reassembly of the file in #20944 in most cases, outside of issues
with out of order UDP packets / QUIC packets.
(cherry picked from commit 562c3c070c6f58d01904d42338489b1a64ad7655)
Co-authored-by: John Thacker <johnthacker@gmail.com>
origin: https://gitlab.com/wireshark/wireshark/-/merge_requests/23175
CVE: CVE-2026-0960
Upstream-Status: Backport [https://gitlab.com/wireshark/wireshark/-/commit/f31123dcdbac37272046b58b2f7941bc7fb42934]
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
epan/dissectors/packet-quic.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/epan/dissectors/packet-quic.c b/epan/dissectors/packet-quic.c
index 53f5e1c..83ba9c3 100644
--- a/epan/dissectors/packet-quic.c
+++ b/epan/dissectors/packet-quic.c
@@ -1472,9 +1472,10 @@ again:
deseg_seq, nxtseq+pinfo->desegment_len, stream->multisegment_pdus);
}
- /* add this segment as the first one for this new pdu */
+ /* add this segment as the first one for this new pdu
+ * Use the the new MSP's reassembly ID (its first frame). */
fragment_add(&quic_reassembly_table, tvb, deseg_offset,
- pinfo, reassembly_id, NULL,
+ pinfo, msp->first_frame, stream_info,
0, nxtseq - deseg_seq,
nxtseq < msp->nxtpdu);
}
--
2.50.1
@@ -32,6 +32,9 @@ SRC_URI += " \
file://CVE-2024-2955.patch \
file://CVE-2025-13499.patch \
file://CVE-2025-11626.patch \
file://CVE-2024-8645.patch \
file://CVE-2026-0960.patch \
file://CVE-2025-13945.patch \
"
UPSTREAM_CHECK_URI = "https://1.as.dl.wireshark.org/src"