Backport patch to fix CVE-2026-33845.

References:
  https://nvd.nist.gov/vuln/detail/CVE-2026-33845

Upstream fix:
  
https://gitlab.com/gnutls/gnutls/-/commit/e5b72c53c7d789d19d1d1cd10b275e87d0415413

Tested with ptest:
Before: PASSED: 371, FAILED: 0, SKIPPED: 15
After: PASSED: 371, FAILED: 0, SKIPPED: 15

Signed-off-by: Adarsh Jagadish Kamini <[email protected]>
---
 .../gnutls/gnutls/CVE-2026-33845.patch        | 195 ++++++++++++++++++
 meta/recipes-support/gnutls/gnutls_3.8.12.bb  |   1 +
 2 files changed, 196 insertions(+)
 create mode 100644 meta/recipes-support/gnutls/gnutls/CVE-2026-33845.patch

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..d81ffb7ef7
--- /dev/null
+++ b/meta/recipes-support/gnutls/gnutls/CVE-2026-33845.patch
@@ -0,0 +1,195 @@
+From 9679a9c8ab1694b78c7cb285d29da904e3f3bc45 Mon Sep 17 00:00:00 2001
+From: Adarsh Jagadish Kamini <[email protected]>
+Date: Mon, 27 Jul 2026 08:58:02 +0000
+Subject: [PATCH] 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 <[email protected]>
+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
+Signed-off-by: Alexander Sosedkin <[email protected]>
+
+CVE: CVE-2026-33845
+Upstream-Status: Backport 
[https://gitlab.com/gnutls/gnutls/-/commit/e5b72c53c7d789d19d1d1cd10b275e87d0415413]
+
+Backport notes: adapted to the stable branch, no logic changes.
+- lib/buffers.c: the local fragment-size variable is named frag_size here,
+  not frag_length as upstream; renamed accordingly.
+- lib/buffers.c: merge_handshake_packet() has no recv_buf alias in this
+  branch, so recv_buf[pos] was expanded to
+  session->internals.handshake_recv_buffer[pos], which changes line wrapping.
+- lib/gnutls_int.h: applies cleanly.
+
+Assisted-by: kiro:claude-sonnet-4.6
+Signed-off-by: Adarsh Jagadish Kamini <[email protected]>
+---
+ lib/buffers.c    | 57 ++++++++++++++++++++++++------------------------
+ lib/gnutls_int.h |  4 ++--
+ 2 files changed, 31 insertions(+), 30 deletions(-)
+
+diff --git a/lib/buffers.c b/lib/buffers.c
+index 672380b05..2d77e7590 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_size > 0)
+-              hsk->end_offset = hsk->start_offset + frag_size - 1;
+-      else
+-              hsk->end_offset = 0;
++      hsk->frag_length = frag_size;
+ 
+       _gnutls_handshake_log(
+               "HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, 
frag length: %d, sequence: %d\n",
+@@ -940,9 +937,10 @@ static int parse_handshake_header(gnutls_session_t 
session, mbuffer_st *bufel,
+ 
+       if (hsk->length > 0 &&
+           (frag_size > data_size ||
+-           (frag_size > 0 && hsk->end_offset >= hsk->length))) {
++           (frag_size > 0 && hsk->start_offset + frag_size > 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_size != hsk->start_offset &&
+                  hsk->start_offset != 0)
+               return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+ 
+@@ -991,11 +989,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++;
+@@ -1012,7 +1009,7 @@ static int merge_handshake_packet(gnutls_session_t 
session,
+               if (hsk->start_offset <
+                           session->internals.handshake_recv_buffer[pos]
+                                   .start_offset &&
+-                  hsk->end_offset + 1 >=
++                  hsk->start_offset + hsk->frag_length >=
+                           session->internals.handshake_recv_buffer[pos]
+                                   .start_offset) {
+                       memcpy(&session->internals.handshake_recv_buffer[pos]
+@@ -1021,28 +1018,34 @@ static int merge_handshake_packet(gnutls_session_t 
session,
+                       session->internals.handshake_recv_buffer[pos]
+                               .start_offset = hsk->start_offset;
+                       session->internals.handshake_recv_buffer[pos]
+-                              .end_offset = MIN(
+-                              hsk->end_offset,
++                              .frag_length = MIN(
++                              hsk->frag_length,
+                               session->internals.handshake_recv_buffer[pos]
+-                                      .end_offset);
+-              } else if (hsk->end_offset >
++                                      .frag_length);
++              } else if (hsk->start_offset + hsk->frag_length >
++                                 session->internals.handshake_recv_buffer[pos]
++                                         .start_offset +
+                                  session->internals.handshake_recv_buffer[pos]
+-                                         .end_offset &&
++                                         .frag_length &&
+                          hsk->start_offset <=
+                                  session->internals.handshake_recv_buffer[pos]
+-                                                 .end_offset +
+-                                         1) {
++                                         .start_offset +
++                                 session->internals.handshake_recv_buffer[pos]
++                                         .frag_length) {
+                       memcpy(&session->internals.handshake_recv_buffer[pos]
+                                       .data.data[hsk->start_offset],
+                              hsk->data.data, hsk->data.length);
+ 
+-                      session->internals.handshake_recv_buffer[pos]
+-                              .end_offset = hsk->end_offset;
+                       session->internals.handshake_recv_buffer[pos]
+                               .start_offset = MIN(
+                               hsk->start_offset,
+                               session->internals.handshake_recv_buffer[pos]
+                                       .start_offset);
++                      session->internals.handshake_recv_buffer[pos]
++                              .frag_length =
++                              hsk->start_offset + hsk->frag_length -
++                              session->internals.handshake_recv_buffer[pos]
++                                      .start_offset;
+               }
+               _gnutls_handshake_buffer_clear(hsk);
+       }
+@@ -1102,8 +1105,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,
+@@ -1114,8 +1117,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);
+@@ -1302,9 +1306,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,
+@@ -1320,7 +1322,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 54d3c9f67..283f25c07 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;
diff --git a/meta/recipes-support/gnutls/gnutls_3.8.12.bb 
b/meta/recipes-support/gnutls/gnutls_3.8.12.bb
index 468b4bdd40..4219a650de 100644
--- a/meta/recipes-support/gnutls/gnutls_3.8.12.bb
+++ b/meta/recipes-support/gnutls/gnutls_3.8.12.bb
@@ -25,6 +25,7 @@ SRC_URI = 
"https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar
            file://Add-ptest-support.patch \
            file://c99.patch \
            file://CVE-2026-3833.patch \
+           file://CVE-2026-33845.patch \
            "
 
 SRC_URI[sha256sum] = 
"a7b341421bfd459acf7a374ca4af3b9e06608dcd7bd792b2bf470bea012b8e51"
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#242100): 
https://lists.openembedded.org/g/openembedded-core/message/242100
Mute This Topic: https://lists.openembedded.org/mt/120469293/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to