]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
buffers: add more checks to DTLS reassembly
authorAlexander Sosedkin <asosedkin@redhat.com>
Fri, 17 Apr 2026 16:21:36 +0000 (18:21 +0200)
committerAlexander Sosedkin <asosedkin@redhat.com>
Wed, 29 Apr 2026 13:35:02 +0000 (15:35 +0200)
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>
lib/buffers.c

index d54c77022873531e213dff13cffd9661fe862755..5d4d1627686b072a139e8aa4fe98af017e06865b 100644 (file)
@@ -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],