From dcd891a02e11dc13417800042d5272777fca0e97 Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Fri, 17 Apr 2026 18:21:36 +0200
Subject: [PATCH 3/8] buffers: add more checks to DTLS reassembly

Previously, gnutls didn't check that DTLS fragments claimed
a consistent message_length value.
Additionally, a crucial array size check was missing,
enabling an attacker to cause a heap overwrite.
The updated version rejects fragments with mismatching length
and adds a missing boundary check.

Reported-by: Haruto Kimura (Stella)
Reported-by: Oscar Reparaz
Reported-by: Zou Dikai
Fixes: #1816
Fixes: #1838
Fixes: #1839
Fixes: CVE-2026-33846
Fixes: GNUTLS-SA-2026-04-29-1
CVSS: 7.4 High CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:H
CVSS: 7.5 High CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>

Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/65ab33fa54e34fba69d793735b7df3d383d1ff78]
CVE: CVE-2026-33846
Signed-off-by: Pritam Srichandan Sahoo <PritamSrichandan.Sahoo@windriver.com>
---
 lib/buffers.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/lib/buffers.c b/lib/buffers.c
index d54c77022..5d4d16276 100644
--- a/lib/buffers.c
+++ b/lib/buffers.c
@@ -1010,6 +1010,26 @@ static int merge_handshake_packet(gnutls_session_t session,
 		_gnutls_handshake_buffer_move(&recv_buf[pos], hsk);
 
 	} else {
+		if (hsk->length != recv_buf[pos].length) {
+			/* inconsistent across fragments */
+			_gnutls_handshake_buffer_clear(hsk);
+			return gnutls_assert_val(
+				GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+		}
+		/* start_offset + data.length <= hsk->length <= max_length */
+		if (hsk->length < hsk->start_offset + hsk->data.length) {
+			/* impossible claims, overflow requested */
+			_gnutls_handshake_buffer_clear(hsk);
+			return gnutls_assert_val(
+				GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+		}
+		if (hsk->length > recv_buf[pos].data.max_length) {
+			/* we don't have this much allocated, overflow guard */
+			_gnutls_handshake_buffer_clear(hsk);
+			return gnutls_assert_val(
+				GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+		}
+
 		if (hsk->start_offset < recv_buf[pos].start_offset &&
 		    hsk->end_offset + 1 >= recv_buf[pos].start_offset) {
 			memcpy(&recv_buf[pos].data.data[hsk->start_offset],
-- 
2.53.0

