Fix CVE-2026-33630: double-free in process_timeouts() in c-ares
Backport upstream commit d823199b688052dcdc1646f2ab4cb8c16b1c644a
to fix CVE-2026-33630, a double-free vulnerability in
process_timeouts() in c-ares 1.34.6. The patch also consolidates
requeue handling in ares_process.c to prevent unbounded recursion.
A new patch (c-ares-1.34.6-CVE-2026-33630.patch) was added as
Patch1 in the spec file.
CVE: CVE-2026-33630
Upstream patches:
- d823199b68.patch
Resolves: RHEL-192867
This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.
Assisted-by: Ymir
This commit is contained in:
parent
f7300ffbb6
commit
6bdf9b6170
472
c-ares-1.34.6-CVE-2026-33630.patch
Normal file
472
c-ares-1.34.6-CVE-2026-33630.patch
Normal file
@ -0,0 +1,472 @@
|
||||
From f1134474ed2b19374556515d6fdd33aae4250125 Mon Sep 17 00:00:00 2001
|
||||
From: Brad House <brad@brad-house.com>
|
||||
Date: Mon, 6 Jul 2026 11:19:36 -0400
|
||||
Subject: [PATCH] [Backport v1.34] Fix double-free in process_timeouts() and
|
||||
consolidate requeue handling (#1237)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Backports the double-free fix (**GHSA-6wfj-rwm7-3542** /
|
||||
**CVE-2026-33630**) and the requeue-recursion fix for #1043 to the
|
||||
`v1.34` release branch.
|
||||
|
||||
Cherry-pick of main commit 1fa3b86a0b8d18fe7b60f3228a01d770feb026bc —
|
||||
applied cleanly (diff identical to main; v1.34 already carried the
|
||||
`requeue`-array infrastructure from the earlier security merge, so this
|
||||
adds the `ares_flush_requeue()` / `ares_send_query_int()` consolidation
|
||||
on top).
|
||||
|
||||
## What it fixes
|
||||
- **Double-free (self-cancellation):** `process_timeouts()` invoked the
|
||||
query callback without first detaching the query from `queries_by_qid` /
|
||||
`all_queries`, so a reentrant `ares_cancel()` from the callback freed
|
||||
the query which was then freed again by the caller. The same
|
||||
self-cancellation double-free was also reachable via `read_answers()`'
|
||||
deferred ENDQUERY flush.
|
||||
- **#1043 stack overflow:** unbounded `ares_requeue_query()` →
|
||||
`ares_send_query()` recursion.
|
||||
|
||||
Both share one root cause — deferred work being done immediately. Every
|
||||
flush site now funnels through `ares_flush_requeue()`, which
|
||||
re-dispatches retries iteratively and fully detaches each query before
|
||||
invoking its callback.
|
||||
|
||||
## Verification
|
||||
- CMake + Ninja Debug build clean, no warnings in `ares_process.c`.
|
||||
- Regression tests pass, including `CancelInCallbackNoDoubleFree` and
|
||||
`NoSocketExplosionOnTimeout` (91 targeted cancel/timeout tests green).
|
||||
|
||||
Target release: **1.34.7**.
|
||||
---
|
||||
src/lib/ares_process.c | 185 ++++++++++++++++++++++++++++++-----------
|
||||
test/ares-test-mock.cc | 111 +++++++++++++++++++++++++
|
||||
2 files changed, 248 insertions(+), 48 deletions(-)
|
||||
|
||||
diff --git a/src/lib/ares_process.c b/src/lib/ares_process.c
|
||||
index 93529684..cafc05bd 100644
|
||||
--- a/src/lib/ares_process.c
|
||||
+++ b/src/lib/ares_process.c
|
||||
@@ -66,6 +66,11 @@ static void end_query(ares_channel_t *channel, ares_server_t *server,
|
||||
ares_query_t *query, ares_status_t status,
|
||||
ares_dns_record_t *dnsrec,
|
||||
ares_array_t **requeue);
|
||||
+static ares_status_t ares_send_query_int(ares_server_t *requested_server,
|
||||
+ ares_query_t *query,
|
||||
+ const ares_timeval_t *now,
|
||||
+ ares_array_t **requeue);
|
||||
+static void ares_detach_query(ares_query_t *query);
|
||||
|
||||
static void ares_query_remove_from_conn(ares_query_t *query)
|
||||
{
|
||||
@@ -573,6 +578,79 @@ static ares_status_t ares_append_endqueue(ares_array_t **requeue,
|
||||
dnsrec);
|
||||
}
|
||||
|
||||
+/* Drain the deferred requeue/endqueue list iteratively. All flush sites
|
||||
+ * (read_answers(), process_timeouts(), and ares_send_query()) funnel through
|
||||
+ * here so that:
|
||||
+ * 1. Retries are re-dispatched by appending to this same list and looping,
|
||||
+ * rather than recursing ares_requeue_query() -> ares_send_query() until
|
||||
+ * the stack is exhausted (issue #1043).
|
||||
+ * 2. A query is fully detached from all lookup lists before its callback is
|
||||
+ * invoked, so a reentrant ares_cancel() from within that callback cannot
|
||||
+ * find and free the same query, which would otherwise double-free it
|
||||
+ * (CVE-2026-33630 / GHSA-6wfj-rwm7-3542).
|
||||
+ *
|
||||
+ * On return the list has been fully processed, an empty-queue notification has
|
||||
+ * been sent if appropriate, and *requeue has been destroyed and set to NULL. */
|
||||
+static ares_status_t ares_flush_requeue(ares_channel_t *channel,
|
||||
+ const ares_timeval_t *now,
|
||||
+ ares_array_t **requeue)
|
||||
+{
|
||||
+ ares_status_t status = ARES_SUCCESS;
|
||||
+
|
||||
+ if (requeue == NULL) {
|
||||
+ return status;
|
||||
+ }
|
||||
+
|
||||
+ while (*requeue != NULL && ares_array_len(*requeue) > 0) {
|
||||
+ ares_query_t *query;
|
||||
+ ares_requeue_t entry;
|
||||
+ ares_status_t internal_status;
|
||||
+
|
||||
+ internal_status = ares_array_claim_at(&entry, sizeof(entry), *requeue, 0);
|
||||
+ if (internal_status != ARES_SUCCESS) {
|
||||
+ break; /* LCOV_EXCL_LINE: DefensiveCoding */
|
||||
+ }
|
||||
+
|
||||
+ query = ares_htable_szvp_get_direct(channel->queries_by_qid, entry.qid);
|
||||
+
|
||||
+ if (entry.type == REQUEUE_REQUEUE) {
|
||||
+ /* Query disappeared (e.g. a prior callback in this drain cancelled it) */
|
||||
+ if (query == NULL) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Re-dispatch via the internal entrypoint so any further requeues are
|
||||
+ * appended back onto this same list and drained by the loop above,
|
||||
+ * rather than recursing. */
|
||||
+ internal_status = ares_send_query_int(entry.server, query, now, requeue);
|
||||
+ /* We only care about ARES_ENOMEM */
|
||||
+ if (internal_status == ARES_ENOMEM) {
|
||||
+ status = ARES_ENOMEM;
|
||||
+ }
|
||||
+ } else { /* REQUEUE_ENDQUERY */
|
||||
+ if (query != NULL) {
|
||||
+ /* Detach the query from all lookup lists BEFORE invoking the callback.
|
||||
+ * Otherwise a reentrant ares_cancel() from within the callback would
|
||||
+ * find this query still linked in all_queries/queries_by_qid, free it,
|
||||
+ * and the ares_free_query() below would then double-free it. */
|
||||
+ ares_detach_query(query);
|
||||
+ query->callback(query->arg, entry.status, query->timeouts,
|
||||
+ entry.dnsrec);
|
||||
+ ares_free_query(query);
|
||||
+ }
|
||||
+ ares_dns_record_destroy(entry.dnsrec);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Don't forget to send notification if queue emptied */
|
||||
+ if (*requeue != NULL) {
|
||||
+ ares_queue_notify_empty(channel);
|
||||
+ }
|
||||
+ ares_array_destroy(*requeue);
|
||||
+ *requeue = NULL;
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
static ares_status_t read_answers(ares_conn_t *conn, const ares_timeval_t *now)
|
||||
{
|
||||
ares_status_t status;
|
||||
@@ -625,43 +703,11 @@ static ares_status_t read_answers(ares_conn_t *conn, const ares_timeval_t *now)
|
||||
}
|
||||
|
||||
cleanup:
|
||||
-
|
||||
- /* Flush requeue */
|
||||
- while (ares_array_len(requeue) > 0) {
|
||||
- ares_query_t *query;
|
||||
- ares_requeue_t entry;
|
||||
- ares_status_t internal_status;
|
||||
-
|
||||
- internal_status = ares_array_claim_at(&entry, sizeof(entry), requeue, 0);
|
||||
- if (internal_status != ARES_SUCCESS) {
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- query = ares_htable_szvp_get_direct(channel->queries_by_qid, entry.qid);
|
||||
-
|
||||
- if (entry.type == REQUEUE_REQUEUE) {
|
||||
- /* query disappeared */
|
||||
- if (query == NULL) {
|
||||
- continue;
|
||||
- }
|
||||
- internal_status = ares_send_query(entry.server, query, now);
|
||||
- /* We only care about ARES_ENOMEM */
|
||||
- if (internal_status == ARES_ENOMEM) {
|
||||
- status = ARES_ENOMEM;
|
||||
- }
|
||||
- } else { /* REQUEUE_ENDQUERY */
|
||||
- if (query != NULL) {
|
||||
- query->callback(query->arg, entry.status, query->timeouts, entry.dnsrec);
|
||||
- ares_free_query(query);
|
||||
- }
|
||||
- ares_dns_record_destroy(entry.dnsrec);
|
||||
- }
|
||||
- }
|
||||
- /* Don't forget to send notification if queue emptied */
|
||||
- if (requeue != NULL) {
|
||||
- ares_queue_notify_empty(channel);
|
||||
+ /* Flush requeue - re-dispatch retries and invoke deferred callbacks
|
||||
+ * iteratively and safely */
|
||||
+ if (ares_flush_requeue(channel, now, &requeue) == ARES_ENOMEM) {
|
||||
+ status = ARES_ENOMEM;
|
||||
}
|
||||
- ares_array_destroy(requeue);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -696,7 +742,8 @@ static ares_status_t process_timeouts(ares_channel_t *channel,
|
||||
const ares_timeval_t *now)
|
||||
{
|
||||
ares_slist_node_t *node;
|
||||
- ares_status_t status = ARES_SUCCESS;
|
||||
+ ares_status_t status = ARES_SUCCESS;
|
||||
+ ares_array_t *requeue = NULL;
|
||||
|
||||
/* Just keep popping off the first as this list will re-sort as things come
|
||||
* and go. We don't want to try to rely on 'next' as some operation might
|
||||
@@ -715,13 +762,19 @@ static ares_status_t process_timeouts(ares_channel_t *channel,
|
||||
|
||||
conn = query->conn;
|
||||
server_increment_failures(conn->server, query->using_tcp);
|
||||
- status = ares_requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL,
|
||||
- NULL);
|
||||
+ status =
|
||||
+ ares_requeue_query(query, now, ARES_ETIMEOUT, ARES_TRUE, NULL, &requeue);
|
||||
if (status == ARES_ENOMEM) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:
|
||||
+ /* Flush requeue - re-dispatch retries and invoke deferred callbacks
|
||||
+ * iteratively and safely */
|
||||
+ if (ares_flush_requeue(channel, now, &requeue) == ARES_ENOMEM) {
|
||||
+ status = ARES_ENOMEM;
|
||||
+ }
|
||||
+
|
||||
if (status == ARES_ENOMEM) {
|
||||
return ARES_ENOMEM;
|
||||
}
|
||||
@@ -871,7 +924,7 @@ static ares_status_t process_answer(ares_channel_t *channel,
|
||||
if (issue_might_be_edns(query->query, rdnsrec)) {
|
||||
status = rewrite_without_edns(query);
|
||||
if (status != ARES_SUCCESS) {
|
||||
- end_query(channel, server, query, status, NULL, NULL);
|
||||
+ end_query(channel, server, query, status, NULL, requeue);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1262,8 +1315,44 @@ static ares_status_t ares_conn_query_write(ares_conn_t *conn,
|
||||
return ares_conn_flush(conn);
|
||||
}
|
||||
|
||||
+/* Public entrypoint. Establishes a requeue list and drives
|
||||
+ * ares_send_query_int() plus any retries/deferred callbacks it produces
|
||||
+ * iteratively, so a chain of retryable failures can never recurse until the
|
||||
+ * stack is exhausted (#1043). */
|
||||
ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
ares_query_t *query, const ares_timeval_t *now)
|
||||
+{
|
||||
+ ares_channel_t *channel = query->channel;
|
||||
+ ares_array_t *requeue = NULL;
|
||||
+ unsigned short qid = query->qid;
|
||||
+ ares_status_t status;
|
||||
+
|
||||
+ status = ares_send_query_int(requested_server, query, now, &requeue);
|
||||
+
|
||||
+ /* Drain any retries/deferred callbacks this send produced.
|
||||
+ * ares_flush_requeue() always fully processes and destroys the list (even on
|
||||
+ * ENOMEM), and sends the empty-queue notification if needed. */
|
||||
+ if (ares_flush_requeue(channel, now, &requeue) == ARES_ENOMEM) {
|
||||
+ status = ARES_ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ /* A retry may have been deferred (returning ARES_SUCCESS from the append)
|
||||
+ * and then terminally failed while draining, in which case the query has
|
||||
+ * been freed. Do not dereference 'query' here. If it is no longer tracked
|
||||
+ * it ended, so don't report success to the caller (which would, e.g., cause
|
||||
+ * ares_send_nolock() to write to a now-freed *qid). */
|
||||
+ if (status == ARES_SUCCESS &&
|
||||
+ ares_htable_szvp_get_direct(channel->queries_by_qid, qid) == NULL) {
|
||||
+ status = ARES_ETIMEOUT;
|
||||
+ }
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+static ares_status_t ares_send_query_int(ares_server_t *requested_server,
|
||||
+ ares_query_t *query,
|
||||
+ const ares_timeval_t *now,
|
||||
+ ares_array_t **requeue)
|
||||
{
|
||||
ares_channel_t *channel = query->channel;
|
||||
ares_server_t *server;
|
||||
@@ -1286,7 +1375,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
}
|
||||
|
||||
if (server == NULL) {
|
||||
- end_query(channel, server, query, ARES_ENOSERVER /* ? */, NULL, NULL);
|
||||
+ end_query(channel, server, query, ARES_ENOSERVER /* ? */, NULL, requeue);
|
||||
return ARES_ENOSERVER;
|
||||
}
|
||||
|
||||
@@ -1310,11 +1399,11 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
case ARES_ECONNREFUSED:
|
||||
case ARES_EBADFAMILY:
|
||||
server_increment_failures(server, query->using_tcp);
|
||||
- return ares_requeue_query(query, now, status, ARES_TRUE, NULL, NULL);
|
||||
+ return ares_requeue_query(query, now, status, ARES_TRUE, NULL, requeue);
|
||||
|
||||
/* Anything else is not retryable, likely ENOMEM */
|
||||
default:
|
||||
- end_query(channel, server, query, status, NULL, NULL);
|
||||
+ end_query(channel, server, query, status, NULL, requeue);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@@ -1328,7 +1417,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
|
||||
case ARES_ENOMEM:
|
||||
/* Not retryable */
|
||||
- end_query(channel, server, query, status, NULL, NULL);
|
||||
+ end_query(channel, server, query, status, NULL, requeue);
|
||||
return status;
|
||||
|
||||
/* These conditions are retryable as they are server-specific
|
||||
@@ -1336,7 +1425,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
case ARES_ECONNREFUSED:
|
||||
case ARES_EBADFAMILY:
|
||||
handle_conn_error(conn, ARES_TRUE, status);
|
||||
- status = ares_requeue_query(query, now, status, ARES_TRUE, NULL, NULL);
|
||||
+ status = ares_requeue_query(query, now, status, ARES_TRUE, NULL, requeue);
|
||||
if (status == ARES_ETIMEOUT) {
|
||||
status = ARES_ECONNREFUSED;
|
||||
}
|
||||
@@ -1344,7 +1433,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
|
||||
default:
|
||||
server_increment_failures(server, query->using_tcp);
|
||||
- status = ares_requeue_query(query, now, status, ARES_TRUE, NULL, NULL);
|
||||
+ status = ares_requeue_query(query, now, status, ARES_TRUE, NULL, requeue);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1360,7 +1449,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
ares_slist_insert(channel->queries_by_timeout, query);
|
||||
if (!query->node_queries_by_timeout) {
|
||||
/* LCOV_EXCL_START: OutOfMemory */
|
||||
- end_query(channel, server, query, ARES_ENOMEM, NULL, NULL);
|
||||
+ end_query(channel, server, query, ARES_ENOMEM, NULL, requeue);
|
||||
return ARES_ENOMEM;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
@@ -1373,7 +1462,7 @@ ares_status_t ares_send_query(ares_server_t *requested_server,
|
||||
|
||||
if (query->node_queries_to_conn == NULL) {
|
||||
/* LCOV_EXCL_START: OutOfMemory */
|
||||
- end_query(channel, server, query, ARES_ENOMEM, NULL, NULL);
|
||||
+ end_query(channel, server, query, ARES_ENOMEM, NULL, requeue);
|
||||
return ARES_ENOMEM;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
diff --git a/test/ares-test-mock.cc b/test/ares-test-mock.cc
|
||||
index 4b60eee8..35789e17 100644
|
||||
--- a/test/ares-test-mock.cc
|
||||
+++ b/test/ares-test-mock.cc
|
||||
@@ -1722,6 +1722,115 @@ TEST_P(MockUDPChannelTest, TriggerResendThenConnFailEDNS) {
|
||||
EXPECT_EQ("{'www.google.com' aliases=[] addrs=[1.2.3.4]}", ss.str());
|
||||
}
|
||||
|
||||
+// Regression for issue #1043: a long chain of retryable connection failures
|
||||
+// used to recurse ares_requeue_query() -> ares_send_query() until the stack was
|
||||
+// exhausted. With a very high retry count and a socket that always fails to be
|
||||
+// created (a retryable ARES_ECONNREFUSED), the retries must be processed
|
||||
+// iteratively and the query must terminate cleanly rather than crashing.
|
||||
+class MockRetryDepthChannelTest : public MockChannelOptsTest,
|
||||
+ public ::testing::WithParamInterface<int> {
|
||||
+public:
|
||||
+ MockRetryDepthChannelTest()
|
||||
+ : MockChannelOptsTest(1, GetParam(), false, false, FillOptions(&opts_),
|
||||
+ ARES_OPT_TRIES)
|
||||
+ {
|
||||
+ }
|
||||
+
|
||||
+ static struct ares_options *FillOptions(struct ares_options *opts)
|
||||
+ {
|
||||
+ memset(opts, 0, sizeof(struct ares_options));
|
||||
+ /* Large enough that the old recursive path would overflow the stack. */
|
||||
+ opts->tries = 100000;
|
||||
+ return opts;
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ struct ares_options opts_;
|
||||
+};
|
||||
+
|
||||
+static size_t g_always_fail_socket_calls = 0;
|
||||
+
|
||||
+static ares_socket_t always_fail_socket(int af, int type, int protocol,
|
||||
+ void *user_data)
|
||||
+{
|
||||
+ (void)af;
|
||||
+ (void)type;
|
||||
+ (void)protocol;
|
||||
+ (void)user_data;
|
||||
+ g_always_fail_socket_calls++;
|
||||
+ return ARES_SOCKET_BAD;
|
||||
+}
|
||||
+
|
||||
+TEST_P(MockRetryDepthChannelTest, HighRetryNoStackOverflow) {
|
||||
+ ares_socket_functions sock_funcs;
|
||||
+ memset(&sock_funcs, 0, sizeof(sock_funcs));
|
||||
+ sock_funcs.asocket = always_fail_socket;
|
||||
+ ares_set_socket_functions(channel_, &sock_funcs, NULL);
|
||||
+
|
||||
+ g_always_fail_socket_calls = 0;
|
||||
+
|
||||
+ QueryResult result;
|
||||
+ ares_query_dnsrec(channel_, "www.google.com", ARES_CLASS_IN, ARES_REC_TYPE_A,
|
||||
+ QueryCallback, &result, NULL);
|
||||
+ Process();
|
||||
+
|
||||
+ /* If the retries didn't drive the query to a terminal state on their own
|
||||
+ * (e.g. it parked awaiting a response that will never arrive), cancel it so
|
||||
+ * the query terminates deterministically. */
|
||||
+ if (!result.done_) {
|
||||
+ ares_cancel(channel_);
|
||||
+ Process();
|
||||
+ }
|
||||
+
|
||||
+ /* The essential property is that we reached this point at all: on unpatched
|
||||
+ * code the retryable failures recursed ares_requeue_query()/ares_send_query()
|
||||
+ * until the stack overflowed and the process aborted before getting here. We
|
||||
+ * also confirm the retries were attempted iteratively (more than one socket
|
||||
+ * creation) and that the query reached a terminal state. */
|
||||
+ EXPECT_GT(g_always_fail_socket_calls, (size_t)1);
|
||||
+ EXPECT_TRUE(result.done_);
|
||||
+}
|
||||
+
|
||||
+// Regression for CVE-2026-33630 / GHSA-6wfj-rwm7-3542: invoking ares_cancel()
|
||||
+// from within a normal response callback must not double-free the query. The
|
||||
+// callback is dispatched from the read_answers() deferred-requeue flush, and the
|
||||
+// query must be detached from all lookup lists before the callback runs so that
|
||||
+// the reentrant ares_cancel() cannot find and free it a second time.
|
||||
+struct CancelInCbData {
|
||||
+ ares_channel_t *channel;
|
||||
+ bool done;
|
||||
+};
|
||||
+
|
||||
+static void CancelChannelCallback(void *arg, ares_status_t status,
|
||||
+ size_t timeouts,
|
||||
+ const ares_dns_record_t *dnsrec)
|
||||
+{
|
||||
+ CancelInCbData *data = static_cast<CancelInCbData *>(arg);
|
||||
+ (void)status;
|
||||
+ (void)timeouts;
|
||||
+ (void)dnsrec;
|
||||
+ data->done = true;
|
||||
+ /* Reentrant cancel from within the callback. Must not double-free. */
|
||||
+ ares_cancel(data->channel);
|
||||
+}
|
||||
+
|
||||
+TEST_P(MockUDPChannelTest, CancelInCallbackNoDoubleFree) {
|
||||
+ DNSPacket reply;
|
||||
+ reply.set_response().set_aa()
|
||||
+ .add_question(new DNSQuestion("www.google.com", T_A))
|
||||
+ .add_answer(new DNSARR("www.google.com", 0x0100, {0x01, 0x02, 0x03, 0x04}));
|
||||
+ ON_CALL(server_, OnRequest("www.google.com", T_A))
|
||||
+ .WillByDefault(SetReply(&server_, &reply));
|
||||
+
|
||||
+ CancelInCbData data;
|
||||
+ data.channel = channel_;
|
||||
+ data.done = false;
|
||||
+ ares_query_dnsrec(channel_, "www.google.com", ARES_CLASS_IN, ARES_REC_TYPE_A,
|
||||
+ CancelChannelCallback, &data, NULL);
|
||||
+ Process();
|
||||
+ EXPECT_TRUE(data.done);
|
||||
+}
|
||||
+
|
||||
TEST_P(MockUDPChannelTest, GetSock) {
|
||||
DNSPacket reply;
|
||||
reply.set_response().set_aa()
|
||||
@@ -2573,6 +2682,8 @@ INSTANTIATE_TEST_SUITE_P(AddressFamilies, ContainedMockChannelSysConfig, ::testi
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AddressFamilies, MockUDPChannelTest, ::testing::ValuesIn(ares::test::families), PrintFamily);
|
||||
|
||||
+INSTANTIATE_TEST_SUITE_P(AddressFamilies, MockRetryDepthChannelTest, ::testing::ValuesIn(ares::test::families), PrintFamily);
|
||||
+
|
||||
INSTANTIATE_TEST_SUITE_P(AddressFamilies, MockUDPMaxQueriesTest, ::testing::ValuesIn(ares::test::families), PrintFamily);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AddressFamilies, CacheQueriesTest, ::testing::ValuesIn(ares::test::families), PrintFamily);
|
||||
@ -3,11 +3,13 @@
|
||||
Summary: A library that performs asynchronous DNS operations
|
||||
Name: c-ares
|
||||
Version: 1.34.6
|
||||
Release: 1%{?dist}
|
||||
Release: 3%{?dist}
|
||||
License: MIT
|
||||
URL: http://c-ares.org/
|
||||
Source0: https://github.com/c-ares/c-ares/releases/download/v%{version}/c-ares-%{version}.tar.gz
|
||||
#Patch0: 0001-Merge-pull-request-from-GHSA-mg26-v6qh-x48q.patch
|
||||
# https://github.com/c-ares/c-ares/commit/d823199b688052dcdc1646f2ab4cb8c16b1c644a
|
||||
Patch1: c-ares-1.34.6-CVE-2026-33630.patch
|
||||
BuildRequires: gcc
|
||||
%if %{use_cmake}
|
||||
BuildRequires: cmake
|
||||
@ -79,6 +81,10 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libcares.la
|
||||
%{_mandir}/man3/ares_*
|
||||
|
||||
%changelog
|
||||
* Wed Jul 22 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.34.6-3
|
||||
- Fix double-free in process_timeouts() (CVE-2026-33630)
|
||||
Resolves: RHEL-192867
|
||||
|
||||
* Tue Dec 09 2025 Alejandro López <allopez@redhat.com> - 1.34.6-1
|
||||
- Update to 1.34.6
|
||||
Resolves: RHEL-103761
|
||||
|
||||
Loading…
Reference in New Issue
Block a user