diff mbox series

[scarthgap,2/7] gnutls: Fix CVE-2026-33845

Message ID 20260520081403.3052797-2-hsimeliere.opensource@witekio.com
State New
Headers show
Series [scarthgap,1/7] gnutls: Fix CVE-2026-33846 | expand

Commit Message

Hugo Simeliere May 20, 2026, 8:13 a.m. UTC
From: "Hugo SIMELIERE (Schneider Electric)" <hsimeliere.opensource@witekio.com>

Pick patch from [1] as mentioned in Debian report in [2].
Pick pre-patch [3] to minimize conflicts.

[1] https://gitlab.com/gnutls/gnutls/-/commit/e5b72c53c7d789d19d1d1cd10b275e87d0415413
[2] https://security-tracker.debian.org/tracker/CVE-2026-33845
[3] https://gitlab.com/gnutls/gnutls/-/commit/bd70e112d4d1f063223f0f0886aaaf33699390d0

Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
Reviewed-by: Bruno VERNAY <bruno.vernay@se.com>
---
 .../gnutls/gnutls/CVE-2026-33845-pre.patch    |  97 ++++++++++
 .../gnutls/gnutls/CVE-2026-33845.patch        | 172 ++++++++++++++++++
 meta/recipes-support/gnutls/gnutls_3.8.4.bb   |   2 +
 3 files changed, 271 insertions(+)
 create mode 100644 meta/recipes-support/gnutls/gnutls/CVE-2026-33845-pre.patch
 create mode 100644 meta/recipes-support/gnutls/gnutls/CVE-2026-33845.patch
diff mbox series

Patch

