mirror of
https://git.yoctoproject.org/poky
synced 2026-10-18 05:57:02 +00:00
gnutls: fix CVE-2026-33845
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 (From OE-Core rev: a624b5ffcb02b5ec566ccc788106391cf1084b5f) Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
1 parent
88822a6dcf
commit
456fd03409
2 files changed
+191
No files matched your search
@@ -0,0 +1,190 @@
|
||||
From d217d233d3eb5566a911dad11b639552d63acfac Mon Sep 17 00:00:00 2001
|
||||
From: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
|
||||
Date: Wed, 29 Jul 2026 08:54:58 +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 <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
|
||||
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
|
||||
|
||||
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 <adarsh.jagadish.kamini@est.tech>
|
||||
---
|
||||
lib/buffers.c | 59 ++++++++++++++++++++++++++----------------------
|
||||
lib/gnutls_int.h | 4 ++--
|
||||
2 files changed, 34 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/lib/buffers.c b/lib/buffers.c
|
||||
index 672380b05..ad59e4f14 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,11 @@ 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 +990,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 +1010,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 +1019,36 @@ 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]
|
||||
- .end_offset &&
|
||||
+ .start_offset +
|
||||
+ session->internals
|
||||
+ .handshake_recv_buffer[pos]
|
||||
+ .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 +1108,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 +1120,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 +1309,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,
|
||||
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;
|
||||
@@ -50,6 +50,7 @@ SRC_URI = "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar
|
||||
file://CVE-2026-42011_p1.patch \
|
||||
file://CVE-2026-42011_p2.patch \
|
||||
file://CVE-2026-33846.patch \
|
||||
file://CVE-2026-33845.patch \
|
||||
"
|
||||
|
||||
SRC_URI[sha256sum] = "2bea4e154794f3f00180fa2a5c51fe8b005ac7a31cd58bd44cdfa7f36ebc3a9b"
|
||||
|
||||
Reference in new issue
Block a user