From: Martin Schwenke Date: Wed, 27 May 2026 08:59:24 +0000 (+1000) Subject: CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=80db91e1bfad43e2b875c20b0fbb30443efa8ce2;p=thirdparty%2Fsamba.git CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access Protocol field lengths need to be validated to avoid attempts to access memory beyond the end of the packet buffer. BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085 Reported-by: Tristan Madani Signed-off-by: Martin Schwenke Reviewed-by: Tristan Madani Reviewed-by: Stefan Metzmacher --- diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c index 78ee39015e6..e1de0197175 100644 --- a/ctdb/server/ctdb_call.c +++ b/ctdb/server/ctdb_call.c @@ -583,6 +583,9 @@ static int dmaster_defer_add(struct ctdb_db_context *ctdb_db, void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_req_dmaster_old *c = (struct ctdb_req_dmaster_old *)hdr; + size_t req_dmaster_header_len = offsetof(struct ctdb_req_dmaster_old, + data); + size_t buf_len = hdr->length; TDB_DATA key, data, data2; struct ctdb_ltdb_header header; struct ctdb_db_context *ctdb_db; @@ -590,6 +593,13 @@ void ctdb_request_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr size_t len; int ret; + if (buf_len < req_dmaster_header_len || + c->keylen > buf_len - req_dmaster_header_len || + c->datalen > buf_len - req_dmaster_header_len - c->keylen) { + DBG_WARNING("Invalid packet\n"); + return; + } + key.dptr = c->data; key.dsize = c->keylen; data.dptr = c->data + c->keylen; @@ -917,6 +927,8 @@ sort_keys: void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_req_call_old *c = (struct ctdb_req_call_old *)hdr; + size_t req_call_header_len = offsetof(struct ctdb_req_call_old, data); + size_t buf_len = hdr->length; TDB_DATA data; struct ctdb_reply_call_old *r; int ret, len; @@ -925,6 +937,13 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) struct ctdb_db_context *ctdb_db; int tmp_count, bucket; + if (buf_len < req_call_header_len || + c->keylen > buf_len - req_call_header_len || + c->calldatalen > buf_len - req_call_header_len - c->keylen) { + DBG_WARNING("Invalid packet\n"); + return; + } + if (ctdb->methods == NULL) { DEBUG(DEBUG_INFO,(__location__ " Failed ctdb_request_call. Transport is DOWN\n")); return; @@ -1199,8 +1218,17 @@ void ctdb_request_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) void ctdb_reply_call(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_reply_call_old *c = (struct ctdb_reply_call_old *)hdr; + size_t reply_call_header_len = offsetof(struct ctdb_reply_call_old, + data); + size_t buf_len = hdr->length; struct ctdb_call_state *state; + if (buf_len < reply_call_header_len || + c->datalen > buf_len - reply_call_header_len) { + DBG_WARNING("Invalid packet\n"); + return; + } + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_call_state); if (state == NULL) { DEBUG(DEBUG_ERR, (__location__ " reqid %u not found\n", hdr->reqid)); @@ -1296,12 +1324,22 @@ finished_ro: void ctdb_reply_dmaster(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_reply_dmaster_old *c = (struct ctdb_reply_dmaster_old *)hdr; + size_t reply_dmaster_header_len = offsetof(struct ctdb_reply_dmaster_old, + data); + size_t buf_len = hdr->length; struct ctdb_db_context *ctdb_db; TDB_DATA key, data; uint32_t record_flags = 0; size_t len; int ret; + if (buf_len < reply_dmaster_header_len || + c->keylen > buf_len - reply_dmaster_header_len || + c->datalen > buf_len - reply_dmaster_header_len - c->keylen) { + DBG_WARNING("Invalid packet\n"); + return; + } + ctdb_db = find_ctdb_db(ctdb, c->db_id); if (ctdb_db == NULL) { DEBUG(DEBUG_ERR,("Unknown db_id 0x%x in ctdb_reply_dmaster\n", c->db_id)); diff --git a/ctdb/server/ctdb_client.c b/ctdb/server/ctdb_client.c index c9edb1d554c..84e8e3d2da6 100644 --- a/ctdb/server/ctdb_client.c +++ b/ctdb/server/ctdb_client.c @@ -193,8 +193,17 @@ void ctdb_request_message(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_req_message_old *c = (struct ctdb_req_message_old *)hdr; + size_t req_message_header_len = offsetof(struct ctdb_req_message_old, + data); + size_t buf_len = hdr->length; TDB_DATA data; + if (buf_len < req_message_header_len || + c->datalen > buf_len - req_message_header_len) { + DBG_WARNING("Invalid packet\n"); + return; + } + data.dsize = c->datalen; data.dptr = talloc_memdup(c, &c->data[0], c->datalen); if (data.dptr == NULL) { diff --git a/ctdb/server/ctdb_control.c b/ctdb/server/ctdb_control.c index 00a90774895..3b2ae0e5542 100644 --- a/ctdb/server/ctdb_control.c +++ b/ctdb/server/ctdb_control.c @@ -936,11 +936,20 @@ void ctdb_request_control_reply(struct ctdb_context *ctdb, struct ctdb_req_contr void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_req_control_old *c = (struct ctdb_req_control_old *)hdr; + size_t req_control_header_len = offsetof(struct ctdb_req_control_old, + data); + size_t buf_len = hdr->length; TDB_DATA data, *outdata; int32_t status; bool async_reply = false; const char *errormsg = NULL; + if (buf_len < req_control_header_len || + c->datalen > buf_len - req_control_header_len) { + DBG_WARNING("Invalid packet\n"); + return; + } + data.dptr = &c->data[0]; data.dsize = c->datalen; @@ -960,10 +969,20 @@ void ctdb_request_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr void ctdb_reply_control(struct ctdb_context *ctdb, struct ctdb_req_header *hdr) { struct ctdb_reply_control_old *c = (struct ctdb_reply_control_old *)hdr; + size_t reply_control_header_len = offsetof(struct ctdb_reply_control_old, + data); + size_t buf_len = hdr->length; TDB_DATA data; struct ctdb_control_state *state; const char *errormsg = NULL; + if (buf_len < reply_control_header_len || + c->datalen > buf_len - reply_control_header_len || + c->errorlen > buf_len - reply_control_header_len - c->datalen) { + DBG_WARNING("Invalid packet\n"); + return; + } + state = reqid_find(ctdb->idr, hdr->reqid, struct ctdb_control_state); if (state == NULL) { DEBUG(DEBUG_ERR,("pnn %u Invalid reqid %u in ctdb_reply_control\n",