]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access
authorMartin Schwenke <mschwenke@ddn.com>
Wed, 27 May 2026 08:59:24 +0000 (18:59 +1000)
committerBjoern Jacke <bjacke@samba.org>
Tue, 28 Jul 2026 15:56:37 +0000 (15:56 +0000)
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 <tristan@talencesecurity.com>
Signed-off-by: Martin Schwenke <mschwenke@ddn.com>
Reviewed-by: Tristan Madani <tristan@talencesecurity.com>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
ctdb/server/ctdb_call.c
ctdb/server/ctdb_client.c
ctdb/server/ctdb_control.c

index 78ee39015e61e3c2a08b73314b2fbf1ff56daa68..e1de0197175c03905d95b9594636805d5fc56bd3 100644 (file)
@@ -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));
index c9edb1d554cc04ec442038d76ba584f0d8c627c2..84e8e3d2da6ce368a53e667c5900624657c95da6 100644 (file)
@@ -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) {
index 00a907748955e801549fdc77d9aa02e73c037132..3b2ae0e55421d44956e3aa0f6632e58915478774 100644 (file)
@@ -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",