On Mon Jun 29, 2026 at 7:02 AM CEST, Pritam Srichandan Sahoo via lists.openembedded.org wrote: > Backport upstream fixes for DTLS handshake fragment reassembly > vulnerability (CVE-2026-33846). > > Includes: > - 4f94e5cfe1f2: add basic DTLS fragment reassembly test > - 9deffca528c2: shorten merge_handshake_packet using recv_buf > - 65ab33fa54e3: add validation checks for DTLS fragment length and bounds > - cf3f1955e58c: add reproducer for DTLS fragment reassembly bug (#1816) > - bb427ff74dba: add fragmented ClientHello test coverage > - 092c65d004e2: match DTLS datagrams by handshake sequence number > - a2b41be83a1a: add test for mismatched message_seq handling (#1839) > > These commits are included in gnutls 3.8.13 and are backported by > both Debian (gnutls28_3.8.9-3+deb13u4) and CentOS 10-stream > (gnutls-3.8.10-4.el10) using identical commit selection. > > Signed-off-by: Pritam Srichandan Sahoo <[email protected]>" > ---
Hello, looks like it breaks musl build: https://autobuilder.yoctoproject.org/valkyrie/?#/builders/109/builds/643/steps/12/logs/stdio (line 18053) Can you check please? Thanks! > .../gnutls/gnutls/CVE-2026-33846.patch | 862 ++++++++++++++++++ > meta/recipes-support/gnutls/gnutls_3.8.12.bb | 1 + > 2 files changed, 863 insertions(+) > create mode 100644 meta/recipes-support/gnutls/gnutls/CVE-2026-33846.patch > > diff --git a/meta/recipes-support/gnutls/gnutls/CVE-2026-33846.patch > b/meta/recipes-support/gnutls/gnutls/CVE-2026-33846.patch > new file mode 100644 > index 0000000000..5c85a531b3 > --- /dev/null > +++ b/meta/recipes-support/gnutls/gnutls/CVE-2026-33846.patch > @@ -0,0 +1,862 @@ > +From 4f94e5cfe1f252a431e41642b0752e7e0daf43b9 Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Fri, 20 Mar 2026 16:09:40 +0100 > +Subject: [PATCH 1/7] tests/mini-dtls-fragments: implement a basic DTLS test > + > +Upstream-Status: Backport > +[1] > https://gitlab.com/gnutls/gnutls/-/commit/4f94e5cfe1f252a431e41642b0752e7e0daf43b9 > +[2] > https://gitlab.com/gnutls/gnutls/-/commit/9deffca528c23bbb218f5ec3bd4bb1bf4cbd1fc0 > +[3] > https://gitlab.com/gnutls/gnutls/-/commit/65ab33fa54e34fba69d793735b7df3d383d1ff78 > +[4] > https://gitlab.com/gnutls/gnutls/-/commit/cf3f1955e58cbcc10373b841bb101fb058565d87 > +[5] > https://gitlab.com/gnutls/gnutls/-/commit/bb427ff74dba849d40753ed9c8511e873f762743 > +[6] > https://gitlab.com/gnutls/gnutls/-/commit/092c65d004e2f125f2fea3db84d801ac49a09f78 > +[7] > https://gitlab.com/gnutls/gnutls/-/commit/a2b41be83a1a3529c551ccf54958da91a656550e > + > +CVE: CVE-2026-33846 > +Signed-off-by: Alexander Sosedkin <[email protected]> > +Signed-off-by: Pritam Srichandan Sahoo <[email protected]> > +--- > + tests/Makefile.am | 7 +- > + tests/mini-dtls-fragments.c | 208 ++++++++++++++++++++++++++++++++++++ > + 2 files changed, 214 insertions(+), 1 deletion(-) > + create mode 100644 tests/mini-dtls-fragments.c > + > +diff --git a/tests/Makefile.am b/tests/Makefile.am > +index aeeaaf79d..586f1952d 100644 > +--- a/tests/Makefile.am > ++++ b/tests/Makefile.am > +@@ -241,7 +241,8 @@ ctests += mini-record-2 simple gnutls_hmac_fast > set_pkcs12_cred cert certuniquei > + x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \ > + x509-upnconstraint xts-key-check cipher-padding > pkcs7-verify-double-free \ > + fips-rsa-sizes tls12-rehandshake-ticket pathbuf tls-force-ems \ > +- psk-importer privkey-derive dh-compute2 ecdh-compute2 > ++ psk-importer privkey-derive dh-compute2 ecdh-compute2 \ > ++ mini-dtls-fragments > + > + ctests += tls-channel-binding > + > +@@ -513,6 +514,10 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \ > + -I$(top_srcdir)/gl \ > + -I$(top_builddir)/gl > + > ++mini_dtls_fragments_CPPFLAGS = $(AM_CPPFLAGS) \ > ++ -I$(top_srcdir)/gl \ > ++ -I$(top_builddir)/gl > ++ > + if ENABLE_PKCS11 > + if !WINDOWS > + ctests += tls13/post-handshake-with-cert-pkcs11 > pkcs11/tls-neg-pkcs11-no-key \ > +diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c > +new file mode 100644 > +index 000000000..ee75feeb6 > +--- /dev/null > ++++ b/tests/mini-dtls-fragments.c > +@@ -0,0 +1,208 @@ > ++/* > ++ * Copyright (C) 2026 Red Hat, Inc. > ++ * > ++ * Author: Alexander Sosedkin > ++ * > ++ * This file is part of GnuTLS. > ++ * > ++ * GnuTLS is free software; you can redistribute it and/or modify it > ++ * under the terms of the GNU General Public License as published by > ++ * the Free Software Foundation; either version 3 of the License, or > ++ * (at your option) any later version. > ++ * > ++ * GnuTLS is distributed in the hope that it will be useful, but > ++ * WITHOUT ANY WARRANTY; without even the implied warranty of > ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > ++ * General Public License for more details. > ++ * > ++ * You should have received a copy of the GNU Lesser General Public License > ++ * along with this program. If not, see <https://www.gnu.org/licenses/> > ++ */ > ++ > ++#ifdef HAVE_CONFIG_H > ++#include "config.h" > ++#endif > ++ > ++#include <stdio.h> > ++#include <stdlib.h> > ++ > ++#if defined(_WIN32) > ++ > ++int main(void) > ++{ > ++ exit(77); > ++} > ++ > ++#else > ++ > ++#include <assert.h> > ++#include <errno.h> > ++#include <stdbool.h> > ++#include <stdint.h> > ++#include <string.h> > ++#include <gnutls/gnutls.h> > ++#include <gnutls/dtls.h> > ++#include "cert-common.h" > ++#include "utils.h" > ++ > ++#include "attribute.h" > ++ > ++static void server_log_func(int level, const char *str) > ++{ > ++ fprintf(stderr, "server|<%d>| %s", level, str); > ++} > ++ > ++static void client_log_func(int level, const char *str) > ++{ > ++ fprintf(stderr, "client|<%d>| %s", level, str); > ++} > ++ > ++#define QUEUE_SIZE 1024 > ++#define PACKET_SIZE 2048 > ++ > ++typedef struct { > ++ uint8_t buf[PACKET_SIZE]; > ++ size_t len; > ++} packet_t; > ++typedef struct { > ++ packet_t packets[QUEUE_SIZE]; > ++ size_t head; > ++ size_t tail; > ++} queue_t; > ++ > ++static queue_t c2s, s2c; > ++ > ++static int queue_put(queue_t *q, const void *buf, size_t len) > ++{ > ++ assert(len <= PACKET_SIZE); > ++ memcpy(q->packets[q->tail].buf, buf, len); > ++ q->packets[q->tail].len = len; > ++ q->tail++; > ++ q->tail %= QUEUE_SIZE; > ++ assert(q->tail != q->head); > ++ return len; > ++} > ++ > ++static ssize_t queue_get(queue_t *q, gnutls_session_t s, void *buf, size_t > len) > ++{ > ++ if (q->head == q->tail) { > ++ gnutls_transport_set_errno(s, EAGAIN); > ++ return -1; > ++ } > ++ size_t n = q->packets[q->head].len; > ++ memcpy(buf, q->packets[q->head].buf, n); > ++ q->head++; > ++ q->head %= QUEUE_SIZE; > ++ return n; > ++} > ++ > ++static void queue_reset(queue_t *q) > ++{ > ++ q->head = q->tail = 0; > ++} > ++ > ++static int pull_timeout(gnutls_transport_ptr_t tr, unsigned ms) > ++{ > ++ return 1; > ++} > ++ > ++static ssize_t server_pull(gnutls_transport_ptr_t tr, void *b, size_t l) > ++{ > ++ return queue_get(&c2s, (gnutls_session_t)tr, b, l); > ++} > ++ > ++static ssize_t client_pull(gnutls_transport_ptr_t tr, void *b, size_t l) > ++{ > ++ return queue_get(&s2c, (gnutls_session_t)tr, b, l); > ++} > ++ > ++static ssize_t server_push(gnutls_transport_ptr_t tr, const void *b, size_t > l) > ++{ > ++ return queue_put(&s2c, b, l); > ++} > ++ > ++static ssize_t client_push_normal(gnutls_transport_ptr_t tr, const void *b, > ++ size_t l) > ++{ > ++ return queue_put(&c2s, b, l); > ++} > ++ > ++static void test(gnutls_push_func client_push) > ++{ > ++ gnutls_session_t client, server; > ++ gnutls_certificate_credentials_t ccred, scred; > ++ int cr = 0, sr = 0; > ++ bool cdone = false, sdone = false; > ++ > ++ if (debug) > ++ gnutls_global_set_log_level(4711); > ++ > ++ gnutls_certificate_allocate_credentials(&scred); > ++ gnutls_certificate_set_x509_key_mem(scred, &server_cert, &server_key, > ++ GNUTLS_X509_FMT_PEM); > ++ gnutls_certificate_allocate_credentials(&ccred); > ++ > ++ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_DATAGRAM); > ++ gnutls_init(&client, GNUTLS_CLIENT | GNUTLS_DATAGRAM); > ++ > ++ gnutls_priority_set_direct(server, "NORMAL:-VERS-ALL:+VERS-DTLS1.2", > ++ NULL); > ++ gnutls_priority_set_direct(client, "NORMAL:-VERS-ALL:+VERS-DTLS1.2", > ++ NULL); > ++ > ++ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred); > ++ gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred); > ++ > ++ gnutls_dtls_set_timeouts(client, get_dtls_retransmit_timeout(), > ++ get_timeout()); > ++ gnutls_dtls_set_timeouts(server, get_dtls_retransmit_timeout(), > ++ get_timeout()); > ++ > ++ gnutls_transport_set_ptr(client, client); > ++ gnutls_transport_set_push_function(client, client_push); > ++ gnutls_transport_set_pull_function(client, client_pull); > ++ gnutls_transport_set_pull_timeout_function(client, pull_timeout); > ++ > ++ gnutls_transport_set_ptr(server, server); > ++ gnutls_transport_set_push_function(server, server_push); > ++ gnutls_transport_set_pull_function(server, server_pull); > ++ gnutls_transport_set_pull_timeout_function(server, pull_timeout); > ++ > ++ while (!cdone || !sdone) { > ++ gnutls_global_set_log_function(client_log_func); > ++ if (!cdone) > ++ cr = gnutls_handshake(client); > ++ if (!cr || gnutls_error_is_fatal(cr)) > ++ cdone = true; > ++ > ++ gnutls_global_set_log_function(server_log_func); > ++ if (!sdone) > ++ sr = gnutls_handshake(server); > ++ if (!sr || gnutls_error_is_fatal(sr)) > ++ sdone = true; > ++ } > ++ > ++ if (cr) > ++ fail("client: %s\n", gnutls_strerror(cr)); > ++ if (sr) > ++ fail("server: %s\n", gnutls_strerror(sr)); > ++ > ++ success("OK\n"); > ++ > ++ queue_reset(&c2s); > ++ queue_reset(&s2c); > ++ > ++ gnutls_deinit(client); > ++ gnutls_deinit(server); > ++ gnutls_certificate_free_credentials(ccred); > ++ gnutls_certificate_free_credentials(scred); > ++} > ++ > ++void doit(void) > ++{ > ++ global_init(); > ++ test(client_push_normal); > ++ gnutls_global_deinit(); > ++} > ++ > ++#endif /* _WIN32 */ > +-- > +2.54.0 > + > + > +From 9deffca528c23bbb218f5ec3bd4bb1bf4cbd1fc0 Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Fri, 17 Apr 2026 17:49:31 +0200 > +Subject: [PATCH 2/7] buffers: shorten merge_handshake_packet using recv_buf > + > +I had vague concerns about thread-safety of this, > +but then this pattern already exists within the file. > + > +Signed-off-by: Alexander Sosedkin <[email protected]> > +--- > + lib/buffers.c | 52 +++++++++++++++++---------------------------------- > + 1 file changed, 17 insertions(+), 35 deletions(-) > + > +diff --git a/lib/buffers.c b/lib/buffers.c > +index 672380b05..d54c77022 100644 > +--- a/lib/buffers.c > ++++ b/lib/buffers.c > +@@ -967,9 +967,11 @@ static int merge_handshake_packet(gnutls_session_t > session, > + int exists = 0, i, pos = 0; > + int ret; > + > ++ handshake_buffer_st *recv_buf = > ++ session->internals.handshake_recv_buffer; > ++ > + for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) { > +- if (session->internals.handshake_recv_buffer[i].htype == > +- hsk->htype) { > ++ if (recv_buf[i].htype == hsk->htype) { > + exists = 1; > + pos = i; > + break; > +@@ -1005,44 +1007,24 @@ static int merge_handshake_packet(gnutls_session_t > session, > + _gnutls_write_uint24(0, &hsk->header[6]); > + _gnutls_write_uint24(hsk->length, &hsk->header[9]); > + > +- _gnutls_handshake_buffer_move( > +- &session->internals.handshake_recv_buffer[pos], hsk); > ++ _gnutls_handshake_buffer_move(&recv_buf[pos], hsk); > + > + } else { > +- if (hsk->start_offset < > +- session->internals.handshake_recv_buffer[pos] > +- .start_offset && > +- hsk->end_offset + 1 >= > +- session->internals.handshake_recv_buffer[pos] > +- .start_offset) { > +- memcpy(&session->internals.handshake_recv_buffer[pos] > +- .data.data[hsk->start_offset], > ++ 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], > + hsk->data.data, hsk->data.length); > +- session->internals.handshake_recv_buffer[pos] > +- .start_offset = hsk->start_offset; > +- session->internals.handshake_recv_buffer[pos] > +- .end_offset = MIN( > +- hsk->end_offset, > +- session->internals.handshake_recv_buffer[pos] > +- .end_offset); > +- } else if (hsk->end_offset > > +- session->internals.handshake_recv_buffer[pos] > +- .end_offset && > +- hsk->start_offset <= > +- session->internals.handshake_recv_buffer[pos] > +- .end_offset + > +- 1) { > +- memcpy(&session->internals.handshake_recv_buffer[pos] > +- .data.data[hsk->start_offset], > ++ 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) { > ++ memcpy(&recv_buf[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); > ++ recv_buf[pos].end_offset = hsk->end_offset; > ++ recv_buf[pos].start_offset = MIN( > ++ hsk->start_offset, recv_buf[pos].start_offset); > + } > + _gnutls_handshake_buffer_clear(hsk); > + } > +-- > +2.54.0 > + > + > +From 65ab33fa54e34fba69d793735b7df3d383d1ff78 Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Fri, 17 Apr 2026 18:21:36 +0200 > +Subject: [PATCH 3/7] 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 <[email protected]> > +--- > + 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.54.0 > + > + > +From cf3f1955e58cbcc10373b841bb101fb058565d87 Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Wed, 1 Apr 2026 19:51:45 +0200 > +Subject: [PATCH 4/7] tests/mini-dtls-fragments: extend with a #1816 > reproducer > + > +Signed-off-by: Alexander Sosedkin <[email protected]> > +--- > + tests/mini-dtls-fragments.c | 120 ++++++++++++++++++++++++++++++++++++ > + 1 file changed, 120 insertions(+) > + > +diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c > +index ee75feeb6..8d5a18acd 100644 > +--- a/tests/mini-dtls-fragments.c > ++++ b/tests/mini-dtls-fragments.c > +@@ -106,6 +106,11 @@ static int pull_timeout(gnutls_transport_ptr_t tr, > unsigned ms) > + return 1; > + } > + > ++static int c2s_pull_timeout_once(gnutls_transport_ptr_t tr, unsigned ms) > ++{ > ++ return c2s.head != c2s.tail ? 1 : 0; > ++} > ++ > + static ssize_t server_pull(gnutls_transport_ptr_t tr, void *b, size_t l) > + { > + return queue_get(&c2s, (gnutls_session_t)tr, b, l); > +@@ -198,10 +203,125 @@ static void test(gnutls_push_func client_push) > + gnutls_certificate_free_credentials(scred); > + } > + > ++static void test_malicious1816(void) > ++{ > ++ /* dgram1: msg_len=50, frag_offset=25, frag_len=25 */ > ++ static const uint8_t dgram1_hdr[] = { > ++ 0x16, /* type: handshake */ > ++ 0xfe, 0xfd, /* version: DTLS 1.2 */ > ++ 0x00, 0x00, /* epoch: 0 */ > ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* seq: 0 */ > ++ 0x00, 0x25, /* record_length: 37 */ > ++ 0x01, /* msg_type: ClientHello */ > ++ 0x00, 0x00, 0x32, /* msg_length: 50 */ > ++ 0x00, 0x00, /* msg_seq: 0 */ > ++ 0x00, 0x00, 0x19, /* frag_offset: 25 */ > ++ 0x00, 0x00, 0x19, /* frag_length: 25 */ > ++ }; > ++ /* dgram2: msg_len=3000, frag_offset=0, frag_len=48 */ > ++ static const uint8_t dgram2_hdr[] = { > ++ 0x16, /* type: handshake */ > ++ 0xfe, 0xfd, /* version: DTLS 1.2 */ > ++ 0x00, 0x00, /* epoch: 0 */ > ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* seq: 1 */ > ++ 0x00, 0x3c, /* record_length: 60 */ > ++ 0x01, /* msg_type: ClientHello */ > ++ 0x00, 0x0b, 0xb8, /* msg_length: 3000 */ > ++ 0x00, 0x00, /* msg_seq: 0 */ > ++ 0x00, 0x00, 0x00, /* frag_offset: 0 */ > ++ 0x00, 0x00, 0x30, /* frag_length: 48 */ > ++ }; > ++ /* dgram3: msg_len=3000, frag_offset=40, frag_len=1475 */ > ++ static const uint8_t dgram3_hdr[] = { > ++ 0x16, /* type: handshake */ > ++ 0xfe, 0xfd, /* version: DTLS 1.2 */ > ++ 0x00, 0x00, /* epoch: 0 */ > ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, /* seq: 2 */ > ++ 0x05, 0xcf, /* record_length: 1487 */ > ++ 0x01, /* msg_type: ClientHello */ > ++ 0x00, 0x0b, 0xb8, /* msg_length: 3000 */ > ++ 0x00, 0x00, /* msg_seq: 0 */ > ++ 0x00, 0x00, 0x28, /* frag_offset: 40 */ > ++ 0x00, 0x05, 0xc3, /* frag_length: 1475 */ > ++ }; > ++ /* dgram4: msg_len=3000, frag_offset=1500, frag_len=1475 */ > ++ static const uint8_t dgram4_hdr[] = { > ++ 0x16, /* type: handshake */ > ++ 0xfe, 0xfd, /* version: DTLS 1.2 */ > ++ 0x00, 0x00, /* epoch: 0 */ > ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, /* seq: 3 */ > ++ 0x05, 0xcf, /* record_length: 1487 */ > ++ 0x01, /* msg_type: ClientHello */ > ++ 0x00, 0x0b, 0xb8, /* msg_length: 3000 */ > ++ 0x00, 0x00, /* msg_seq: 0 */ > ++ 0x00, 0x05, 0xdc, /* frag_offset: 1500 */ > ++ 0x00, 0x05, 0xc3, /* frag_length: 1475 */ > ++ }; > ++ gnutls_session_t server; > ++ gnutls_certificate_credentials_t scred; > ++ uint8_t dgram[1500]; > ++ int sr; > ++ > ++ if (debug) > ++ gnutls_global_set_log_level(4711); > ++ > ++ gnutls_certificate_allocate_credentials(&scred); > ++ gnutls_certificate_set_x509_key_mem(scred, &server_cert, &server_key, > ++ GNUTLS_X509_FMT_PEM); > ++ > ++ gnutls_init(&server, GNUTLS_SERVER | GNUTLS_DATAGRAM); > ++ gnutls_priority_set_direct(server, "NORMAL:+VERS-DTLS1.2", NULL); > ++ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred); > ++ > ++ gnutls_dtls_set_timeouts(server, get_dtls_retransmit_timeout(), > ++ get_timeout()); > ++ > ++ gnutls_transport_set_ptr(server, server); > ++ gnutls_transport_set_push_function(server, server_push); > ++ gnutls_transport_set_pull_function(server, server_pull); > ++ gnutls_transport_set_pull_timeout_function(server, > ++ c2s_pull_timeout_once); > ++ > ++ memset(dgram, 0, sizeof(dgram)); > ++ memcpy(dgram, dgram1_hdr, 25); > ++ queue_put(&c2s, dgram, 25 + 25); > ++ > ++ memset(dgram, 0, sizeof(dgram)); > ++ memcpy(dgram, dgram2_hdr, 25); > ++ queue_put(&c2s, dgram, 25 + 48); > ++ > ++ memset(dgram, 0, sizeof(dgram)); > ++ memcpy(dgram, dgram3_hdr, 25); > ++ queue_put(&c2s, dgram, 25 + 1475); > ++ > ++ memset(dgram, 0, sizeof(dgram)); > ++ memcpy(dgram, dgram4_hdr, 25); > ++ queue_put(&c2s, dgram, 25 + 1475); > ++ > ++ gnutls_global_set_log_function(server_log_func); > ++ do { > ++ sr = gnutls_handshake(server); /* invalid write if vulnerable */ > ++ } while (c2s.head != c2s.tail && !gnutls_error_is_fatal(sr)); > ++ if (sr != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) > ++ fail("server: expected GNUTLS_E_UNEXPECTED_PACKET_LENGTH, " > ++ "got: %s\n", > ++ gnutls_strerror(sr)); > ++ > ++ success("OK\n"); > ++ > ++ queue_reset(&c2s); > ++ queue_reset(&s2c); > ++ > ++ gnutls_deinit(server); > ++ gnutls_certificate_free_credentials(scred); > ++} > ++ > + void doit(void) > + { > + global_init(); > + test(client_push_normal); > ++ success("malicious reassembly bug exploitation (#1816):\n"); > ++ test_malicious1816(); > + gnutls_global_deinit(); > + } > + > +-- > +2.54.0 > + > + > +From bb427ff74dba849d40753ed9c8511e873f762743 Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Mon, 20 Apr 2026 16:08:11 +0200 > +Subject: [PATCH 5/7] tests/mini-dtls-fragments: extend with fragmenting > + ClientHello > + > +Signed-off-by: Alexander Sosedkin <[email protected]> > +--- > + tests/mini-dtls-fragments.c | 107 ++++++++++++++++++++++++++++++++++++ > + 1 file changed, 107 insertions(+) > + > +diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c > +index 8d5a18acd..93490bac2 100644 > +--- a/tests/mini-dtls-fragments.c > ++++ b/tests/mini-dtls-fragments.c > +@@ -132,6 +132,39 @@ static ssize_t > client_push_normal(gnutls_transport_ptr_t tr, const void *b, > + return queue_put(&c2s, b, l); > + } > + > ++static void write_u16(uint8_t *p, uint16_t val) > ++{ > ++ p[0] = val >> 8; > ++ p[1] = val & 0xff; > ++} > ++ > ++static void write_u24(uint8_t *p, uint32_t val) > ++{ > ++ p[0] = (val >> 16) & 0xff; > ++ p[1] = (val >> 8) & 0xff; > ++ p[2] = val & 0xff; > ++} > ++ > ++static void write_u48(uint8_t *p, uint64_t seq) > ++{ > ++ int i; > ++ for (i = 5; i >= 0; i--) { > ++ p[i] = seq & 0xff; > ++ seq >>= 8; > ++ } > ++} > ++ > ++static uint64_t read_u48(const uint8_t *p) > ++{ > ++ uint64_t seq = 0; > ++ int i; > ++ for (i = 5; i >= 0; i--) { > ++ seq <<= 8; > ++ seq |= p[i]; > ++ } > ++ return seq; > ++} > ++ > + static void test(gnutls_push_func client_push) > + { > + gnutls_session_t client, server; > +@@ -316,12 +349,86 @@ static void test_malicious1816(void) > + gnutls_certificate_free_credentials(scred); > + } > + > ++static ssize_t queue_put_renumbered(queue_t *q, const uint8_t *data, size_t > l, > ++ int delta_n) > ++{ > ++ if (delta_n == 0 || l < 13 || data[3] != 0 || data[4] != 0) > ++ return queue_put(&c2s, data, l); > ++ > ++ uint8_t *p = malloc(l); > ++ assert(p); > ++ memcpy(p, data, l); > ++ write_u48(p + 5, read_u48(p + 5) + delta_n); > ++ ssize_t ret = queue_put(q, p, l); > ++ free(p); > ++ return ret; > ++} > ++ > ++static void split_client_hello(const uint8_t *data, size_t len, uint8_t > **frag1, > ++ size_t *frag1_len, uint8_t **frag2, > ++ size_t *frag2_len) > ++{ > ++ size_t body_size = len - 25; > ++ *frag1_len = 13 + 12 + 1; > ++ *frag2_len = 13 + 12 + (body_size - 1); > ++ > ++ *frag1 = malloc(13 + 12 + 1); > ++ assert(*frag1); > ++ *frag2 = malloc(13 + 12 + body_size - 1); > ++ assert(*frag2); > ++ > ++ /* first fragment: record header + handshake header + first body byte */ > ++ memcpy(*frag1, data, 13); /* record header */ > ++ write_u16(*frag1 + 11, 12 + 1); /* record length */ > ++ memcpy(*frag1 + 13, data + 13, 12); /* handshake header */ > ++ write_u24(*frag1 + 19, 0); /* fragment_offset = 0 */ > ++ write_u24(*frag1 + 22, 1); /* fragment_length = 1 */ > ++ (*frag1)[25] = data[25]; /* first body byte */ > ++ > ++ /* second fragment: record header + handshake header + remaining body */ > ++ memcpy(*frag2, data, 13); /* record header */ > ++ write_u16(*frag2 + 11, *frag2_len - 13); /* record length */ > ++ write_u48(*frag2 + 5, read_u48(*frag2 + 5) + 1); /* sequence number */ > ++ memcpy(*frag2 + 13, data + 13, 12); /* handshake header */ > ++ write_u24(*frag2 + 19, 1); /* fragment_offset = 1 */ > ++ write_u24(*frag2 + 22, body_size - 1); /* shortened fragment_length */ > ++ memcpy(*frag2 + 25, data + 26, body_size - 1); /* remaining body */ > ++} > ++ > ++static ssize_t client_push_split_hello(gnutls_transport_ptr_t tr, const > void *b, > ++ size_t l) > ++{ > ++ static int seq_offset = 0; /* for renumbering follow-up epoch0 ones */ > ++ > ++ const uint8_t *data = (const uint8_t *)b; > ++ uint8_t *frag1, *frag2; > ++ size_t frag1_len, frag2_len; > ++ > ++ /* Pass through anything that isn't an epoch0 ClientHello with body */ > ++ if (l < 13 + 12 + 1 || /* too short for DTLS record header */ > ++ data[0] != 22 || /* not a handshake record */ > ++ data[3] != 0 || data[4] != 0 || /* not epoch 0 */ > ++ data[13] != 1) /* not ClientHello */ > ++ return queue_put_renumbered(&c2s, b, l, seq_offset); > ++ > ++ /* epoch0 Client Hello: special treatment of splitting into fragments */ > ++ split_client_hello(data, l, &frag1, &frag1_len, &frag2, &frag2_len); > ++ queue_put(&c2s, frag1, frag1_len); > ++ queue_put(&c2s, frag2, frag2_len); > ++ free(frag1); > ++ free(frag2); > ++ seq_offset++; > ++ return l; > ++} > ++ > + void doit(void) > + { > + global_init(); > + test(client_push_normal); > + success("malicious reassembly bug exploitation (#1816):\n"); > + test_malicious1816(); > ++ success("split client hello smoke-test\n"); > ++ test(client_push_split_hello); > + gnutls_global_deinit(); > + } > + > +-- > +2.54.0 > + > + > +From 092c65d004e2f125f2fea3db84d801ac49a09f78 Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Mon, 20 Apr 2026 16:32:02 +0200 > +Subject: [PATCH 6/7] buffers: match DTLS datagrams by sequence number > + > +DTLS handshake fragment reassembly previously matched incoming fragments > +by handshake type only, without checking the sequence number. > +This allowed fragments from different handshake messages > +to be merged into the same reassembly buffer. > + > +Now sequence number is accounted for during reassembly, > +ensuring fragments are only merged when they belong > +to the same handshake message. > + > +Reported-by: Zou Dikai > +Fixes: #1839 > +Signed-off-by: Alexander Sosedkin <[email protected]> > +--- > + lib/buffers.c | 3 ++- > + 1 file changed, 2 insertions(+), 1 deletion(-) > + > +diff --git a/lib/buffers.c b/lib/buffers.c > +index 5d4d16276..62f140ed3 100644 > +--- a/lib/buffers.c > ++++ b/lib/buffers.c > +@@ -971,7 +971,8 @@ static int merge_handshake_packet(gnutls_session_t > session, > + session->internals.handshake_recv_buffer; > + > + for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) { > +- if (recv_buf[i].htype == hsk->htype) { > ++ if (recv_buf[i].htype == hsk->htype && > ++ recv_buf[i].sequence == hsk->sequence) { > + exists = 1; > + pos = i; > + break; > +-- > +2.54.0 > + > + > +From a2b41be83a1a3529c551ccf54958da91a656550e Mon Sep 17 00:00:00 2001 > +From: Alexander Sosedkin <[email protected]> > +Date: Mon, 20 Apr 2026 16:36:08 +0200 > +Subject: [PATCH 7/7] tests/mini-dtls-fragments: #1839 mismatching message_seq > + > +Signed-off-by: Alexander Sosedkin <[email protected]> > +--- > + tests/mini-dtls-fragments.c | 54 ++++++++++++++++++++++++++++++++----- > + 1 file changed, 47 insertions(+), 7 deletions(-) > + > +diff --git a/tests/mini-dtls-fragments.c b/tests/mini-dtls-fragments.c > +index 93490bac2..499a92a92 100644 > +--- a/tests/mini-dtls-fragments.c > ++++ b/tests/mini-dtls-fragments.c > +@@ -165,7 +165,7 @@ static uint64_t read_u48(const uint8_t *p) > + return seq; > + } > + > +-static void test(gnutls_push_func client_push) > ++static void test(gnutls_push_func client_push, bool expect_success) > + { > + gnutls_session_t client, server; > + gnutls_certificate_credentials_t ccred, scred; > +@@ -218,12 +218,22 @@ static void test(gnutls_push_func client_push) > + sr = gnutls_handshake(server); > + if (!sr || gnutls_error_is_fatal(sr)) > + sdone = true; > ++ > ++ if (c2s.head == c2s.tail && s2c.head == s2c.tail) > ++ break; /* speed the test up */ > + } > + > +- if (cr) > +- fail("client: %s\n", gnutls_strerror(cr)); > +- if (sr) > +- fail("server: %s\n", gnutls_strerror(sr)); > ++ if (expect_success) { > ++ if (cr) > ++ fail("client: %s\n", gnutls_strerror(cr)); > ++ if (sr) > ++ fail("server: %s\n", gnutls_strerror(sr)); > ++ > ++ } else { > ++ if (cr == 0 && sr == 0) > ++ fail("handshake unexpectedly succeeded: %s / %s\n", > ++ gnutls_strerror(cr), gnutls_strerror(sr)); > ++ } > + > + success("OK\n"); > + > +@@ -421,14 +431,44 @@ static ssize_t > client_push_split_hello(gnutls_transport_ptr_t tr, const void *b, > + return l; > + } > + > ++static ssize_t client_push_split_hello_bad_seq(gnutls_transport_ptr_t tr, > ++ const void *b, size_t l) > ++{ > ++ /* gnutls wasn't matching on message_seq on merging, see #1839 */ > ++ static int seq_offset = 0; /* for renumbering follow-up epoch0 ones */ > ++ > ++ const uint8_t *data = (const uint8_t *)b; > ++ uint8_t *frag1, *frag2; > ++ size_t frag1_len, frag2_len; > ++ > ++ /* Pass through anything that isn't an epoch0 ClientHello with body */ > ++ if (l < 13 + 12 + 1 || /* too short for DTLS record header */ > ++ data[0] != 22 || /* not a handshake record */ > ++ data[3] != 0 || data[4] != 0 || /* not epoch 0 */ > ++ data[13] != 1) /* not ClientHello */ > ++ return queue_put_renumbered(&c2s, b, l, seq_offset); > ++ > ++ /* epoch0 Client Hello: special treatment of splitting into fragments */ > ++ split_client_hello(data, l, &frag1, &frag1_len, &frag2, &frag2_len); > ++ queue_put(&c2s, frag1, frag1_len); > ++ frag2[18]++; /* WRONG, message_seq mismatch must be rejected, #1839 */ > ++ queue_put(&c2s, frag2, frag2_len); > ++ free(frag1); > ++ free(frag2); > ++ seq_offset++; > ++ return l; > ++} > ++ > + void doit(void) > + { > + global_init(); > +- test(client_push_normal); > ++ test(client_push_normal, true); > + success("malicious reassembly bug exploitation (#1816):\n"); > + test_malicious1816(); > + success("split client hello smoke-test\n"); > +- test(client_push_split_hello); > ++ test(client_push_split_hello, true); > ++ success("split client hello smoke-test and mangle sequence number\n"); > ++ test(client_push_split_hello_bad_seq, false); > + gnutls_global_deinit(); > + } > + > +-- > +2.54.0 > + > diff --git a/meta/recipes-support/gnutls/gnutls_3.8.12.bb > b/meta/recipes-support/gnutls/gnutls_3.8.12.bb > index 8554ab943d..3ae7a2eb78 100644 > --- a/meta/recipes-support/gnutls/gnutls_3.8.12.bb > +++ b/meta/recipes-support/gnutls/gnutls_3.8.12.bb > @@ -24,6 +24,7 @@ SRC_URI = > "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar > file://run-ptest \ > file://Add-ptest-support.patch \ > file://c99.patch \ > + file://CVE-2026-33846.patch \ > " > > SRC_URI[sha256sum] = > "a7b341421bfd459acf7a374ca4af3b9e06608dcd7bd792b2bf470bea012b8e51" -- Yoann Congal Smile ECS
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#239909): https://lists.openembedded.org/g/openembedded-core/message/239909 Mute This Topic: https://lists.openembedded.org/mt/120027284/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
