From 0fa6bb4f3edfbe819ed15555c2c64fd66f3077ad Mon Sep 17 00:00:00 2001
From: Martin Schwenke <mschwenke@ddn.com>
Date: Wed, 10 Jun 2026 12:15:17 +1000
Subject: [PATCH 13/23] CVE-2026-58224: ctdb-protocol: Avoid DoS memory allocations

The pull loop already avoids out of bounds accesses beyond the end of
the buffer.  However, it does not avoid a DoS memory allocation due to
an unreasonably large array size.

Check that the number of specified array elements can be pulled from
buffer, which puts a reasonable upper bound on the subsequent memory
allocation.

Use an initialised dummy variable to avoid static analysers
complaining about uninitialised variables being passed.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085

Reported-by: Andrew Tridgell (issue 22)
Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Tristan Madani <tristan@talencesecurity.com>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
---
 ctdb/protocol/protocol_types.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/ctdb/protocol/protocol_types.c b/ctdb/protocol/protocol_types.c
index 86e1bc3954e..2edf8228d18 100644
--- a/ctdb/protocol/protocol_types.c
+++ b/ctdb/protocol/protocol_types.c
@@ -838,6 +838,7 @@ int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 			      size_t *npull)
 {
 	struct ctdb_statistics_list *val;
+	struct ctdb_statistics dummy = {};
 	size_t offset = 0, np;
 	int ret, i;
 
@@ -863,6 +864,11 @@ int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
+	if ((uint64_t)val->num * ctdb_statistics_len(&dummy) > buflen - offset) {
+		ret = EMSGSIZE;
+		goto fail;
+	}
+
 	val->stats = talloc_array(val, struct ctdb_statistics, val->num);
 	if (val->stats == NULL) {
 		ret = ENOMEM;
@@ -1088,6 +1094,7 @@ int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 		       struct ctdb_dbid_map **out, size_t *npull)
 {
 	struct ctdb_dbid_map *val;
+	struct ctdb_dbid dummy = {};
 	size_t offset = 0, np;
 	uint32_t i;
 	int ret;
@@ -1108,6 +1115,11 @@ int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
+	if ((uint64_t)val->num * ctdb_dbid_len(&dummy) > buflen - offset) {
+		ret = EMSGSIZE;
+		goto fail;
+	}
+
 	val->dbs = talloc_array(val, struct ctdb_dbid, val->num);
 	if (val->dbs == NULL) {
 		ret = ENOMEM;
@@ -3905,6 +3917,7 @@ int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 		       struct ctdb_node_map **out, size_t *npull)
 {
 	struct ctdb_node_map *val;
+	struct ctdb_node_and_flags dummy = {};
 	size_t offset = 0, np;
 	uint32_t i;
 	int ret;
@@ -3925,6 +3938,12 @@ int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
 		goto done;
 	}
 
+	if ((uint64_t)val->num * ctdb_node_and_flags_len(&dummy) >
+	    buflen - offset) {
+		ret = EMSGSIZE;
+		goto fail;
+	}
+
 	val->node = talloc_array(val, struct ctdb_node_and_flags, val->num);
 	if (val->node == NULL) {
 		ret = ENOMEM;
-- 
2.43.0