diff --git a/meta/recipes-support/gnutls/gnutls/CVE-2026-33845-pre.patch b/meta/recipes-support/gnutls/gnutls/CVE-2026-33845-pre.patch
new file mode 100644
index 0000000000..0eaccd5ba9
--- /dev/null
+++ b/meta/recipes-support/gnutls/gnutls/CVE-2026-33845-pre.patch
@@ -0,0 +1,97 @@ 
+From f2f852f604d73f890f977bab9792fbc4c20adbcd Mon Sep 17 00:00:00 2001
+From: Alexander Sosedkin <asosedkin@redhat.com>
+Date: Wed, 22 Apr 2026 14:19:57 +0200
+Subject: [PATCH 1/2] buffers: rename a variable in parse_handshake_header
+
+CVE: CVE-2026-33845
+Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/bd70e112d4d1f063223f0f0886aaaf33699390d0]
+
+Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
+(cherry picked from commit bd70e112d4d1f063223f0f0886aaaf33699390d0)
+Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
+---
+ lib/buffers.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/lib/buffers.c b/lib/buffers.c
+index 5d4d16276..705c77f91 100644
+--- a/lib/buffers.c
++++ b/lib/buffers.c
+@@ -857,7 +857,7 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ {
+ 	uint8_t *dataptr = NULL; /* for realloc */
+ 	size_t handshake_header_size = HANDSHAKE_HEADER_SIZE(session),
+-	       data_size, frag_size;
++	       data_size, frag_length;
+ 
+ 	/* Note: SSL2_HEADERS == 1 */
+ 	if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
+@@ -872,7 +872,7 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 		handshake_header_size =
+ 			SSL2_HEADERS; /* we've already read one byte */
+ 
+-		frag_size =
++		frag_length =
+ 			_mbuffer_get_udata_size(bufel) -
+ 			handshake_header_size; /* we've read the first byte */
+ 
+@@ -883,7 +883,7 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 
+ 		hsk->sequence = 0;
+ 		hsk->start_offset = 0;
+-		hsk->length = frag_size;
++		hsk->length = frag_length;
+ 	} else
+ #endif
+ 	{ /* TLS or DTLS handshake headers */
+@@ -898,13 +898,13 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 		if (IS_DTLS(session)) {
+ 			hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
+ 			hsk->start_offset = _gnutls_read_uint24(&dataptr[6]);
+-			frag_size = _gnutls_read_uint24(&dataptr[9]);
++			frag_length = _gnutls_read_uint24(&dataptr[9]);
+ 		} else {
+ 			hsk->sequence = 0;
+ 			hsk->start_offset = 0;
+-			frag_size = MIN((_mbuffer_get_udata_size(bufel) -
+-					 handshake_header_size),
+-					hsk->length);
++			frag_length = MIN((_mbuffer_get_udata_size(bufel) -
++					   handshake_header_size),
++					  hsk->length);
+ 		}
+ 
+ 		/* TLS1.3: distinguish server hello versus hello retry request.
+@@ -923,8 +923,8 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 	}
+ 	data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
+ 
+-	if (frag_size > 0)
+-		hsk->end_offset = hsk->start_offset + frag_size - 1;
++	if (frag_length > 0)
++		hsk->end_offset = hsk->start_offset + frag_length - 1;
+ 	else
+ 		hsk->end_offset = 0;
+ 
+@@ -932,15 +932,15 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 		"HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
+ 		session, _gnutls_handshake2str(hsk->htype),
+ 		(unsigned)hsk->htype, (int)hsk->length, (int)data_size,
+-		hsk->start_offset, (int)frag_size, (int)hsk->sequence);
++		hsk->start_offset, (int)frag_length, (int)hsk->sequence);
+ 
+ 	hsk->header_size = handshake_header_size;
+ 	memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
+ 	       handshake_header_size);
+ 
+ 	if (hsk->length > 0 &&
+-	    (frag_size > data_size ||
+-	     (frag_size > 0 && hsk->end_offset >= hsk->length))) {
++	    (frag_length > data_size ||
++	     (frag_length > 0 && hsk->end_offset >= hsk->length))) {
+ 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ 	} else if (hsk->length == 0 && hsk->end_offset != 0 &&
+ 		   hsk->start_offset != 0)
+-- 
+2.43.0
+
diff --git a/meta/recipes-support/gnutls/gnutls/CVE-2026-33845.patch b/meta/recipes-support/gnutls/gnutls/CVE-2026-33845.patch
new file mode 100644
index 0000000000..d9af55d263
--- /dev/null
+++ b/meta/recipes-support/gnutls/gnutls/CVE-2026-33845.patch
@@ -0,0 +1,172 @@ 
+From a6fc5c6fbfe10acd087cd233e73c5cfefbd2762a Mon Sep 17 00:00:00 2001
+From: Alexander Sosedkin <asosedkin@redhat.com>
+Date: Mon, 23 Mar 2026 15:09:43 +0100
+Subject: [PATCH 2/2] buffers: switch from end_offset over to frag_length
+
+Instead of maintaining an inclusive [start_offset, end_offset] range
+when reassembling DTLS handshake,
+track start_offset and a relative frag_length instead.
+
+You'd think it'd be a no-op, but it fixes:
+
+* 0-length fragments triggering completion if message was 1 byte long
+* a remotely triggerable underflow and an ensuing heap overrun
+
+Reported-by: Joshua Rogers of AISLE Research Team <joshua@joshua.hu>
+Fixes: #1811
+Fixes: CVE-2026-33845
+Fixes: GNUTLS-SA-2026-04-29-3
+CVSS: 7.5 High CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
+
+CVE: CVE-2026-33845
+Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/e5b72c53c7d789d19d1d1cd10b275e87d0415413]
+
+Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
+(cherry picked from commit e5b72c53c7d789d19d1d1cd10b275e87d0415413)
+Signed-off-by: Hugo SIMELIERE (Schneider Electric) <hsimeliere.opensource@witekio.com>
+---
+ lib/buffers.c    | 51 +++++++++++++++++++++++++-----------------------
+ lib/gnutls_int.h |  4 ++--
+ 2 files changed, 29 insertions(+), 26 deletions(-)
+
+diff --git a/lib/buffers.c b/lib/buffers.c
+index 705c77f91..9075a2009 100644
+--- a/lib/buffers.c
++++ b/lib/buffers.c
+@@ -923,10 +923,7 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 	}
+ 	data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
+ 
+-	if (frag_length > 0)
+-		hsk->end_offset = hsk->start_offset + frag_length - 1;
+-	else
+-		hsk->end_offset = 0;
++	hsk->frag_length = frag_length;
+ 
+ 	_gnutls_handshake_log(
+ 		"HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
+@@ -940,9 +937,11 @@ static int parse_handshake_header(gnutls_session_t session, mbuffer_st *bufel,
+ 
+ 	if (hsk->length > 0 &&
+ 	    (frag_length > data_size ||
+-	     (frag_length > 0 && hsk->end_offset >= hsk->length))) {
++	     (frag_length > 0 &&
++	      hsk->start_offset + frag_length > hsk->length))) {
+ 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+-	} else if (hsk->length == 0 && hsk->end_offset != 0 &&
++	} else if (hsk->length == 0 &&
++		   hsk->start_offset + frag_length != hsk->start_offset &&
+ 		   hsk->start_offset != 0)
+ 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ 
+@@ -993,11 +992,10 @@ static int merge_handshake_packet(gnutls_session_t session,
+ 			hsk->data.length = hsk->length;
+ 		}
+ 
+-		if (hsk->length > 0 && hsk->end_offset > 0 &&
+-		    hsk->end_offset - hsk->start_offset + 1 != hsk->length) {
++		if (hsk->length > 0 && hsk->frag_length > 0 &&
++		    hsk->frag_length != hsk->length) {
+ 			memmove(&hsk->data.data[hsk->start_offset],
+-				hsk->data.data,
+-				hsk->end_offset - hsk->start_offset + 1);
++				hsk->data.data, hsk->frag_length);
+ 		}
+ 
+ 		session->internals.handshake_recv_buffer_size++;
+@@ -1031,20 +1029,27 @@ static int merge_handshake_packet(gnutls_session_t session,
+ 		}
+ 
+ 		if (hsk->start_offset < recv_buf[pos].start_offset &&
+-		    hsk->end_offset + 1 >= recv_buf[pos].start_offset) {
++		    hsk->start_offset + hsk->frag_length >=
++			    recv_buf[pos].start_offset) {
+ 			memcpy(&recv_buf[pos].data.data[hsk->start_offset],
+ 			       hsk->data.data, hsk->data.length);
+ 			recv_buf[pos].start_offset = hsk->start_offset;
+-			recv_buf[pos].end_offset =
+-				MIN(hsk->end_offset, recv_buf[pos].end_offset);
+-		} else if (hsk->end_offset > recv_buf[pos].end_offset &&
+-			   hsk->start_offset <= recv_buf[pos].end_offset + 1) {
++			recv_buf[pos].frag_length = MIN(
++				hsk->frag_length, recv_buf[pos].frag_length);
++		} else if (hsk->start_offset + hsk->frag_length >
++				   recv_buf[pos].start_offset +
++					   recv_buf[pos].frag_length &&
++			   hsk->start_offset <=
++				   recv_buf[pos].start_offset +
++					   recv_buf[pos].frag_length) {
+ 			memcpy(&recv_buf[pos].data.data[hsk->start_offset],
+ 			       hsk->data.data, hsk->data.length);
+ 
+-			recv_buf[pos].end_offset = hsk->end_offset;
+ 			recv_buf[pos].start_offset = MIN(
+ 				hsk->start_offset, recv_buf[pos].start_offset);
++			recv_buf[pos].frag_length = hsk->start_offset +
++						    hsk->frag_length -
++						    recv_buf[pos].start_offset;
+ 		}
+ 		_gnutls_handshake_buffer_clear(hsk);
+ 	}
+@@ -1104,8 +1109,8 @@ static int get_last_packet(gnutls_session_t session,
+ 		}
+ 
+ 		else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
+-			  recv_buf[LAST_ELEMENT].end_offset ==
+-				  recv_buf[LAST_ELEMENT].length - 1) ||
++			  recv_buf[LAST_ELEMENT].frag_length ==
++				  recv_buf[LAST_ELEMENT].length) ||
+ 			 recv_buf[LAST_ELEMENT].length == 0) {
+ 			session->internals.dtls.hsk_read_seq++;
+ 			_gnutls_handshake_buffer_move(hsk,
+@@ -1116,8 +1121,9 @@ static int get_last_packet(gnutls_session_t session,
+ 			/* if we don't have a complete handshake message, but we
+ 			 * have queued data waiting, try again to reconstruct the
+ 			 * handshake packet, using the queued */
+-			if (recv_buf[LAST_ELEMENT].end_offset !=
+-				    recv_buf[LAST_ELEMENT].length - 1 &&
++			if ((recv_buf[LAST_ELEMENT].start_offset +
++			     recv_buf[LAST_ELEMENT].frag_length) !=
++				    recv_buf[LAST_ELEMENT].length &&
+ 			    record_check_unprocessed(session) > 0)
+ 				return gnutls_assert_val(
+ 					GNUTLS_E_INT_CHECK_AGAIN);
+@@ -1304,9 +1310,7 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
+ 					&session->internals.record_buffer,
+ 					bufel, ret);
+ 
+-				data_size = MIN(tmp.length,
+-						tmp.end_offset -
+-							tmp.start_offset + 1);
++				data_size = MIN(tmp.length, tmp.frag_length);
+ 
+ 				ret = _gnutls_buffer_append_data(
+ 					&tmp.data,
+@@ -1322,7 +1326,6 @@ int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
+ 				ret = merge_handshake_packet(session, &tmp);
+ 				if (ret < 0)
+ 					return gnutls_assert_val(ret);
+-
+ 			} while (_mbuffer_get_udata_size(bufel) > 0);
+ 
+ 			prev = bufel;
+diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
+index 8cf9a8715..689dcdc41 100644
+--- a/lib/gnutls_int.h
++++ b/lib/gnutls_int.h
+@@ -479,10 +479,10 @@ typedef struct {
+ 	uint16_t sequence;
+ 
+ 	/* indicate whether that message is complete.
+-	 * complete means start_offset == 0 and end_offset == length
++	 * complete means start_offset == 0 and frag_length == length
+ 	 */
+ 	uint32_t start_offset;
+-	uint32_t end_offset;
++	uint32_t frag_length; /* used exclusively in DTLS reassembly */
+ 
+ 	uint8_t header[MAX_HANDSHAKE_HEADER_SIZE];
+ 	int header_size;
+-- 
+2.43.0
+
diff --git a/meta/recipes-support/gnutls/gnutls_3.8.4.bb b/meta/recipes-support/gnutls/gnutls_3.8.4.bb
index e40a654a8e..702a83fc85 100644
--- a/meta/recipes-support/gnutls/gnutls_3.8.4.bb
+++ b/meta/recipes-support/gnutls/gnutls_3.8.4.bb
@@ -45,6 +45,8 @@  SRC_URI = "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar
            file://CVE-2025-14831-9.patch \
            file://CVE-2026-33846-pre.patch \
            file://CVE-2026-33846.patch \
+           file://CVE-2026-33845-pre.patch \
+           file://CVE-2026-33845.patch \
            "
 
 SRC_URI[sha256sum] = "2bea4e154794f3f00180fa2a5c51fe8b005ac7a31cd58bd44cdfa7f36ebc3a9b"