unbound: patch CVE-2026-32665

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-32665

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Ankur Tyagi authored and Anuj Mittal committed 2026-09-15 10:13:56 +05:30
1 parent e7aac6e2ec
commit 8792c7f818
2 files changed
+120

No files matched your search

@@ -0,0 +1,119 @@
From c9bd4309ec14f767db0d0de5647f0e8fe554b60d Mon Sep 17 00:00:00 2001
From: "W.C.A. Wijngaards" <wouter@nlnetlabs.nl>
Date: Wed, 22 Jul 2026 10:09:26 +0200
Subject: [PATCH] - Fix CVE-2026-32665, Remote DNS-over-QUIC denial of
service due to `quic-size` budget bypass. Thanks to N0zoM1z0
(https://github.com/N0zoM1z0) for the report. In addition, thanks to Kunta
Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University, for also
reporting this issue. In addition, thanks to Qifan Zhang, Palo Alto
Networks, for also reporting this issue. In addition, thanks to Xuanchao
Xie, for also reporting this issue.
(cherry picked from commit 01dfd2f466d383370405d8ecf939570947f3523e)
CVE: CVE-2026-32665
Upstream-Status: Backport [https://github.com/NLnetLabs/unbound/commit/01dfd2f466d383370405d8ecf939570947f3523e]
Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
services/listen_dnsport.c | 32 ++++++++++++++++++++++----------
1 file changed, 22 insertions(+), 10 deletions(-)
diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c
index f7fcca194..3c5010b6b 100644
--- a/services/listen_dnsport.c
+++ b/services/listen_dnsport.c
@@ -3978,7 +3978,8 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
/** doq stream pick up answer data from buffer */
static int
-doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
+doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream,
+ struct sldns_buffer* buf)
{
stream->is_answer_available = 1;
if(stream->out) {
@@ -3988,6 +3989,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
}
stream->nwrite = 0;
stream->outlen = sldns_buffer_limit(buf);
+ if(!doq_table_quic_size_available(conn->doq_socket->table,
+ conn->doq_socket->cfg, stream->outlen)) {
+ verbose(VERB_ALGO, "doq stream: no space for reply length");
+ return 0;
+ }
/* For quic the output bytes have to stay allocated and available,
* for potential resends, until the remote end has acknowledged them.
* This includes the tcplen start uint16_t, in outlen_wire. */
@@ -4014,7 +4020,7 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
if(stream->out)
doq_table_quic_size_subtract(conn->doq_socket->table,
stream->outlen);
- if(!doq_stream_pickup_answer(stream, buf))
+ if(!doq_stream_pickup_answer(conn, stream, buf))
return 0;
doq_table_quic_size_add(conn->doq_socket->table, stream->outlen);
doq_stream_on_write_list(conn, stream);
@@ -4025,13 +4031,19 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
/** doq stream data length has completed, allocations can be done. False on
* allocation failure. */
static int
-doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table)
+doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream,
+ struct doq_table* table)
{
if(stream->inlen > 1024*1024) {
log_err("doq stream in length too large %d",
(int)stream->inlen);
return 0;
}
+ if(!doq_table_quic_size_available(table, conn->doq_socket->cfg,
+ stream->inlen)) {
+ verbose(VERB_ALGO, "doq stream: no space for query length");
+ return 0;
+ }
stream->in = calloc(1, stream->inlen);
if(!stream->in) {
log_err("doq could not read stream, calloc failed: "
@@ -4092,8 +4104,9 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
/** doq receive data for a stream, more bytes of the incoming data */
static int
-doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
- size_t datalen, int* recv_done, struct doq_table* table)
+doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream,
+ const uint8_t* data, size_t datalen, int* recv_done,
+ struct doq_table* table)
{
int got_data = 0;
/* read the tcplength uint16_t at the start */
@@ -4114,7 +4127,7 @@ doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
if(stream->nread == 2) {
/* the initial length value is completed */
stream->inlen = ntohs(tcplen);
- if(!doq_stream_datalen_complete(stream, table))
+ if(!doq_stream_datalen_complete(conn, stream, table))
return 0;
} else {
/* store for later */
@@ -4331,8 +4344,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
verbose(VERB_ALGO, "doq: stream with this id already exists");
return 0;
}
- if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */
- !doq_table_quic_size_available(doq_conn->doq_socket->table,
+ if(!doq_table_quic_size_available(doq_conn->doq_socket->table,
doq_conn->doq_socket->cfg, sizeof(*stream)
+ 100 /* estimated query in */
+ 512 /* estimated response out */
@@ -4390,8 +4402,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
return 0;
}
if(datalen != 0) {
- if(!doq_stream_recv_data(stream, data, datalen, &recv_done,
- doq_conn->doq_socket->table))
+ if(!doq_stream_recv_data(doq_conn, stream, data, datalen,
+ &recv_done, doq_conn->doq_socket->table))
return NGTCP2_ERR_CALLBACK_FAILURE;
}
if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) {
@@ -24,6 +24,7 @@ SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=master;t
file://CVE-2026-44390.patch \
file://CVE-2026-44608.patch \
file://CVE-2026-46582.patch \
file://CVE-2026-32665.patch \
"
SRCREV = "f6269baa605d31859f28770e01a24e3677e5f82c"