[Pkg-samba-maint] Bug#1142942: trixie-pu: package samba/1:4.22.11+dfsg-0+deb13u1
Michael Tokarev
mjt at tls.msk.ru
Tue Jul 28 13:26:18 BST 2026
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: samba at packages.debian.org
Control: affects -1 + src:samba
User: release.debian.org at packages.debian.org
Usertags: pu
[ Reason ]
Previous samba security fixes were made through trixie-security
as a patchset for the current-at-the-time samba release in
trixie. With the upstream announce, there's actual new upstream
release is available, which incorporates all the fixes and has
an additional fix.
To avoid confusion, it is best to syncronize with the actual
upstream source and drop the security patches.
[ Tests ]
Since this release is just a syncronization with the upstream
tarball, producing basically the same source in the end (modulo
the WHATSNEW.txt changes, version bump and an additional fix),
it's essentally the same as before, so there's no much testing
necessary. It works at least as best as the previous release
plus the secrity patchset on top (already running it in production
locally).
[ Risks ]
The risk this time is really minimal.
[ Checklist ]
[x] *all* changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in (old)stable
[x] the issue is verified as fixed in unstable
[ Changes ]
The d/changelog difference, which is rather small, is below.
The bulk of the debdiff consists of the removal of the big
security patchset and applying it to the orig.tar.xz. The
actual code difference leads to WHATSNEW.txt changes, the
version bump, and a single additional fix in
libcli/security/security_descriptor.c.
Here's how the diffstat of the differences between the extracted
source dirs looks like:
4.22.10/.pc/2026-jul-sec-update-bug-16039-v4-22-combined.patch |only
4.22.10/debian/patches/2026-jul-sec-update-bug-16039-v4-22-combined.patch |only
4.22.11/.pc/applied-patches | 1
4.22.11/VERSION | 2
4.22.11/WHATSNEW.txt | 111 +++++++++++++++++++++++++++++++++++-
4.22.11/debian/changelog | 13 ++++
4.22.11/debian/patches/series | 1
4.22.11/libcli/security/security_descriptor.c | 15 +---
8 files changed, 127 insertions(+), 16 deletions(-)
[ Other Info ]
I'm uploading the new debian release into the archive together
with filing this bug report, to save a round-trip - since the
resulting changes are really minimal.
Thanks,
/mjt
diff -Nru samba-4.22.10+dfsg/debian/changelog samba-4.22.11+dfsg/debian/changelog
--- samba-4.22.10+dfsg/debian/changelog 2026-07-24 16:14:13.000000000 +0300
+++ samba-4.22.11+dfsg/debian/changelog 2026-07-28 15:02:03.000000000 +0300
@@ -1,3 +1,16 @@
+samba (2:4.22.11+dfsg-0+deb13u1) trixie; urgency=medium
+
+ * switch to actual new upstream release, dropping the security
+ patchset (it is included into the upstream tarball now).
+
+ Besides all the security fixes, there's an addtional fix in
+ this release (which was queued before the security fixes):
+
+ o libsecurity: Fix security_acl_dup()'s talloc hierarchy
+ Bug: https://bugzilla.samba.org/show_bug.cgi?id=16095
+
+ -- Michael Tokarev <mjt at tls.msk.ru> Tue, 28 Jul 2026 15:02:03 +0300
+
samba (2:4.22.10+dfsg-0+deb13u2) trixie-security; urgency=medium
* 2026-jul-sec-update-bug-16039-v4-22-combined.patch:
diff -Nru samba-4.22.10+dfsg/debian/patches/2026-jul-sec-update-bug-16039-v4-22-combined.patch samba-4.22.11+dfsg/debian/patches/2026-jul-sec-update-bug-16039-v4-22-combined.patch
--- samba-4.22.10+dfsg/debian/patches/2026-jul-sec-update-bug-16039-v4-22-combined.patch 2026-07-24 16:03:05.000000000 +0300
+++ samba-4.22.11+dfsg/debian/patches/2026-jul-sec-update-bug-16039-v4-22-combined.patch 1970-01-01 03:00:00.000000000 +0300
@@ -1,1960 +0,0 @@
-Date: Wed, 15 Jul 2026 18:42:00 +0000
-From: Björn Jacke <bjacke at samba.org>
-Subject: July 2026 samba security fixes for v4.22
-Origin: upstream, https://bugzilla.samba.org/show_bug.cgi?id=16039
-Forwarded: not-needed
-
-From ea7530366da502e0a116467e4565304603eba5b1 Mon Sep 17 00:00:00 2001
-From: Stefan Metzmacher <metze at samba.org>
-Date: Fri, 29 May 2026 12:43:13 +0200
-Subject: [PATCH 01/23] CVE-2026-6949: ndr_dns: let ndr_pull_dns_res_rec()
- remember the start offset
-
-In order to verify TSIG signatures we need a reliable way to
-truncate the original dns_name_packet buffer before the
-last additional dns_res_rec.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16083
-
-Signed-off-by: Stefan Metzmacher <metze at samba.org>
-Reviewed-by: Douglas Bagnall <dbagnall at samba.org>
----
- librpc/idl/dns.idl | 6 ++++++
- librpc/ndr/ndr_dns.c | 11 +++++++++++
- .../librpc/tests/dns-decode_dns_name_packet-hex.txt | 1 +
- 3 files changed, 18 insertions(+)
-
-diff --git a/librpc/idl/dns.idl b/librpc/idl/dns.idl
-index ec8668aa212..7cb316b2b12 100644
---- a/librpc/idl/dns.idl
-+++ b/librpc/idl/dns.idl
-@@ -251,6 +251,12 @@ interface dns
- } dns_rdata;
-
- typedef [flag(LIBNDR_PRINT_ARRAY_HEX|NDR_NOALIGN),nopush,nopull] struct {
-+ /*
-+ * This is the start offset of this
-+ * dns_res_rec relative to the start of
-+ * dns_name_packet buffer.
-+ */
-+ [ignore] uint32 start_ndr_offset;
- dns_string name;
- dns_qtype rr_type;
- dns_qclass rr_class;
-diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
-index 9cc54c1a972..f1de40fd7e8 100644
---- a/librpc/ndr/ndr_dns.c
-+++ b/librpc/ndr/ndr_dns.c
-@@ -276,6 +276,17 @@ _PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr,
- ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
- LIBNDR_FLAG_NOALIGN);
- if (ndr_flags & NDR_SCALARS) {
-+ /*
-+ * Remember the start offset in order
-+ * to know how to truncate before the
-+ * last dns_res_rec in order to do
-+ * the correct TSIG calculation.
-+ *
-+ * Note that we just set LIBNDR_FLAG_NOALIGN
-+ * above, so ndr_pull_align is a no-op.
-+ */
-+ r->start_ndr_offset = ndr->offset;
-+
- NDR_CHECK(ndr_pull_align(ndr, 4));
- NDR_CHECK(ndr_pull_dns_string(ndr, NDR_SCALARS, &r->name));
- NDR_CHECK(ndr_pull_dns_qtype(ndr, NDR_SCALARS, &r->rr_type));
-diff --git a/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt b/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt
-index 84b55f2d362..ccc29c062f2 100644
---- a/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt
-+++ b/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt
-@@ -21,6 +21,7 @@ pull returned Success
- answers: ARRAY(0)
- nsrecs: ARRAY(1)
- nsrecs: struct dns_res_rec
-+ start_ndr_offset : 0x00000027 (39)
- name : 'cnamedotprefix0.samba2003.example.com'
- rr_type : DNS_QTYPE_CNAME (0x5)
- rr_class : DNS_QCLASS_IN (0x1)
---
-2.43.0
-
-
-From f7f4d096aedb236ccf026ed3c59c7538e5303830 Mon Sep 17 00:00:00 2001
-From: Stefan Metzmacher <metze at samba.org>
-Date: Fri, 29 May 2026 13:12:20 +0200
-Subject: [PATCH 02/23] CVE-2026-6949: s4:dns_server: correctly truncate the
- buffer for TSIG verification
-
-Calculating the length of the TSIG additional dns_res_rec,
-via ndr_push_dns_res_rec() is fragile and may generate
-a buffer larger than the original dns_name_packet buffer.
-
-This could underflow the resulting packet_len,
-to a very large value and buffer_len to a small value.
-
-Resulting in a memcpy() of a very large size into
-a very small buffer. This most likely already
-gets a segmentation fault when reading after the
-in->data.
-
-This was reported by Arjun Basnet with Securin Labs.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16083
-
-Signed-off-by: Stefan Metzmacher <metze at samba.org>
-Reviewed-by: Douglas Bagnall <dbagnall at samba.org>
----
- source4/dns_server/dns_crypto.c | 44 ++++++++++++++++++++++++---------
- 1 file changed, 32 insertions(+), 12 deletions(-)
-
-diff --git a/source4/dns_server/dns_crypto.c b/source4/dns_server/dns_crypto.c
-index d30e9715086..722213bfd0a 100644
---- a/source4/dns_server/dns_crypto.c
-+++ b/source4/dns_server/dns_crypto.c
-@@ -36,6 +36,8 @@ static WERROR dns_copy_tsig(TALLOC_CTX *mem_ctx,
- struct dns_res_rec *old,
- struct dns_res_rec *new_rec)
- {
-+ new_rec->start_ndr_offset = 0;
-+
- new_rec->name = talloc_strdup(mem_ctx, old->name);
- W_ERROR_HAVE_NO_MEMORY(new_rec->name);
-
-@@ -101,7 +103,7 @@ WERROR dns_verify_tsig(struct dns_server *dns,
- NTSTATUS status;
- enum ndr_err_code ndr_err;
- uint16_t i, arcount = 0;
-- DATA_BLOB tsig_blob, fake_tsig_blob, sig;
-+ DATA_BLOB fake_tsig_blob, sig;
- uint8_t *buffer = NULL;
- size_t buffer_len = 0, packet_len = 0;
- struct dns_server_tkey *tkey = NULL;
-@@ -131,6 +133,22 @@ WERROR dns_verify_tsig(struct dns_server *dns,
- state->sign = true;
- DBG_DEBUG("Got TSIG\n");
-
-+ /*
-+ * We need to keep the input packet exactly like we got it,
-+ * but we need to cut off the tsig record.
-+ *
-+ * DNS packets can not be larger than UINT16_MAX,
-+ * the size of the UDP payload is uint16_t and
-+ * there's a uint16_t length header for TCP.
-+ *
-+ * And the start offset of the last
-+ * additional record can't be larger than
-+ * the whole packet.
-+ */
-+ packet_len = packet->additional[i].start_ndr_offset;
-+ SMB_ASSERT(in->length <= UINT16_MAX);
-+ SMB_ASSERT(in->length > packet_len);
-+
- state->tsig = talloc_zero(state->mem_ctx, struct dns_res_rec);
- if (state->tsig == NULL) {
- return WERR_NOT_ENOUGH_MEMORY;
-@@ -205,14 +223,6 @@ WERROR dns_verify_tsig(struct dns_server *dns,
- check_rec->other_size = 0;
- check_rec->other_data = NULL;
-
-- ndr_err = ndr_push_struct_blob(&tsig_blob, mem_ctx, state->tsig,
-- (ndr_push_flags_fn_t)ndr_push_dns_res_rec);
-- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-- DEBUG(1, ("Failed to push packet: %s!\n",
-- ndr_errstr(ndr_err)));
-- return DNS_ERR(SERVER_FAILURE);
-- }
--
- ndr_err = ndr_push_struct_blob(&fake_tsig_blob, mem_ctx, check_rec,
- (ndr_push_flags_fn_t)ndr_push_dns_fake_tsig_rec);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-@@ -221,9 +231,19 @@ WERROR dns_verify_tsig(struct dns_server *dns,
- return DNS_ERR(SERVER_FAILURE);
- }
-
-- /* we need to work some magic here. we need to keep the input packet
-- * exactly like we got it, but we need to cut off the tsig record */
-- packet_len = in->length - tsig_blob.length;
-+ /*
-+ * We already asserted packet_len < UINT16_MAX
-+ * above, and struct ndr_push has alloc_size and
-+ * offset as uint32_t, so it's really unlikely
-+ * to overflow buffer_len. For SIZE_MAX == UINT32_MAX,
-+ * the following check might be important, but
-+ * just lets do it always.
-+ */
-+ if (fake_tsig_blob.length > (SIZE_MAX - UINT16_MAX)) {
-+ DBG_WARNING("fake_tsig_blob.length=%zu too large!\n",
-+ fake_tsig_blob.length);
-+ return DNS_ERR(SERVER_FAILURE);
-+ }
- buffer_len = packet_len + fake_tsig_blob.length;
- buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len);
- if (buffer == NULL) {
---
-2.43.0
-
-
-From f252a17bc8ae7568943b0f4cf526d1f8555d6429 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Wed, 27 May 2026 18:59:24 +1000
-Subject: [PATCH 03/23] 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 <tristan at talencesecurity.com>
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_call.c | 38 ++++++++++++++++++++++++++++++++++++++
- ctdb/server/ctdb_client.c | 9 +++++++++
- ctdb/server/ctdb_control.c | 19 +++++++++++++++++++
- 3 files changed, 66 insertions(+)
-
-diff --git a/ctdb/server/ctdb_call.c b/ctdb/server/ctdb_call.c
-index a51a92d3e45..cfeca78061c 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 a51795f340a..cfd80330c41 100644
---- a/ctdb/server/ctdb_control.c
-+++ b/ctdb/server/ctdb_control.c
-@@ -933,11 +933,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;
-
-@@ -957,10 +966,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",
---
-2.43.0
-
-
-From 38a62cf5f72495b99f10b74339c6f895504469aa Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Sat, 30 May 2026 14:38:02 +1000
-Subject: [PATCH 04/23] CVE-2026-58224: ctdb-protocol: Avoid DoS memory allocation
-
-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. Variable i
-could be reused but that might be confusing, so leave any optimisation
-to the compiler.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Reported-by: Martin Schwenke <mschwenke at ddn.com>
-Reported-by: Also Andrew Tridgell (issue 22)
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/protocol/protocol_types.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/ctdb/protocol/protocol_types.c b/ctdb/protocol/protocol_types.c
-index 0eb1923207e..86e1bc3954e 100644
---- a/ctdb/protocol/protocol_types.c
-+++ b/ctdb/protocol/protocol_types.c
-@@ -925,6 +925,7 @@ int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- struct ctdb_vnn_map *val;
- size_t offset = 0, np;
- uint32_t i;
-+ uint32_t dummy = 0;
- int ret;
-
- val = talloc(mem_ctx, struct ctdb_vnn_map);
-@@ -950,6 +951,11 @@ int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- goto done;
- }
-
-+ if ((uint64_t)val->size * ctdb_uint32_len(&dummy) > buflen - offset) {
-+ ret = EMSGSIZE;
-+ goto fail;
-+ }
-+
- val->map = talloc_array(val, uint32_t, val->size);
- if (val->map == NULL) {
- ret = ENOMEM;
---
-2.43.0
-
-
-From 00dda8a31a045c242980c095d02f902d2ee3acc1 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Sat, 30 May 2026 14:25:00 +1000
-Subject: [PATCH 05/23] CVE-2026-58224: ctdb-daemon: Avoid out-of-bounds data access
-
-Do not allow the VNN map's size to extend past the end of the buffer.
-This is checked by switching to ctdb_vnn_map_pull(), which also
-simplifies the code.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_recover.c | 32 +++++++++++++++++++++-----------
- 1 file changed, 21 insertions(+), 11 deletions(-)
-
-diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c
-index 18dc250f5ce..506b0989799 100644
---- a/ctdb/server/ctdb_recover.c
-+++ b/ctdb/server/ctdb_recover.c
-@@ -36,6 +36,8 @@
- #include "ctdb_private.h"
- #include "ctdb_client.h"
-
-+#include "protocol/protocol_private.h"
-+
- #include "common/system.h"
- #include "common/common.h"
- #include "common/logging.h"
-@@ -67,24 +69,32 @@ ctdb_control_getvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA inda
- int
- ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
- {
-- struct ctdb_vnn_map_wire *map = (struct ctdb_vnn_map_wire *)indata.dptr;
-+ struct ctdb_vnn_map *new = NULL;
-+ size_t npull = 0;
-+ int ret = 0;
-
- if (ctdb->recovery_mode != CTDB_RECOVERY_ACTIVE) {
- DEBUG(DEBUG_ERR, ("Attempt to set vnnmap when not in recovery\n"));
- return -1;
- }
-
-+ ret = ctdb_vnn_map_pull(indata.dptr, indata.dsize, ctdb, &new, &npull);
-+ if (ret != 0) {
-+ switch (ret) {
-+ case ENOMEM:
-+ DBG_ERR("Memory allocation error\n");
-+ break;
-+ case EMSGSIZE:
-+ DBG_ERR("Invalid packet\n");
-+ break;
-+ default:
-+ DBG_ERR("Unexpected error (%d)\n", ret);
-+ }
-+ return -1;
-+ }
-+
- talloc_free(ctdb->vnn_map);
--
-- ctdb->vnn_map = talloc(ctdb, struct ctdb_vnn_map);
-- CTDB_NO_MEMORY(ctdb, ctdb->vnn_map);
--
-- ctdb->vnn_map->generation = map->generation;
-- ctdb->vnn_map->size = map->size;
-- ctdb->vnn_map->map = talloc_array(ctdb->vnn_map, uint32_t, map->size);
-- CTDB_NO_MEMORY(ctdb, ctdb->vnn_map->map);
--
-- memcpy(ctdb->vnn_map->map, map->map, sizeof(uint32_t)*map->size);
-+ ctdb->vnn_map = new;
-
- return 0;
- }
---
-2.43.0
-
-
-From 817f926ee93f5a5fc536e676551eb9fc3edb80e0 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Sat, 30 May 2026 15:04:31 +1000
-Subject: [PATCH 06/23] CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access
-
-If a NUL terminator doesn't appear in the buffer then the database
-name is not a valid string.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_ltdb_server.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/ctdb/server/ctdb_ltdb_server.c b/ctdb/server/ctdb_ltdb_server.c
-index 8d03062b97a..2433b39b836 100644
---- a/ctdb/server/ctdb_ltdb_server.c
-+++ b/ctdb/server/ctdb_ltdb_server.c
-@@ -1109,8 +1109,15 @@ int32_t ctdb_control_db_attach(struct ctdb_context *ctdb,
- struct ctdb_db_context *db;
- struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
- struct ctdb_client *client = NULL;
-+ char *t = NULL;
- uint32_t opcode;
-
-+ t = memchr(indata.dptr, '\0', indata.dsize);
-+ if (t == NULL) {
-+ DBG_ERR("Invalid packet\n");
-+ return -1;
-+ }
-+
- if (ctdb->tunable.allow_client_db_attach == 0) {
- DEBUG(DEBUG_ERR, ("DB Attach to database %s denied by tunable "
- "AllowClientDBAccess == 0\n", db_name));
---
-2.43.0
-
-
-From aebf88cc3f73574112a41b4aeaa6745bf735816a Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Sat, 30 May 2026 17:35:23 +1000
-Subject: [PATCH 07/23] CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access
-
-The count can't exceed the recdata buffer size.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_update_record.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/ctdb/server/ctdb_update_record.c b/ctdb/server/ctdb_update_record.c
-index 405499c81e2..154b1427410 100644
---- a/ctdb/server/ctdb_update_record.c
-+++ b/ctdb/server/ctdb_update_record.c
-@@ -318,6 +318,16 @@ int32_t ctdb_control_update_record(struct ctdb_context *ctdb,
- struct childwrite_handle *handle;
- struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
-
-+ if (recdata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
-+ DBG_ERR("Invalid packet\n");
-+ return -1;
-+ }
-+ if (m->count >
-+ recdata.dsize - offsetof(struct ctdb_marshall_buffer, data)) {
-+ DBG_ERR("Invalid packet\n");
-+ return -1;
-+ }
-+
- if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
- DEBUG(DEBUG_INFO,("rejecting ctdb_control_update_record when recovery active\n"));
- return -1;
---
-2.43.0
-
-
-From 424c42226fa2deac56f5df8fd9b114b6ab0b144e Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Sat, 30 May 2026 17:45:56 +1000
-Subject: [PATCH 08/23] CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access
-
-The count can't exceed the indata buffer size.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_recover.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c
-index 506b0989799..b74dca58c8d 100644
---- a/ctdb/server/ctdb_recover.c
-+++ b/ctdb/server/ctdb_recover.c
-@@ -1062,6 +1062,12 @@ int32_t ctdb_control_try_delete_records(struct ctdb_context *ctdb, TDB_DATA inda
- return -1;
- }
-
-+ if (reply->count >
-+ indata.dsize - offsetof(struct ctdb_marshall_buffer, data)) {
-+ DBG_ERR("Invalid packet\n");
-+ return -1;
-+ }
-+
- ctdb_db = find_ctdb_db(ctdb, reply->db_id);
- if (!ctdb_db) {
- DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", reply->db_id));
---
-2.43.0
-
-
-From ed3e723587920dc3c955f098c0e1a00f316835e4 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Sun, 31 May 2026 15:11:39 +1000
-Subject: [PATCH 09/23] CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access
-
-The first check is clearly needed because m->db_id is referenced. The
-second check is handled by a similar update to
-ctdb_control_update_record(), but repeat it in case something else
-changes.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_persistent.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/ctdb/server/ctdb_persistent.c b/ctdb/server/ctdb_persistent.c
-index 26717441d17..1b0d1411553 100644
---- a/ctdb/server/ctdb_persistent.c
-+++ b/ctdb/server/ctdb_persistent.c
-@@ -182,6 +182,16 @@ int32_t ctdb_control_trans3_commit(struct ctdb_context *ctdb,
- struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
- struct ctdb_db_context *ctdb_db;
-
-+ if (recdata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
-+ DBG_ERR("Invalid packet\n");
-+ return -1;
-+ }
-+ if (m->count >
-+ recdata.dsize - offsetof(struct ctdb_marshall_buffer, data)) {
-+ DBG_ERR("Invalid packet\n");
-+ return -1;
-+ }
-+
- if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
- DEBUG(DEBUG_INFO,("rejecting ctdb_control_trans3_commit when recovery active\n"));
- return -1;
---
-2.43.0
-
-
-From 6a6cfa25148a39d024f4e868029db420a36a2b61 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Tue, 9 Jun 2026 10:41:25 +1000
-Subject: [PATCH 10/23] CVE-2026-58224: ctdb-daemon: Avoid out of bounds data access
-
-Instead of checking only that there is enough data for the length
-field, check there is enough data for the entire header part of the
-struct. After cross-checking overall lengths, ensure there is enough
-data for the key/data in the data element.
-
-While here, modernise the DEBUG.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Reported-by: Andrew Tridgell (issue 13)
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/server/ctdb_traverse.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/ctdb/server/ctdb_traverse.c b/ctdb/server/ctdb_traverse.c
-index 4865dcc94f0..094f824bf9d 100644
---- a/ctdb/server/ctdb_traverse.c
-+++ b/ctdb/server/ctdb_traverse.c
-@@ -561,13 +561,17 @@ int32_t ctdb_control_traverse_all(struct ctdb_context *ctdb, TDB_DATA data, TDB_
- int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata)
- {
- struct ctdb_rec_data_old *d = (struct ctdb_rec_data_old *)data.dptr;
-+ size_t rec_data_header_len = offsetof(struct ctdb_rec_data_old, data);
- struct ctdb_traverse_all_handle *state;
- TDB_DATA key;
- ctdb_traverse_fn_t callback;
- void *private_data;
-
-- if (data.dsize < sizeof(uint32_t) || data.dsize != d->length) {
-- DEBUG(DEBUG_ERR,("Bad record size in ctdb_control_traverse_data\n"));
-+ if (data.dsize < rec_data_header_len ||
-+ data.dsize != d->length ||
-+ d->keylen > d->length - rec_data_header_len ||
-+ d->datalen > d->length - rec_data_header_len - d->keylen) {
-+ DBG_ERR("Invalid packet\n");
- return -1;
- }
-
---
-2.43.0
-
-
-From bbf7f1c64c31f50a4fceafee40315c2a6605e30d Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Tue, 9 Jun 2026 21:48:02 +1000
-Subject: [PATCH 11/23] CVE-2026-58224: ctdb-protocol: Avoid off-by-one error for bytes pulled
-
-As per the comment, if there is no NUL byte in the buffer then don't
-count one in the number of bytes pulled.
-
-Note that this is unlikely to be a security issue because it would
-take a protocol bug elsewhere to overrun the buffer. However, include
-this fix here for posterity.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Reported-by: Andrew Tridgell (issue 16)
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/protocol/protocol_basic.c | 12 ++++++++++--
- 1 file changed, 10 insertions(+), 2 deletions(-)
-
-diff --git a/ctdb/protocol/protocol_basic.c b/ctdb/protocol/protocol_basic.c
-index 42f207790d0..9cc52def644 100644
---- a/ctdb/protocol/protocol_basic.c
-+++ b/ctdb/protocol/protocol_basic.c
-@@ -247,7 +247,8 @@ void ctdb_string_push(const char **in, uint8_t *buf, size_t *npush)
- int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- const char **out, size_t *npull)
- {
-- const char *str;
-+ const char *str = NULL;
-+ size_t len = 0;
-
- if (buflen > UINT32_MAX) {
- return EMSGSIZE;
-@@ -265,7 +266,14 @@ int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- }
-
- *out = str;
-- *npull = ctdb_string_len(&str);
-+ /*
-+ * Avoid claiming to have consumed more than buflen.
-+ * ctdb_string_len() returns buflen + 1 if there is no
-+ * NUL-terminator within buflen, so no NUL was actually
-+ * consumed (so no +1 needed).
-+ */
-+ len = ctdb_string_len(&str);
-+ *npull = MIN(buflen, len);
- return 0;
- }
-
---
-2.43.0
-
-
-From 623cbadd46043ba6352d61a1fa9d8c17deb2b178 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Tue, 9 Jun 2026 21:54:20 +1000
-Subject: [PATCH 12/23] CVE-2026-58224: ctdb-protocol: Always pull the specified number of
- bytes
-
-The string should not contain a premature NUL terminator, which would
-cause less than the specified number of bytes to be pulled. If it
-does, consume the specified number of bytes anyway. The alternative
-doesn't make sense.
-
-Note that this is unlikely to be a security issue, where trailing data
-in the string field causes the buffer to be overrun. That would
-require an additional protocol bug. However, include this fix here
-for posterity.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/protocol/protocol_basic.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/ctdb/protocol/protocol_basic.c b/ctdb/protocol/protocol_basic.c
-index 9cc52def644..750ea8f9fe7 100644
---- a/ctdb/protocol/protocol_basic.c
-+++ b/ctdb/protocol/protocol_basic.c
-@@ -319,7 +319,8 @@ int ctdb_stringn_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- if (ret != 0) {
- return ret;
- }
-- offset += np;
-+ /* Always consume the specified number bytes */
-+ offset += u32;
-
- *npull = offset;
- return 0;
---
-2.43.0
-
-
-From 0fa6bb4f3edfbe819ed15555c2c64fd66f3077ad Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at 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 at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at 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
-
-
-From 0e50b8600d491fd4001c20aecccf3abe1ea199ac Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Wed, 10 Jun 2026 12:37:02 +1000
-Subject: [PATCH 14/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
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/protocol/protocol_types.c | 35 ++++++++++++++++++++++++++++++++++
- 1 file changed, 35 insertions(+)
-
-diff --git a/ctdb/protocol/protocol_types.c b/ctdb/protocol/protocol_types.c
-index 2edf8228d18..8cbdaee5106 100644
---- a/ctdb/protocol/protocol_types.c
-+++ b/ctdb/protocol/protocol_types.c
-@@ -2380,6 +2380,7 @@ int ctdb_connection_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- struct ctdb_connection_list **out, size_t *npull)
- {
- struct ctdb_connection_list *val;
-+ struct ctdb_connection dummy = {};
- size_t offset = 0, np;
- uint32_t i;
- int ret;
-@@ -2400,6 +2401,11 @@ int ctdb_connection_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- goto done;
- }
-
-+ if ((uint64_t)val->num * ctdb_connection_len(&dummy) > buflen - offset) {
-+ ret = EMSGSIZE;
-+ goto fail;
-+ }
-+
- val->conn = talloc_array(val, struct ctdb_connection, val->num);
- if (val->conn == NULL) {
- ret = ENOMEM;
-@@ -3417,6 +3423,7 @@ int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- struct ctdb_tickle_list **out, size_t *npull)
- {
- struct ctdb_tickle_list *val;
-+ struct ctdb_connection dummy = {};
- size_t offset = 0, np;
- uint32_t i;
- int ret;
-@@ -3444,6 +3451,11 @@ int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- goto done;
- }
-
-+ if ((uint64_t)val->num * ctdb_connection_len(&dummy) > buflen - offset) {
-+ ret = EMSGSIZE;
-+ goto fail;
-+ }
-+
- val->conn = talloc_array(val, struct ctdb_connection, val->num);
- if (val->conn == NULL) {
- ret = ENOMEM;
-@@ -3762,6 +3774,7 @@ int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- struct ctdb_public_ip_list **out, size_t *npull)
- {
- struct ctdb_public_ip_list *val;
-+ struct ctdb_public_ip dummy = {};
- size_t offset = 0, np;
- uint32_t i;
- int ret;
-@@ -3782,6 +3795,11 @@ int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- goto done;
- }
-
-+ if ((uint64_t)val->num * ctdb_public_ip_len(&dummy) > buflen - offset) {
-+ ret = EMSGSIZE;
-+ goto fail;
-+ }
-+
- val->ip = talloc_array(val, struct ctdb_public_ip, val->num);
- if (val->ip == NULL) {
- ret = ENOMEM;
-@@ -4124,6 +4142,7 @@ int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- struct ctdb_script_list **out, size_t *npull)
- {
- struct ctdb_script_list *val;
-+ struct ctdb_script dummy = {};
- size_t offset = 0, np;
- uint32_t i;
- int ret;
-@@ -4157,6 +4176,12 @@ int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- goto done;
- }
-
-+ if ((uint64_t)val->num_scripts * ctdb_script_len(&dummy)
-+ > buflen - offset) {
-+ ret = EMSGSIZE;
-+ goto fail;
-+ }
-+
- val->script = talloc_array(val, struct ctdb_script, val->num_scripts);
- if (val->script == NULL) {
- ret = ENOMEM;
-@@ -4400,6 +4425,7 @@ int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- struct ctdb_iface_list **out, size_t *npull)
- {
- struct ctdb_iface_list *val;
-+ struct ctdb_iface dummy = {};
- size_t offset = 0, np;
- uint32_t i;
- int ret;
-@@ -4420,6 +4446,11 @@ int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
- goto done;
- }
-
-+ if ((uint64_t)val->num * ctdb_iface_len(&dummy) > buflen - offset) {
-+ ret = EMSGSIZE;
-+ goto fail;
-+ }
-+
- val->iface = talloc_array(val, struct ctdb_iface, val->num);
- if (val->iface == NULL) {
- ret = ENOMEM;
-@@ -5347,6 +5378,10 @@ int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
-
- val->num = buflen / ctdb_g_lock_len(&lock);
-
-+ /*
-+ * No array count pre-check needed because val->num is
-+ * calculated from buflen
-+ */
- val->lock = talloc_array(val, struct ctdb_g_lock, val->num);
- if (val->lock == NULL) {
- ret = ENOMEM;
---
-2.43.0
-
-
-From 3f0c7161989b2adbbb00ce26838097e26ed6c09a Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Thu, 11 Jun 2026 11:25:52 +1000
-Subject: [PATCH 15/23] CVE-2026-58224: ctdb-common: Secure sock_daemon Unix domain sockets
-
-Currently, the mode of the socket depends on the creating process's
-umask. This might allow unwanted access.
-
-It might be preferable to do this just for the eventd socket.
-However, there is no useful place to hook this in outside of
-sock_daemon.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/common/sock_daemon.c | 26 ++++++++++++++++++++++++++
- 1 file changed, 26 insertions(+)
-
-diff --git a/ctdb/common/sock_daemon.c b/ctdb/common/sock_daemon.c
-index e31a36445b5..ed0ccfd70ef 100644
---- a/ctdb/common/sock_daemon.c
-+++ b/ctdb/common/sock_daemon.c
-@@ -204,6 +204,8 @@ static int sock_client_context_destructor(
- static int socket_setup(const char *sockpath, bool remove_before_use)
- {
- struct sockaddr_un addr;
-+ const char *t;
-+ bool test_mode_enabled = false;
- size_t len;
- int ret, fd;
-
-@@ -240,6 +242,30 @@ static int socket_setup(const char *sockpath, bool remove_before_use)
- return -1;
- }
-
-+ t = getenv("CTDB_TEST_MODE");
-+ if (t != NULL) {
-+ test_mode_enabled = true;
-+ }
-+
-+ if (!test_mode_enabled) {
-+ /* Behaviour of fchown(2) is undefined on sockets */
-+ ret = chown(sockpath, geteuid(), getegid());
-+ if (ret != 0) {
-+ D_ERR("Unable to secure (chown) socket '%s'\n",
-+ sockpath);
-+ close(fd);
-+ return -1;
-+ }
-+ }
-+
-+ /* Behaviour of fchmod(2) is undefined on sockets */
-+ ret = chmod(sockpath, 0700);
-+ if (ret != 0) {
-+ D_ERR("Unable to secure (chmod) socket '%s'\n", sockpath);
-+ close(fd);
-+ return -1;
-+ }
-+
- ret = listen(fd, 10);
- if (ret != 0) {
- D_ERR("socket listen failed - %s\n", sockpath);
---
-2.43.0
-
-
-From 6a35065be688fe449120d09045b90ad1ad681386 Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Wed, 10 Jun 2026 18:45:43 +1000
-Subject: [PATCH 16/23] CVE-2026-58224: ctdb-doc: Emphasise that the private network must be
- private
-
-Note that the difference in the first couple of lines is leading
-whitespace being switch to a TAB.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Tristan Madani <tristan at talencesecurity.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/doc/ctdb.7.xml | 27 +++++++++++++++++++--------
- 1 file changed, 19 insertions(+), 8 deletions(-)
-
-diff --git a/ctdb/doc/ctdb.7.xml b/ctdb/doc/ctdb.7.xml
-index be2dd5e5b65..9087acf9870 100644
---- a/ctdb/doc/ctdb.7.xml
-+++ b/ctdb/doc/ctdb.7.xml
-@@ -242,14 +242,25 @@
- services provided by the cluster.
- </para>
- <para>
-- It is strongly recommended that the private addresses are
-- configured on a private network that is separate from client
-- networks. This is because the CTDB protocol is both
-- unauthenticated and unencrypted. If clients share the private
-- network then steps need to be taken to stop injection of
-- packets to relevant ports on the private addresses. It is
-- also likely that CTDB protocol traffic between nodes could
-- leak sensitive information if it can be intercepted.
-+ It is strongly recommended that the private addresses are
-+ configured on a private network that is separate from client
-+ networks. This is because <emphasis>the CTDB protocol is both
-+ unauthenticated and unencrypted</emphasis>. If clients share
-+ the private network then steps need to be taken to stop
-+ injection of packets to relevant ports on the private
-+ addresses. It is also likely that CTDB protocol traffic
-+ between nodes could leak sensitive information if it can be
-+ intercepted or manipulated.
-+ </para>
-+ <para>
-+ In summary, the private network should not be accessible by
-+ untrusted sources. We can't say "must not" because this can't
-+ be enforced by CTDB, so we can only make a strong
-+ recommendation. However, for this reason, future bugs in the
-+ CTDB protocol used over the private network will be fixed as
-+ regular bugs without following the Samba security process.
-+ The same is true of local CTDB protocols used for Unix domain
-+ socket and other communication.
- </para>
-
- <para>
---
-2.43.0
-
-
-From 1ec95b73b235023221a4a18e888fa3286550faea Mon Sep 17 00:00:00 2001
-From: Martin Schwenke <mschwenke at ddn.com>
-Date: Tue, 30 Jun 2026 13:58:22 +1000
-Subject: [PATCH 17/23] CVE-2026-58224: ctdb-common: Add comments to ward off vulnerability
- reports
-
-We can't deal with this in the current CTDB protocol without
-disproportionate effort. So, document reality clearly in the code to
-try to stop these from being reported.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16085
-
-Signed-off-by: Martin Schwenke <mschwenke at ddn.com>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- ctdb/common/ctdb_io.c | 20 +++++++++++++++++++-
- ctdb/common/pkt_read.c | 19 +++++++++++++++++++
- 2 files changed, 38 insertions(+), 1 deletion(-)
-
-diff --git a/ctdb/common/ctdb_io.c b/ctdb/common/ctdb_io.c
-index 9ac9b84a7fb..346a7456f47 100644
---- a/ctdb/common/ctdb_io.c
-+++ b/ctdb/common/ctdb_io.c
-@@ -115,7 +115,25 @@ static void queue_process(struct ctdb_queue *queue)
- return;
- }
-
-- /* Extract complete packet */
-+ /*
-+ * Extract complete packet
-+ *
-+ * Yes, this allows an out-of-memory denial of service (DoS)
-+ * attack if a number of packets are received with
-+ * unreasonable packet sizes, noting that the maximum packet
-+ * size is ~4GB. The CTDB protocol was not designed with a
-+ * maximum packet size in mind, so CTDB may send very large
-+ * valid packets. This means that imposing an arbitrary limit
-+ * on incoming packets is not reasonable. Arguments that
-+ * header fields, such as magic and/or version, should be
-+ * validated before allocating a packet buffer are spurious
-+ * from a security perspective because an attacker attempting
-+ * DoS can send packets with valid headers. The private
-+ * network and ctdbd socket should be secured against
-+ * untrusted access, so reports that this possible DoS vector
-+ * represents a security issue will be ignored. See the
-+ * "Private addresses" section in ctdb(7) for more details.
-+ */
- data = talloc_memdup(queue->data_pool,
- queue->buffer.data + queue->buffer.offset,
- pkt_size);
-diff --git a/ctdb/common/pkt_read.c b/ctdb/common/pkt_read.c
-index 212ace54bbd..8877f6aa368 100644
---- a/ctdb/common/pkt_read.c
-+++ b/ctdb/common/pkt_read.c
-@@ -146,6 +146,25 @@ void pkt_read_handler(struct tevent_context *ev, struct tevent_fd *fde,
- return;
- }
-
-+ /*
-+ * Allocate buffer for entire packet
-+ *
-+ * Yes, this allows an out-of-memory denial of service (DoS)
-+ * attack if a number of packets are received with
-+ * unreasonable packet sizes, noting that the maximum packet
-+ * size is ~4GB. The CTDB protocol was not designed with a
-+ * maximum packet size in mind, so CTDB may send very large
-+ * valid packets. This means that imposing an arbitrary limit
-+ * on incoming packets is not reasonable. Arguments that
-+ * header fields, such as magic and/or version, should be
-+ * validated before allocating a packet buffer are spurious
-+ * from a security perspective because an attacker attempting
-+ * DoS can send packets with valid headers. The private
-+ * network and ctdbd socket should be secured against
-+ * untrusted access, so reports that this possible DoS vector
-+ * represents a security issue will be ignored. See the
-+ * "Private addresses" section in ctdb(7) for more details.
-+ */
- if (state->use_fixed) {
- /* switch to dynamic buffer */
- tmp = talloc_array(state, uint8_t, state->total + more);
---
-2.43.0
-
-
-From ced0a00f97d9f165e6c7725f0d335b1a3411a478 Mon Sep 17 00:00:00 2001
-From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
-Date: Sun, 31 May 2026 12:48:11 +1200
-Subject: [PATCH 18/23] CVE-2026-58216: kdc:kpasswd: calculate correct size for password blob
-
-We were making the enc_data_blob 6 bytes too big.
-
-Its payload is an ASN.1 structure that knows its own size, so the
-extra bytes are not usually read by Heimdal, but a crafted packet
-could force them to be read.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16087
-
-Reported-by: Tristan <TristanInSec at gmail.com>
-Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
-Reviewed-by: Stefan Metzmacher <metze at samba.org>
----
- source4/kdc/kpasswd-service.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/source4/kdc/kpasswd-service.c b/source4/kdc/kpasswd-service.c
-index c671eb46d07..0284fb4f133 100644
---- a/source4/kdc/kpasswd-service.c
-+++ b/source4/kdc/kpasswd-service.c
-@@ -137,7 +137,7 @@ kdc_code kpasswd_process(struct kdc_server *kdc,
-
- ap_req_blob = data_blob_const(&request->data[HEADER_LEN], ap_req_len);
-
-- enc_data_len = len - ap_req_len;
-+ enc_data_len = len - (ap_req_len + HEADER_LEN);
- enc_data_blob = data_blob_const(&request->data[HEADER_LEN + ap_req_len],
- enc_data_len);
-
---
-2.43.0
-
-
-From be4c33a1452aa2cd2fa6a420a1d443aef4233243 Mon Sep 17 00:00:00 2001
-From: Volker Lendecke <vl at samba.org>
-Date: Wed, 17 Jun 2026 08:24:47 +0200
-Subject: [PATCH 19/23] CVE-2026-58218: dns_server: Fix an error path memleak
-
-We talloc the new key off "dns->tkeys", which is long-lived. On any
-error we never free'd that again. Probably not remotely triggerable,
-this is only setting up the gensec context.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16115
-
-Signed-off-by: Volker Lendecke <vl at samba.org>
-Reviewed-by: Douglas Bagnall <dbagnall at samba.org>
----
- source4/dns_server/dns_query.c | 25 ++++++++++++++-----------
- 1 file changed, 14 insertions(+), 11 deletions(-)
-
-diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
-index 1f46ee0aa19..ebc6a735a76 100644
---- a/source4/dns_server/dns_query.c
-+++ b/source4/dns_server/dns_query.c
-@@ -675,18 +675,18 @@ static NTSTATUS create_tkey(struct dns_server *dns,
-
- k = talloc_zero(store, struct dns_server_tkey);
- if (k == NULL) {
-- return NT_STATUS_NO_MEMORY;
-+ goto nomem;
- }
-
- k->name = talloc_strdup(k, name);
-
- if (k->name == NULL) {
-- return NT_STATUS_NO_MEMORY;
-+ goto nomem;
- }
-
- k->algorithm = talloc_strdup(k, algorithm);
- if (k->algorithm == NULL) {
-- return NT_STATUS_NO_MEMORY;
-+ goto nomem;
- }
-
- /*
-@@ -704,8 +704,7 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- &k->gensec);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
-- *tkey = NULL;
-- return status;
-+ goto fail;
- }
-
- gensec_want_feature(k->gensec, GENSEC_FEATURE_SIGN);
-@@ -715,8 +714,7 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to set remote address into GENSEC: %s\n",
- nt_errstr(status)));
-- *tkey = NULL;
-- return status;
-+ goto fail;
- }
-
- status = gensec_set_local_address(k->gensec,
-@@ -724,8 +722,7 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to set local address into GENSEC: %s\n",
- nt_errstr(status)));
-- *tkey = NULL;
-- return status;
-+ goto fail;
- }
-
- status = gensec_start_mech_by_oid(k->gensec, GENSEC_OID_SPNEGO);
-@@ -733,8 +730,7 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start GENSEC server code: %s\n",
- nt_errstr(status)));
-- *tkey = NULL;
-- return status;
-+ goto fail;
- }
-
- TALLOC_FREE(store->tkeys[store->next_idx]);
-@@ -745,6 +741,13 @@ static NTSTATUS create_tkey(struct dns_server *dns,
-
- *tkey = k;
- return NT_STATUS_OK;
-+
-+nomem:
-+ status = NT_STATUS_NO_MEMORY;
-+fail:
-+ TALLOC_FREE(k);
-+ *tkey = NULL;
-+ return status;
- }
-
- static NTSTATUS accept_gss_ticket(TALLOC_CTX *mem_ctx,
---
-2.43.0
-
-
-From d8752af75899caa621f71e6149024a2ed5d552b4 Mon Sep 17 00:00:00 2001
-From: Volker Lendecke <vl at samba.org>
-Date: Wed, 17 Jun 2026 08:58:40 +0200
-Subject: [PATCH 20/23] CVE-2026-58218: dns_server: Only add a tkey after successful
- authentication
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16115
-
-Signed-off-by: Volker Lendecke <vl at samba.org>
-Reviewed-by: Douglas Bagnall <dbagnall at samba.org>
----
- source4/dns_server/dns_query.c | 41 ++++++++++++++++++++++------------
- 1 file changed, 27 insertions(+), 14 deletions(-)
-
-diff --git a/source4/dns_server/dns_query.c b/source4/dns_server/dns_query.c
-index ebc6a735a76..2998dbee060 100644
---- a/source4/dns_server/dns_query.c
-+++ b/source4/dns_server/dns_query.c
-@@ -654,7 +654,8 @@ static WERROR handle_authoritative_recv(struct tevent_req *req)
- return WERR_OK;
- }
-
--static NTSTATUS create_tkey(struct dns_server *dns,
-+static NTSTATUS create_tkey(TALLOC_CTX *mem_ctx,
-+ struct dns_server *dns,
- const char* name,
- const char* algorithm,
- const struct tsocket_address *remote_address,
-@@ -662,7 +663,6 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- struct dns_server_tkey **tkey)
- {
- NTSTATUS status;
-- struct dns_server_tkey_store *store = dns->tkeys;
- struct dns_server_tkey *k = NULL;
-
- if (strcmp(algorithm, "gss-tsig") == 0) {
-@@ -673,7 +673,7 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- return NT_STATUS_ACCESS_DENIED;
- }
-
-- k = talloc_zero(store, struct dns_server_tkey);
-+ k = talloc_zero(mem_ctx, struct dns_server_tkey);
- if (k == NULL) {
- goto nomem;
- }
-@@ -733,12 +733,6 @@ static NTSTATUS create_tkey(struct dns_server *dns,
- goto fail;
- }
-
-- TALLOC_FREE(store->tkeys[store->next_idx]);
--
-- store->tkeys[store->next_idx] = k;
-- (store->next_idx)++;
-- store->next_idx %= store->size;
--
- *tkey = k;
- return NT_STATUS_OK;
-
-@@ -750,6 +744,17 @@ fail:
- return status;
- }
-
-+static void add_tkey(struct dns_server_tkey_store *store,
-+ struct dns_server_tkey **tkey)
-+{
-+ TALLOC_FREE(store->tkeys[store->next_idx]);
-+
-+ store->tkeys[store->next_idx] = talloc_move(store->tkeys, tkey);
-+
-+ (store->next_idx)++;
-+ store->next_idx %= store->size;
-+}
-+
- static NTSTATUS accept_gss_ticket(TALLOC_CTX *mem_ctx,
- struct dns_server *dns,
- struct dns_server_tkey *tkey,
-@@ -863,6 +868,7 @@ static WERROR handle_tkey(struct dns_server *dns,
- struct dns_server_tkey *tkey;
- DATA_BLOB key;
- DATA_BLOB reply;
-+ bool created = false;
-
- tkey = dns_find_tkey(dns->tkeys, in->questions[0].name);
- if (tkey != NULL && tkey->complete) {
-@@ -873,15 +879,19 @@ static WERROR handle_tkey(struct dns_server *dns,
- }
-
- if (tkey == NULL) {
-- status = create_tkey(dns, in->questions[0].name,
-- in_tkey->rdata.tkey_record.algorithm,
-- state->remote_address,
-- state->local_address,
-- &tkey);
-+ status = create_tkey(
-+ mem_ctx,
-+ dns,
-+ in->questions[0].name,
-+ in_tkey->rdata.tkey_record.algorithm,
-+ state->remote_address,
-+ state->local_address,
-+ &tkey);
- if (!NT_STATUS_IS_OK(status)) {
- ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
- return ntstatus_to_werror(status);
- }
-+ created = true;
- }
-
- key.data = in_tkey->rdata.tkey_record.key_data;
-@@ -906,6 +916,9 @@ static WERROR handle_tkey(struct dns_server *dns,
- if (state->key_name == NULL) {
- return WERR_NOT_ENOUGH_MEMORY;
- }
-+ if (created) {
-+ add_tkey(dns->tkeys, &tkey);
-+ }
- } else {
- DEBUG(1, ("GSS key negotiation returned %s\n", nt_errstr(status)));
- ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
---
-2.43.0
-
-
-From 24f7eb574d2e9ea57746f9696491b50dc4ef5352 Mon Sep 17 00:00:00 2001
-From: Stefan Metzmacher <metze at samba.org>
-Date: Mon, 29 Jun 2026 19:09:28 +0200
-Subject: [PATCH 21/23] CVE-2026-58221: s4:dsdb: provide
- dsdb_audit_{log_attributes,operation_human_readable}() functions
-
-They are useful outside of audit_log.c soon.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16147
-
-Signed-off-by: Stefan Metzmacher <metze at samba.org>
-Reviewed-by: Volker Lendecke <vl at samba.org>
-Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
-
-[backport: modified for v4.22, not removing the static versions used
- in audit_log.c or adjusting the tests]
----
- source4/dsdb/samdb/ldb_modules/audit_util.c | 180 ++++++++++++++++++++
- 1 file changed, 180 insertions(+)
-
-diff --git a/source4/dsdb/samdb/ldb_modules/audit_util.c b/source4/dsdb/samdb/ldb_modules/audit_util.c
-index 8fe7d8332d2..25f90ee3db3 100644
---- a/source4/dsdb/samdb/ldb_modules/audit_util.c
-+++ b/source4/dsdb/samdb/ldb_modules/audit_util.c
-@@ -694,3 +694,183 @@ failure:
- DBG_ERR("Unable to create ldb attributes JSON audit message\n");
- return attributes;
- }
-+
-+/*
-+ * @brief Generate a human readable string, detailing attributes in a message
-+ *
-+ * For modify operations each attribute is prefixed with the action.
-+ * Normal values are enclosed in []
-+ * Base64 values are enclosed in {}
-+ * Truncated values are indicated by three trailing dots "..."
-+ *
-+ * @param[in] ldb the ldb_context
-+ * @param[out] buffer the attributes will be appended to the buffer.
-+ * assumed to have been allocated via talloc.
-+ * @param[in] operation the operation type
-+ * @param[in] message the message to process
-+ *
-+ * @return a pointer to buffer
-+ *
-+ */
-+char *dsdb_audit_log_attributes(
-+ struct ldb_context *ldb,
-+ char *buffer,
-+ enum ldb_request_type operation,
-+ const struct ldb_message *message)
-+{
-+ size_t i, j;
-+ for (i=0;i<message->num_elements;i++) {
-+ if (i > 0) {
-+ buffer = talloc_asprintf_append_buffer(buffer, " ");
-+ }
-+
-+ if (message->elements[i].name == NULL) {
-+ ldb_debug(
-+ ldb,
-+ LDB_DEBUG_ERROR,
-+ "Error: Invalid element name (NULL) at "
-+ "position %zu", i);
-+ return NULL;
-+ }
-+
-+ if (operation == LDB_MODIFY) {
-+ const char *action =NULL;
-+ action = dsdb_audit_get_modification_action(
-+ message->elements[i].flags);
-+ buffer = talloc_asprintf_append_buffer(
-+ buffer,
-+ "%s: %s ",
-+ action,
-+ message->elements[i].name);
-+ } else {
-+ buffer = talloc_asprintf_append_buffer(
-+ buffer,
-+ "%s ",
-+ message->elements[i].name);
-+ }
-+
-+ if (dsdb_audit_redact_attribute(message->elements[i].name)) {
-+ /*
-+ * Do not log the value of any secret or password
-+ * attributes
-+ */
-+ buffer = talloc_asprintf_append_buffer(
-+ buffer,
-+ "[REDACTED SECRET ATTRIBUTE]");
-+ continue;
-+ }
-+
-+ for (j=0;j<message->elements[i].num_values;j++) {
-+ struct ldb_val v;
-+ bool use_b64_encode = false;
-+ size_t length;
-+ if (j > 0) {
-+ buffer = talloc_asprintf_append_buffer(
-+ buffer,
-+ " ");
-+ }
-+
-+ v = message->elements[i].values[j];
-+ length = MIN(MAX_LENGTH, v.length);
-+ use_b64_encode = ldb_should_b64_encode(ldb, &v);
-+ if (use_b64_encode) {
-+ const char *encoded = ldb_base64_encode(
-+ buffer,
-+ (char *)v.data,
-+ length);
-+ buffer = talloc_asprintf_append_buffer(
-+ buffer,
-+ "{%s%s}",
-+ encoded,
-+ (v.length > MAX_LENGTH ? "..." : ""));
-+ } else {
-+ buffer = talloc_asprintf_append_buffer(
-+ buffer,
-+ "[%*.*s%s]",
-+ (int)length,
-+ (int)length,
-+ (char *)v.data,
-+ (v.length > MAX_LENGTH ? "..." : ""));
-+ }
-+ }
-+ }
-+ return buffer;
-+}
-+
-+/*
-+ * @brief generate a human readable log entry detailing an ldb operation.
-+ *
-+ * Generate a human readable log entry detailing an ldb operation.
-+ *
-+ * @param[in] mem_ctx the talloc context owning the returned string.
-+ * @param[in] module the ldb module
-+ * @param[in] request the request
-+ * @param[in] reply the result of the operation
-+ *
-+ * @return the log entry.
-+ *
-+ */
-+char *dsdb_audit_operation_human_readable(
-+ TALLOC_CTX *mem_ctx,
-+ struct ldb_module *module,
-+ const struct ldb_request *request,
-+ const struct ldb_reply *reply)
-+{
-+ struct ldb_context *ldb = NULL;
-+ const char *remote_host = NULL;
-+ const struct tsocket_address *remote = NULL;
-+ const struct dom_sid *sid = NULL;
-+ struct dom_sid_buf user_sid;
-+ const char *timestamp = NULL;
-+ const char *op_name = NULL;
-+ char *log_entry = NULL;
-+ const char *dn = NULL;
-+ const char *new_dn = NULL;
-+ const struct ldb_message *message = NULL;
-+
-+ TALLOC_CTX *ctx = talloc_new(NULL);
-+
-+ ldb = ldb_module_get_ctx(module);
-+
-+ remote_host = dsdb_audit_get_remote_host(ldb, ctx);
-+ remote = dsdb_audit_get_remote_address(ldb);
-+ if (remote != NULL && dsdb_audit_is_system_session(module)) {
-+ sid = dsdb_audit_get_actual_sid(ldb);
-+ } else {
-+ sid = dsdb_audit_get_user_sid(module);
-+ }
-+ timestamp = audit_get_timestamp(ctx);
-+ op_name = dsdb_audit_get_operation_name(request);
-+ dn = dsdb_audit_get_primary_dn(request);
-+ new_dn = dsdb_audit_get_secondary_dn(request);
-+
-+ message = dsdb_audit_get_message(request);
-+
-+ log_entry = talloc_asprintf(
-+ mem_ctx,
-+ "[%s] at [%s] status [%s] "
-+ "remote host [%s] SID [%s] DN [%s]",
-+ op_name,
-+ timestamp,
-+ ldb_strerror(reply->error),
-+ remote_host,
-+ dom_sid_str_buf(sid, &user_sid),
-+ dn);
-+ if (new_dn != NULL) {
-+ log_entry = talloc_asprintf_append_buffer(
-+ log_entry,
-+ " New DN [%s]",
-+ new_dn);
-+ }
-+ if (message != NULL) {
-+ log_entry = talloc_asprintf_append_buffer(log_entry,
-+ " attributes [");
-+ log_entry = dsdb_audit_log_attributes(ldb,
-+ log_entry,
-+ request->operation,
-+ message);
-+ log_entry = talloc_asprintf_append_buffer(log_entry, "]");
-+ }
-+ TALLOC_FREE(ctx);
-+ return log_entry;
-+}
---
-2.43.0
-
-
-From b5f78492628a06013354f76521cb153ab7d8e0d5 Mon Sep 17 00:00:00 2001
-From: Stefan Metzmacher <metze at samba.org>
-Date: Wed, 24 Jun 2026 14:01:32 +0200
-Subject: [PATCH 22/23] CVE-2026-58221: s4:dsdb: let rootdse_filter_operations()
- reject untrusted operations on special DNs
-
-Without this authenticated (also non-admin) users write internal meta
-data leading to admin privileges.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16147
-
-Signed-off-by: Stefan Metzmacher <metze at samba.org>
-Reviewed-by: Volker Lendecke <vl at samba.org>
-Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
----
- source4/dsdb/samdb/ldb_modules/rootdse.c | 55 ++++++++++++++++++-
- .../samdb/ldb_modules/wscript_build_server | 2 +-
- 2 files changed, 54 insertions(+), 3 deletions(-)
-
-diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c
-index 7541a2cf376..9cc8477b8f8 100644
---- a/source4/dsdb/samdb/ldb_modules/rootdse.c
-+++ b/source4/dsdb/samdb/ldb_modules/rootdse.c
-@@ -28,6 +28,7 @@
- #include "dsdb/samdb/samdb.h"
- #include "version.h"
- #include "dsdb/samdb/ldb_modules/util.h"
-+#include "dsdb/samdb/ldb_modules/audit_util_proto.h"
- #include "libcli/security/security.h"
- #include "librpc/ndr/libndr.h"
- #include "auth/auth.h"
-@@ -746,18 +747,68 @@ static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request
- return LDB_SUCCESS;
- }
-
--/* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
--
-+/*
-+ * Ensure that anonymous users are not allowed to make anything other than
-+ * rootDSE search operations and special dns like @MODULES are not allowed
-+ * over an untrusted connection.
-+ */
- static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
- {
- struct auth_session_info *session_info;
- struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
- bool is_untrusted = ldb_req_is_untrusted(req);
- bool is_anonymous = true;
-+ struct ldb_dn *dn = NULL;
-+ struct ldb_dn *dn2 = NULL;
-+
- if (is_untrusted == false) {
- return LDB_SUCCESS;
- }
-
-+ switch (req->operation) {
-+ case LDB_SEARCH:
-+ dn = req->op.search.base;
-+ break;
-+ case LDB_ADD:
-+ dn = req->op.add.message->dn;
-+ break;
-+ case LDB_MODIFY:
-+ dn = req->op.mod.message->dn;
-+ break;
-+ case LDB_DELETE:
-+ dn = req->op.del.dn;
-+ break;
-+ case LDB_RENAME:
-+ dn = req->op.rename.olddn;
-+ dn2 = req->op.rename.newdn;
-+ break;
-+ case LDB_EXTENDED:
-+ break;
-+ case LDB_REQ_REGISTER_CONTROL:
-+ case LDB_REQ_REGISTER_PARTITION:
-+ ldb_set_errstring(ldb_module_get_ctx(module), "Invalid OP");
-+ return LDB_ERR_OPERATIONS_ERROR;
-+ }
-+
-+ if (ldb_dn_is_special(dn)) {
-+ struct ldb_reply reply = { .error = LDB_ERR_OPERATIONS_ERROR, };
-+
-+ D_ERR("CVE-2026-58221-ATTACK: %s\n",
-+ dsdb_audit_operation_human_readable(req, module, req, &reply));
-+
-+ ldb_set_errstring(ldb_module_get_ctx(module), "Invalid DN");
-+ return LDB_ERR_OPERATIONS_ERROR;
-+ }
-+ if (ldb_dn_is_special(dn2)) {
-+ struct ldb_reply reply = { .error = LDB_ERR_OPERATIONS_ERROR, };
-+
-+ D_ERR("CVE-2026-58221-ATTACK: %s\n",
-+ dsdb_audit_operation_human_readable(req, module, req, &reply));
-+
-+ ldb_set_errstring(ldb_module_get_ctx(module), "Invalid DN");
-+ return LDB_ERR_OPERATIONS_ERROR;
-+ }
-+
- session_info = (struct auth_session_info *)ldb_get_opaque(
- ldb_module_get_ctx(module),
- DSDB_SESSION_INFO);
-diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build_server b/source4/dsdb/samdb/ldb_modules/wscript_build_server
-index 800ed2954c4..7582b64a938 100644
---- a/source4/dsdb/samdb/ldb_modules/wscript_build_server
-+++ b/source4/dsdb/samdb/ldb_modules/wscript_build_server
-@@ -185,7 +185,7 @@ bld.SAMBA_MODULE('ldb_rootdse',
- init_function='ldb_rootdse_module_init',
- module_init_name='ldb_init_module',
- internal_module=False,
-- deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC'
-+ deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS DSDB_MODULE_HELPERS_AUDIT RPC_NDR_IRPC'
- )
-
-
---
-2.43.0
-
-
-From e3c15d9365fcec0389c9b3ac7bc38871854c64a7 Mon Sep 17 00:00:00 2001
-From: Stefan Metzmacher <metze at samba.org>
-Date: Wed, 24 Jun 2026 14:42:11 +0200
-Subject: [PATCH 23/23] CVE-2026-58222 s4:ldap_server: don't allow untrusted
- compare requests for confidential attributes
-
-This means we apply acl checks against the search filter similar
-to normal ldb searches.
-
-BUG: https://bugzilla.samba.org/show_bug.cgi?id=16148
-
-Signed-off-by: Stefan Metzmacher <metze at samba.org>
-Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
----
- source4/ldap_server/ldap_backend.c | 27 ++++++++++++++++++++-------
- 1 file changed, 20 insertions(+), 7 deletions(-)
-
-diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c
-index 986bc1db941..4603935f0b0 100644
---- a/source4/ldap_server/ldap_backend.c
-+++ b/source4/ldap_server/ldap_backend.c
-@@ -29,6 +29,7 @@
- #include "samba/service_stream.h"
- #include "dsdb/gmsa/util.h"
- #include "dsdb/samdb/samdb.h"
-+#include "dsdb/common/util.h"
- #include <ldb_errors.h>
- #include <ldb_module.h>
- #include "ldb_wrap.h"
-@@ -1449,6 +1450,7 @@ static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call)
- struct ldb_dn *dn;
- const char *attrs[1];
- const char *errstr = NULL;
-+ const char *value = NULL;
- const char *filter = NULL;
- int result = LDAP_SUCCESS;
- int ldb_ret;
-@@ -1461,21 +1463,31 @@ static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call)
- dn = ldb_dn_new(local_ctx, samdb, req->dn);
- NT_STATUS_HAVE_NO_MEMORY(dn);
-
-+ compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
-+ NT_STATUS_HAVE_NO_MEMORY(compare_r);
-+
- DBG_DEBUG("dn: [%s]\n", req->dn);
-- filter = talloc_asprintf(local_ctx, "(%s=%*s)", req->attribute,
-- (int)req->value.length, req->value.data);
-+
-+ if (!ldb_valid_attr_name(req->attribute)) {
-+ result = LDAP_INVALID_ATTRIBUTE_SYNTAX;
-+ errstr = "Invalid Compare attribute name";
-+ goto reply;
-+ }
-+ value = ldb_binary_encode(local_ctx, req->value);
-+ NT_STATUS_HAVE_NO_MEMORY(value);
-+
-+ filter = talloc_asprintf(local_ctx, "%s=%s", req->attribute, value);
- NT_STATUS_HAVE_NO_MEMORY(filter);
-
- DBG_DEBUG("attribute: [%s]\n", filter);
-
- attrs[0] = NULL;
-
-- compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
-- NT_STATUS_HAVE_NO_MEMORY(compare_r);
--
- if (result == LDAP_SUCCESS) {
-- ldb_ret = ldb_search(samdb, local_ctx, &res,
-- dn, LDB_SCOPE_BASE, attrs, "%s", filter);
-+ ldb_ret = dsdb_search(samdb, local_ctx, &res,
-+ dn, LDB_SCOPE_BASE, attrs,
-+ DSDB_MARK_REQ_UNTRUSTED,
-+ "%s", filter);
- if (ldb_ret != LDB_SUCCESS) {
- result = map_ldb_error(local_ctx, ldb_ret,
- ldb_errstring(samdb), &errstr);
-@@ -1497,6 +1509,7 @@ static NTSTATUS ldapsrv_CompareRequest(struct ldapsrv_call *call)
- }
- }
-
-+reply:
- compare = &compare_r->msg->r.CompareResponse;
- compare->dn = NULL;
- compare->resultcode = result;
---
-2.43.0
-
diff -Nru samba-4.22.10+dfsg/debian/patches/series samba-4.22.11+dfsg/debian/patches/series
--- samba-4.22.10+dfsg/debian/patches/series 2026-07-19 20:34:00.000000000 +0300
+++ samba-4.22.11+dfsg/debian/patches/series 2026-07-28 15:00:33.000000000 +0300
@@ -22,4 +22,3 @@
meaningful-error-if-no-python3-markdown.patch
ctdb-use-run-instead-of-var-run.patch
replace-xpg-strerror.patch
-2026-jul-sec-update-bug-16039-v4-22-combined.patch
diff -Nru samba-4.22.10+dfsg/VERSION samba-4.22.11+dfsg/VERSION
--- samba-4.22.10+dfsg/VERSION 2026-05-15 16:51:43.443060200 +0300
+++ samba-4.22.11+dfsg/VERSION 2026-07-21 18:37:04.175275800 +0300
@@ -27,7 +27,7 @@
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=22
-SAMBA_VERSION_RELEASE=10
+SAMBA_VERSION_RELEASE=11
########################################################
# If a official release has a serious bug #
diff -Nru samba-4.22.10+dfsg/WHATSNEW.txt samba-4.22.11+dfsg/WHATSNEW.txt
--- samba-4.22.10+dfsg/WHATSNEW.txt 2026-05-15 16:51:43.444060000 +0300
+++ samba-4.22.11+dfsg/WHATSNEW.txt 2026-07-21 18:37:04.175275800 +0300
@@ -1,4 +1,112 @@
===============================
+ Release Notes for Samba 4.22.11
+ July 28, 2026
+ ===============================
+
+
+This is a security release in order to address the following defects:
+
+o CVE-2026-6949: TSIG packet with name compression can crash DNS
+
+ Incorrect size calculations when a TSIG record contains
+ compressed names can lead to a large out-of-bounds write
+ causing the server to crash.
+
+ https://www.samba.org/samba/security/CVE-2026-6949.html
+
+
+o CVE-2026-58216: An authenticated user could possibly crash a KDC process
+
+ A kpasswd packet that contains malformed ASN.1 might cause
+ the server to access 6 bytes of unallocated memory. This
+ memory is not exposed to the user, but in some
+ circumstances the server could crash.
+
+ https://www.samba.org/samba/security/CVE-2026-58216.html
+
+
+o CVE-2026-58218: DNS signing DoS via TKEY name cache exhaustion
+
+ An unauthenticated user can repeatedly register names TKEY
+ names, which floods a cache causing legitimate TKEYs to be
+ expunged. This can practically block the use DNS TSIG
+ signing.
+
+ https://www.samba.org/samba/security/CVE-2026-58218.html
+
+
+o CVE-2026-58221: Samba AD authenticated LDAP access domain takeover
+
+ Samba AD low-privilege authenticated LDAP access allows
+ modifications to internal LDB special DNs, which permits a
+ domain takeover.
+
+ https://www.samba.org/samba/security/CVE-2026-58221.html
+
+
+o CVE-2026-58222: Samba AD LDAP Compare filter injection and trusted-request
+ confusion disclose protected attributes
+
+ An ordinary authenticated domain user can bypass access
+ checks and query confidential Active Directory attributes
+ (such as KDS root keys) via LDAP Compare requests. Due to a
+ filter injection flaw and trusted execution context, the
+ LDAP Compare operation can be turned into a
+ protected-attribute disclosure oracle.
+
+ https://www.samba.org/samba/security/CVE-2026-58222.html
+
+
+o CVE-2026-58224 The CTDB protocol has bounds checking issues
+
+ CTDB fails to do integrity checking of received packets.
+ This includes failure to check field lengths against packet
+ lengths when unmarshalling packets.
+
+ https://www.samba.org/samba/security/CVE-2026-58224.html
+
+
+Changes since 4.22.10
+---------------------
+
+o Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+ * BUG 16087: CVE-2026-58216
+
+o Volker Lendecke <vl at samba.org>
+ * BUG 16115: CVE-2026-58218
+
+o Stefan Metzmacher <metze at samba.org>
+ * BUG 16083: CVE-2026-6949
+ * BUG 16147: CVE-2026-58221
+ * BUG 16148: CVE-2026-58222
+
+o Martin Schwenke <mschwenke at ddn.com>
+ * BUG 16085: CVE-2026-58224
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical:matrix.org matrix room, or
+#samba-technical IRC channel on irc.libera.chat.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the Samba 4.1 and newer product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+ ===============================
Release Notes for Samba 4.22.10
May 26, 2026
===============================
@@ -120,8 +228,7 @@
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
==============================
Release Notes for Samba 4.22.9
April 09, 2026
diff -Nru samba-4.22.10+dfsg/ctdb/common/ctdb_io.c samba-4.22.11+dfsg/ctdb/common/ctdb_io.c
--- samba-4.22.10+dfsg/ctdb/common/ctdb_io.c 2025-01-30 16:57:43.587315800 +0300
+++ samba-4.22.11+dfsg/ctdb/common/ctdb_io.c 2026-07-21 18:37:04.175275800 +0300
@@ -115,7 +115,25 @@
return;
}
- /* Extract complete packet */
+ /*
+ * Extract complete packet
+ *
+ * Yes, this allows an out-of-memory denial of service (DoS)
+ * attack if a number of packets are received with
+ * unreasonable packet sizes, noting that the maximum packet
+ * size is ~4GB. The CTDB protocol was not designed with a
+ * maximum packet size in mind, so CTDB may send very large
+ * valid packets. This means that imposing an arbitrary limit
+ * on incoming packets is not reasonable. Arguments that
+ * header fields, such as magic and/or version, should be
+ * validated before allocating a packet buffer are spurious
+ * from a security perspective because an attacker attempting
+ * DoS can send packets with valid headers. The private
+ * network and ctdbd socket should be secured against
+ * untrusted access, so reports that this possible DoS vector
+ * represents a security issue will be ignored. See the
+ * "Private addresses" section in ctdb(7) for more details.
+ */
data = talloc_memdup(queue->data_pool,
queue->buffer.data + queue->buffer.offset,
pkt_size);
diff -Nru samba-4.22.10+dfsg/ctdb/common/pkt_read.c samba-4.22.11+dfsg/ctdb/common/pkt_read.c
--- samba-4.22.10+dfsg/ctdb/common/pkt_read.c 2025-01-30 16:57:43.588315700 +0300
+++ samba-4.22.11+dfsg/ctdb/common/pkt_read.c 2026-07-21 18:37:04.175275800 +0300
@@ -146,6 +146,25 @@
return;
}
+ /*
+ * Allocate buffer for entire packet
+ *
+ * Yes, this allows an out-of-memory denial of service (DoS)
+ * attack if a number of packets are received with
+ * unreasonable packet sizes, noting that the maximum packet
+ * size is ~4GB. The CTDB protocol was not designed with a
+ * maximum packet size in mind, so CTDB may send very large
+ * valid packets. This means that imposing an arbitrary limit
+ * on incoming packets is not reasonable. Arguments that
+ * header fields, such as magic and/or version, should be
+ * validated before allocating a packet buffer are spurious
+ * from a security perspective because an attacker attempting
+ * DoS can send packets with valid headers. The private
+ * network and ctdbd socket should be secured against
+ * untrusted access, so reports that this possible DoS vector
+ * represents a security issue will be ignored. See the
+ * "Private addresses" section in ctdb(7) for more details.
+ */
if (state->use_fixed) {
/* switch to dynamic buffer */
tmp = talloc_array(state, uint8_t, state->total + more);
diff -Nru samba-4.22.10+dfsg/ctdb/common/sock_daemon.c samba-4.22.11+dfsg/ctdb/common/sock_daemon.c
--- samba-4.22.10+dfsg/ctdb/common/sock_daemon.c 2025-01-30 16:57:43.590315800 +0300
+++ samba-4.22.11+dfsg/ctdb/common/sock_daemon.c 2026-07-21 18:37:04.179276000 +0300
@@ -204,6 +204,8 @@
static int socket_setup(const char *sockpath, bool remove_before_use)
{
struct sockaddr_un addr;
+ const char *t;
+ bool test_mode_enabled = false;
size_t len;
int ret, fd;
@@ -239,6 +241,30 @@
close(fd);
return -1;
}
+
+ t = getenv("CTDB_TEST_MODE");
+ if (t != NULL) {
+ test_mode_enabled = true;
+ }
+
+ if (!test_mode_enabled) {
+ /* Behaviour of fchown(2) is undefined on sockets */
+ ret = chown(sockpath, geteuid(), getegid());
+ if (ret != 0) {
+ D_ERR("Unable to secure (chown) socket '%s'\n",
+ sockpath);
+ close(fd);
+ return -1;
+ }
+ }
+
+ /* Behaviour of fchmod(2) is undefined on sockets */
+ ret = chmod(sockpath, 0700);
+ if (ret != 0) {
+ D_ERR("Unable to secure (chmod) socket '%s'\n", sockpath);
+ close(fd);
+ return -1;
+ }
ret = listen(fd, 10);
if (ret != 0) {
diff -Nru samba-4.22.10+dfsg/ctdb/doc/ctdb.7.xml samba-4.22.11+dfsg/ctdb/doc/ctdb.7.xml
--- samba-4.22.10+dfsg/ctdb/doc/ctdb.7.xml 2025-02-12 16:24:20.343143500 +0300
+++ samba-4.22.11+dfsg/ctdb/doc/ctdb.7.xml 2026-07-21 18:37:04.179276000 +0300
@@ -242,14 +242,25 @@
services provided by the cluster.
</para>
<para>
- It is strongly recommended that the private addresses are
- configured on a private network that is separate from client
- networks. This is because the CTDB protocol is both
- unauthenticated and unencrypted. If clients share the private
- network then steps need to be taken to stop injection of
- packets to relevant ports on the private addresses. It is
- also likely that CTDB protocol traffic between nodes could
- leak sensitive information if it can be intercepted.
+ It is strongly recommended that the private addresses are
+ configured on a private network that is separate from client
+ networks. This is because <emphasis>the CTDB protocol is both
+ unauthenticated and unencrypted</emphasis>. If clients share
+ the private network then steps need to be taken to stop
+ injection of packets to relevant ports on the private
+ addresses. It is also likely that CTDB protocol traffic
+ between nodes could leak sensitive information if it can be
+ intercepted or manipulated.
+ </para>
+ <para>
+ In summary, the private network should not be accessible by
+ untrusted sources. We can't say "must not" because this can't
+ be enforced by CTDB, so we can only make a strong
+ recommendation. However, for this reason, future bugs in the
+ CTDB protocol used over the private network will be fixed as
+ regular bugs without following the Samba security process.
+ The same is true of local CTDB protocols used for Unix domain
+ socket and other communication.
</para>
<para>
diff -Nru samba-4.22.10+dfsg/ctdb/protocol/protocol_basic.c samba-4.22.11+dfsg/ctdb/protocol/protocol_basic.c
--- samba-4.22.10+dfsg/ctdb/protocol/protocol_basic.c 2025-01-30 16:57:43.603315800 +0300
+++ samba-4.22.11+dfsg/ctdb/protocol/protocol_basic.c 2026-07-21 18:37:04.179276000 +0300
@@ -247,7 +247,8 @@
int ctdb_string_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
const char **out, size_t *npull)
{
- const char *str;
+ const char *str = NULL;
+ size_t len = 0;
if (buflen > UINT32_MAX) {
return EMSGSIZE;
@@ -265,7 +266,14 @@
}
*out = str;
- *npull = ctdb_string_len(&str);
+ /*
+ * Avoid claiming to have consumed more than buflen.
+ * ctdb_string_len() returns buflen + 1 if there is no
+ * NUL-terminator within buflen, so no NUL was actually
+ * consumed (so no +1 needed).
+ */
+ len = ctdb_string_len(&str);
+ *npull = MIN(buflen, len);
return 0;
}
@@ -311,7 +319,8 @@
if (ret != 0) {
return ret;
}
- offset += np;
+ /* Always consume the specified number bytes */
+ offset += u32;
*npull = offset;
return 0;
diff -Nru samba-4.22.10+dfsg/ctdb/protocol/protocol_types.c samba-4.22.11+dfsg/ctdb/protocol/protocol_types.c
--- samba-4.22.10+dfsg/ctdb/protocol/protocol_types.c 2025-01-30 16:57:43.605316000 +0300
+++ samba-4.22.11+dfsg/ctdb/protocol/protocol_types.c 2026-07-21 18:37:04.179276000 +0300
@@ -838,6 +838,7 @@
size_t *npull)
{
struct ctdb_statistics_list *val;
+ struct ctdb_statistics dummy = {};
size_t offset = 0, np;
int ret, i;
@@ -863,6 +864,11 @@
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;
@@ -925,6 +931,7 @@
struct ctdb_vnn_map *val;
size_t offset = 0, np;
uint32_t i;
+ uint32_t dummy = 0;
int ret;
val = talloc(mem_ctx, struct ctdb_vnn_map);
@@ -950,6 +957,11 @@
goto done;
}
+ if ((uint64_t)val->size * ctdb_uint32_len(&dummy) > buflen - offset) {
+ ret = EMSGSIZE;
+ goto fail;
+ }
+
val->map = talloc_array(val, uint32_t, val->size);
if (val->map == NULL) {
ret = ENOMEM;
@@ -1082,6 +1094,7 @@
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;
@@ -1102,6 +1115,11 @@
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;
@@ -2362,6 +2380,7 @@
struct ctdb_connection_list **out, size_t *npull)
{
struct ctdb_connection_list *val;
+ struct ctdb_connection dummy = {};
size_t offset = 0, np;
uint32_t i;
int ret;
@@ -2382,6 +2401,11 @@
goto done;
}
+ if ((uint64_t)val->num * ctdb_connection_len(&dummy) > buflen - offset) {
+ ret = EMSGSIZE;
+ goto fail;
+ }
+
val->conn = talloc_array(val, struct ctdb_connection, val->num);
if (val->conn == NULL) {
ret = ENOMEM;
@@ -3399,6 +3423,7 @@
struct ctdb_tickle_list **out, size_t *npull)
{
struct ctdb_tickle_list *val;
+ struct ctdb_connection dummy = {};
size_t offset = 0, np;
uint32_t i;
int ret;
@@ -3426,6 +3451,11 @@
goto done;
}
+ if ((uint64_t)val->num * ctdb_connection_len(&dummy) > buflen - offset) {
+ ret = EMSGSIZE;
+ goto fail;
+ }
+
val->conn = talloc_array(val, struct ctdb_connection, val->num);
if (val->conn == NULL) {
ret = ENOMEM;
@@ -3744,6 +3774,7 @@
struct ctdb_public_ip_list **out, size_t *npull)
{
struct ctdb_public_ip_list *val;
+ struct ctdb_public_ip dummy = {};
size_t offset = 0, np;
uint32_t i;
int ret;
@@ -3764,6 +3795,11 @@
goto done;
}
+ if ((uint64_t)val->num * ctdb_public_ip_len(&dummy) > buflen - offset) {
+ ret = EMSGSIZE;
+ goto fail;
+ }
+
val->ip = talloc_array(val, struct ctdb_public_ip, val->num);
if (val->ip == NULL) {
ret = ENOMEM;
@@ -3899,6 +3935,7 @@
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;
@@ -3919,6 +3956,12 @@
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;
@@ -4099,6 +4142,7 @@
struct ctdb_script_list **out, size_t *npull)
{
struct ctdb_script_list *val;
+ struct ctdb_script dummy = {};
size_t offset = 0, np;
uint32_t i;
int ret;
@@ -4132,6 +4176,12 @@
goto done;
}
+ if ((uint64_t)val->num_scripts * ctdb_script_len(&dummy)
+ > buflen - offset) {
+ ret = EMSGSIZE;
+ goto fail;
+ }
+
val->script = talloc_array(val, struct ctdb_script, val->num_scripts);
if (val->script == NULL) {
ret = ENOMEM;
@@ -4375,6 +4425,7 @@
struct ctdb_iface_list **out, size_t *npull)
{
struct ctdb_iface_list *val;
+ struct ctdb_iface dummy = {};
size_t offset = 0, np;
uint32_t i;
int ret;
@@ -4395,6 +4446,11 @@
goto done;
}
+ if ((uint64_t)val->num * ctdb_iface_len(&dummy) > buflen - offset) {
+ ret = EMSGSIZE;
+ goto fail;
+ }
+
val->iface = talloc_array(val, struct ctdb_iface, val->num);
if (val->iface == NULL) {
ret = ENOMEM;
@@ -5322,6 +5378,10 @@
val->num = buflen / ctdb_g_lock_len(&lock);
+ /*
+ * No array count pre-check needed because val->num is
+ * calculated from buflen
+ */
val->lock = talloc_array(val, struct ctdb_g_lock, val->num);
if (val->lock == NULL) {
ret = ENOMEM;
diff -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_call.c samba-4.22.11+dfsg/ctdb/server/ctdb_call.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_call.c 2025-01-30 16:57:43.606315900 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_call.c 2026-07-21 18:37:04.179276000 +0300
@@ -583,6 +583,9 @@
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 @@
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 @@
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 @@
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_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 @@
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 -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_client.c samba-4.22.11+dfsg/ctdb/server/ctdb_client.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_client.c 2025-01-30 16:57:43.607315800 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_client.c 2026-07-21 18:37:04.179276000 +0300
@@ -193,8 +193,17 @@
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 -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_control.c samba-4.22.11+dfsg/ctdb/server/ctdb_control.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_control.c 2025-01-30 16:57:43.608316000 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_control.c 2026-07-21 18:37:04.179276000 +0300
@@ -933,11 +933,20 @@
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;
@@ -957,10 +966,20 @@
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",
diff -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_ltdb_server.c samba-4.22.11+dfsg/ctdb/server/ctdb_ltdb_server.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_ltdb_server.c 2025-01-30 16:57:43.609315900 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_ltdb_server.c 2026-07-21 18:37:04.179276000 +0300
@@ -1109,8 +1109,15 @@
struct ctdb_db_context *db;
struct ctdb_node *node = ctdb->nodes[ctdb->pnn];
struct ctdb_client *client = NULL;
+ char *t = NULL;
uint32_t opcode;
+ t = memchr(indata.dptr, '\0', indata.dsize);
+ if (t == NULL) {
+ DBG_ERR("Invalid packet\n");
+ return -1;
+ }
+
if (ctdb->tunable.allow_client_db_attach == 0) {
DEBUG(DEBUG_ERR, ("DB Attach to database %s denied by tunable "
"AllowClientDBAccess == 0\n", db_name));
diff -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_persistent.c samba-4.22.11+dfsg/ctdb/server/ctdb_persistent.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_persistent.c 2025-01-30 16:57:43.610315800 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_persistent.c 2026-07-21 18:37:04.179276000 +0300
@@ -182,6 +182,16 @@
struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
struct ctdb_db_context *ctdb_db;
+ if (recdata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
+ DBG_ERR("Invalid packet\n");
+ return -1;
+ }
+ if (m->count >
+ recdata.dsize - offsetof(struct ctdb_marshall_buffer, data)) {
+ DBG_ERR("Invalid packet\n");
+ return -1;
+ }
+
if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
DEBUG(DEBUG_INFO,("rejecting ctdb_control_trans3_commit when recovery active\n"));
return -1;
diff -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_recover.c samba-4.22.11+dfsg/ctdb/server/ctdb_recover.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_recover.c 2026-05-15 16:51:43.449060200 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_recover.c 2026-07-21 18:37:04.179276000 +0300
@@ -36,6 +36,8 @@
#include "ctdb_private.h"
#include "ctdb_client.h"
+#include "protocol/protocol_private.h"
+
#include "common/system.h"
#include "common/common.h"
#include "common/logging.h"
@@ -67,24 +69,32 @@
int
ctdb_control_setvnnmap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
{
- struct ctdb_vnn_map_wire *map = (struct ctdb_vnn_map_wire *)indata.dptr;
+ struct ctdb_vnn_map *new = NULL;
+ size_t npull = 0;
+ int ret = 0;
if (ctdb->recovery_mode != CTDB_RECOVERY_ACTIVE) {
DEBUG(DEBUG_ERR, ("Attempt to set vnnmap when not in recovery\n"));
return -1;
}
- talloc_free(ctdb->vnn_map);
-
- ctdb->vnn_map = talloc(ctdb, struct ctdb_vnn_map);
- CTDB_NO_MEMORY(ctdb, ctdb->vnn_map);
-
- ctdb->vnn_map->generation = map->generation;
- ctdb->vnn_map->size = map->size;
- ctdb->vnn_map->map = talloc_array(ctdb->vnn_map, uint32_t, map->size);
- CTDB_NO_MEMORY(ctdb, ctdb->vnn_map->map);
+ ret = ctdb_vnn_map_pull(indata.dptr, indata.dsize, ctdb, &new, &npull);
+ if (ret != 0) {
+ switch (ret) {
+ case ENOMEM:
+ DBG_ERR("Memory allocation error\n");
+ break;
+ case EMSGSIZE:
+ DBG_ERR("Invalid packet\n");
+ break;
+ default:
+ DBG_ERR("Unexpected error (%d)\n", ret);
+ }
+ return -1;
+ }
- memcpy(ctdb->vnn_map->map, map->map, sizeof(uint32_t)*map->size);
+ talloc_free(ctdb->vnn_map);
+ ctdb->vnn_map = new;
return 0;
}
@@ -1052,6 +1062,12 @@
return -1;
}
+ if (reply->count >
+ indata.dsize - offsetof(struct ctdb_marshall_buffer, data)) {
+ DBG_ERR("Invalid packet\n");
+ return -1;
+ }
+
ctdb_db = find_ctdb_db(ctdb, reply->db_id);
if (!ctdb_db) {
DEBUG(DEBUG_ERR,(__location__ " Unknown db 0x%08x\n", reply->db_id));
diff -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_traverse.c samba-4.22.11+dfsg/ctdb/server/ctdb_traverse.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_traverse.c 2025-01-30 16:57:43.613315800 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_traverse.c 2026-07-21 18:37:04.179276000 +0300
@@ -561,13 +561,17 @@
int32_t ctdb_control_traverse_data(struct ctdb_context *ctdb, TDB_DATA data, TDB_DATA *outdata)
{
struct ctdb_rec_data_old *d = (struct ctdb_rec_data_old *)data.dptr;
+ size_t rec_data_header_len = offsetof(struct ctdb_rec_data_old, data);
struct ctdb_traverse_all_handle *state;
TDB_DATA key;
ctdb_traverse_fn_t callback;
void *private_data;
- if (data.dsize < sizeof(uint32_t) || data.dsize != d->length) {
- DEBUG(DEBUG_ERR,("Bad record size in ctdb_control_traverse_data\n"));
+ if (data.dsize < rec_data_header_len ||
+ data.dsize != d->length ||
+ d->keylen > d->length - rec_data_header_len ||
+ d->datalen > d->length - rec_data_header_len - d->keylen) {
+ DBG_ERR("Invalid packet\n");
return -1;
}
diff -Nru samba-4.22.10+dfsg/ctdb/server/ctdb_update_record.c samba-4.22.11+dfsg/ctdb/server/ctdb_update_record.c
--- samba-4.22.10+dfsg/ctdb/server/ctdb_update_record.c 2025-01-30 16:57:43.614315700 +0300
+++ samba-4.22.11+dfsg/ctdb/server/ctdb_update_record.c 2026-07-21 18:37:04.179276000 +0300
@@ -318,6 +318,16 @@
struct childwrite_handle *handle;
struct ctdb_marshall_buffer *m = (struct ctdb_marshall_buffer *)recdata.dptr;
+ if (recdata.dsize < offsetof(struct ctdb_marshall_buffer, data)) {
+ DBG_ERR("Invalid packet\n");
+ return -1;
+ }
+ if (m->count >
+ recdata.dsize - offsetof(struct ctdb_marshall_buffer, data)) {
+ DBG_ERR("Invalid packet\n");
+ return -1;
+ }
+
if (ctdb->recovery_mode != CTDB_RECOVERY_NORMAL) {
DEBUG(DEBUG_INFO,("rejecting ctdb_control_update_record when recovery active\n"));
return -1;
diff -Nru samba-4.22.10+dfsg/libcli/security/security_descriptor.c samba-4.22.11+dfsg/libcli/security/security_descriptor.c
--- samba-4.22.10+dfsg/libcli/security/security_descriptor.c 2025-02-12 16:24:20.370143400 +0300
+++ samba-4.22.11+dfsg/libcli/security/security_descriptor.c 2026-07-21 18:37:04.183276200 +0300
@@ -22,6 +22,7 @@
#include "replace.h"
#include "libcli/security/security.h"
#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_security.h"
/*
return a blank security descriptor (no owners, dacl or sacl)
@@ -53,6 +54,7 @@
const struct security_acl *oacl)
{
struct security_acl *nacl;
+ enum ndr_err_code ndr_err;
if (oacl == NULL) {
return NULL;
@@ -67,17 +69,8 @@
return NULL;
}
- *nacl = (struct security_acl) {
- .revision = oacl->revision,
- .size = oacl->size,
- .num_aces = oacl->num_aces,
- };
- if (nacl->num_aces == 0) {
- return nacl;
- }
-
- nacl->aces = (struct security_ace *)talloc_memdup (nacl, oacl->aces, sizeof(struct security_ace) * oacl->num_aces);
- if (nacl->aces == NULL) {
+ ndr_err = ndr_deepcopy_struct(security_acl, oacl, nacl, nacl);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
goto failed;
}
diff -Nru samba-4.22.10+dfsg/librpc/idl/dns.idl samba-4.22.11+dfsg/librpc/idl/dns.idl
--- samba-4.22.10+dfsg/librpc/idl/dns.idl 2025-01-30 16:57:43.823315900 +0300
+++ samba-4.22.11+dfsg/librpc/idl/dns.idl 2026-07-21 18:37:04.183276200 +0300
@@ -251,6 +251,12 @@
} dns_rdata;
typedef [flag(LIBNDR_PRINT_ARRAY_HEX|NDR_NOALIGN),nopush,nopull] struct {
+ /*
+ * This is the start offset of this
+ * dns_res_rec relative to the start of
+ * dns_name_packet buffer.
+ */
+ [ignore] uint32 start_ndr_offset;
dns_string name;
dns_qtype rr_type;
dns_qclass rr_class;
diff -Nru samba-4.22.10+dfsg/librpc/ndr/ndr_dns.c samba-4.22.11+dfsg/librpc/ndr/ndr_dns.c
--- samba-4.22.10+dfsg/librpc/ndr/ndr_dns.c 2025-01-30 16:57:43.834315800 +0300
+++ samba-4.22.11+dfsg/librpc/ndr/ndr_dns.c 2026-07-21 18:37:04.183276200 +0300
@@ -276,6 +276,17 @@
ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
LIBNDR_FLAG_NOALIGN);
if (ndr_flags & NDR_SCALARS) {
+ /*
+ * Remember the start offset in order
+ * to know how to truncate before the
+ * last dns_res_rec in order to do
+ * the correct TSIG calculation.
+ *
+ * Note that we just set LIBNDR_FLAG_NOALIGN
+ * above, so ndr_pull_align is a no-op.
+ */
+ r->start_ndr_offset = ndr->offset;
+
NDR_CHECK(ndr_pull_align(ndr, 4));
NDR_CHECK(ndr_pull_dns_string(ndr, NDR_SCALARS, &r->name));
NDR_CHECK(ndr_pull_dns_qtype(ndr, NDR_SCALARS, &r->rr_type));
diff -Nru samba-4.22.10+dfsg/source4/dns_server/dns_crypto.c samba-4.22.11+dfsg/source4/dns_server/dns_crypto.c
--- samba-4.22.10+dfsg/source4/dns_server/dns_crypto.c 2025-01-30 16:57:44.144316000 +0300
+++ samba-4.22.11+dfsg/source4/dns_server/dns_crypto.c 2026-07-21 18:37:04.183276200 +0300
@@ -36,6 +36,8 @@
struct dns_res_rec *old,
struct dns_res_rec *new_rec)
{
+ new_rec->start_ndr_offset = 0;
+
new_rec->name = talloc_strdup(mem_ctx, old->name);
W_ERROR_HAVE_NO_MEMORY(new_rec->name);
@@ -101,7 +103,7 @@
NTSTATUS status;
enum ndr_err_code ndr_err;
uint16_t i, arcount = 0;
- DATA_BLOB tsig_blob, fake_tsig_blob, sig;
+ DATA_BLOB fake_tsig_blob, sig;
uint8_t *buffer = NULL;
size_t buffer_len = 0, packet_len = 0;
struct dns_server_tkey *tkey = NULL;
@@ -131,6 +133,22 @@
state->sign = true;
DBG_DEBUG("Got TSIG\n");
+ /*
+ * We need to keep the input packet exactly like we got it,
+ * but we need to cut off the tsig record.
+ *
+ * DNS packets can not be larger than UINT16_MAX,
+ * the size of the UDP payload is uint16_t and
+ * there's a uint16_t length header for TCP.
+ *
+ * And the start offset of the last
+ * additional record can't be larger than
+ * the whole packet.
+ */
+ packet_len = packet->additional[i].start_ndr_offset;
+ SMB_ASSERT(in->length <= UINT16_MAX);
+ SMB_ASSERT(in->length > packet_len);
+
state->tsig = talloc_zero(state->mem_ctx, struct dns_res_rec);
if (state->tsig == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
@@ -205,14 +223,6 @@
check_rec->other_size = 0;
check_rec->other_data = NULL;
- ndr_err = ndr_push_struct_blob(&tsig_blob, mem_ctx, state->tsig,
- (ndr_push_flags_fn_t)ndr_push_dns_res_rec);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- DEBUG(1, ("Failed to push packet: %s!\n",
- ndr_errstr(ndr_err)));
- return DNS_ERR(SERVER_FAILURE);
- }
-
ndr_err = ndr_push_struct_blob(&fake_tsig_blob, mem_ctx, check_rec,
(ndr_push_flags_fn_t)ndr_push_dns_fake_tsig_rec);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -221,9 +231,19 @@
return DNS_ERR(SERVER_FAILURE);
}
- /* we need to work some magic here. we need to keep the input packet
- * exactly like we got it, but we need to cut off the tsig record */
- packet_len = in->length - tsig_blob.length;
+ /*
+ * We already asserted packet_len < UINT16_MAX
+ * above, and struct ndr_push has alloc_size and
+ * offset as uint32_t, so it's really unlikely
+ * to overflow buffer_len. For SIZE_MAX == UINT32_MAX,
+ * the following check might be important, but
+ * just lets do it always.
+ */
+ if (fake_tsig_blob.length > (SIZE_MAX - UINT16_MAX)) {
+ DBG_WARNING("fake_tsig_blob.length=%zu too large!\n",
+ fake_tsig_blob.length);
+ return DNS_ERR(SERVER_FAILURE);
+ }
buffer_len = packet_len + fake_tsig_blob.length;
buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len);
if (buffer == NULL) {
diff -Nru samba-4.22.10+dfsg/source4/dns_server/dns_query.c samba-4.22.11+dfsg/source4/dns_server/dns_query.c
--- samba-4.22.10+dfsg/source4/dns_server/dns_query.c 2025-01-30 16:57:44.144316000 +0300
+++ samba-4.22.11+dfsg/source4/dns_server/dns_query.c 2026-07-21 18:37:04.183276200 +0300
@@ -654,7 +654,8 @@
return WERR_OK;
}
-static NTSTATUS create_tkey(struct dns_server *dns,
+static NTSTATUS create_tkey(TALLOC_CTX *mem_ctx,
+ struct dns_server *dns,
const char* name,
const char* algorithm,
const struct tsocket_address *remote_address,
@@ -662,7 +663,6 @@
struct dns_server_tkey **tkey)
{
NTSTATUS status;
- struct dns_server_tkey_store *store = dns->tkeys;
struct dns_server_tkey *k = NULL;
if (strcmp(algorithm, "gss-tsig") == 0) {
@@ -673,20 +673,20 @@
return NT_STATUS_ACCESS_DENIED;
}
- k = talloc_zero(store, struct dns_server_tkey);
+ k = talloc_zero(mem_ctx, struct dns_server_tkey);
if (k == NULL) {
- return NT_STATUS_NO_MEMORY;
+ goto nomem;
}
k->name = talloc_strdup(k, name);
if (k->name == NULL) {
- return NT_STATUS_NO_MEMORY;
+ goto nomem;
}
k->algorithm = talloc_strdup(k, algorithm);
if (k->algorithm == NULL) {
- return NT_STATUS_NO_MEMORY;
+ goto nomem;
}
/*
@@ -704,8 +704,7 @@
&k->gensec);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
- *tkey = NULL;
- return status;
+ goto fail;
}
gensec_want_feature(k->gensec, GENSEC_FEATURE_SIGN);
@@ -715,8 +714,7 @@
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to set remote address into GENSEC: %s\n",
nt_errstr(status)));
- *tkey = NULL;
- return status;
+ goto fail;
}
status = gensec_set_local_address(k->gensec,
@@ -724,8 +722,7 @@
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to set local address into GENSEC: %s\n",
nt_errstr(status)));
- *tkey = NULL;
- return status;
+ goto fail;
}
status = gensec_start_mech_by_oid(k->gensec, GENSEC_OID_SPNEGO);
@@ -733,18 +730,29 @@
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("Failed to start GENSEC server code: %s\n",
nt_errstr(status)));
- *tkey = NULL;
- return status;
+ goto fail;
}
+ *tkey = k;
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+fail:
+ TALLOC_FREE(k);
+ *tkey = NULL;
+ return status;
+}
+
+static void add_tkey(struct dns_server_tkey_store *store,
+ struct dns_server_tkey **tkey)
+{
TALLOC_FREE(store->tkeys[store->next_idx]);
- store->tkeys[store->next_idx] = k;
+ store->tkeys[store->next_idx] = talloc_move(store->tkeys, tkey);
+
(store->next_idx)++;
store->next_idx %= store->size;
-
- *tkey = k;
- return NT_STATUS_OK;
}
static NTSTATUS accept_gss_ticket(TALLOC_CTX *mem_ctx,
@@ -860,6 +868,7 @@
struct dns_server_tkey *tkey;
DATA_BLOB key;
DATA_BLOB reply;
+ bool created = false;
tkey = dns_find_tkey(dns->tkeys, in->questions[0].name);
if (tkey != NULL && tkey->complete) {
@@ -870,15 +879,19 @@
}
if (tkey == NULL) {
- status = create_tkey(dns, in->questions[0].name,
- in_tkey->rdata.tkey_record.algorithm,
- state->remote_address,
- state->local_address,
- &tkey);
+ status = create_tkey(
+ mem_ctx,
+ dns,
+ in->questions[0].name,
+ in_tkey->rdata.tkey_record.algorithm,
+ state->remote_address,
+ state->local_address,
+ &tkey);
if (!NT_STATUS_IS_OK(status)) {
ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
return ntstatus_to_werror(status);
}
+ created = true;
}
key.data = in_tkey->rdata.tkey_record.key_data;
@@ -903,6 +916,9 @@
if (state->key_name == NULL) {
return WERR_NOT_ENOUGH_MEMORY;
}
+ if (created) {
+ add_tkey(dns->tkeys, &tkey);
+ }
} else {
DEBUG(1, ("GSS key negotiation returned %s\n", nt_errstr(status)));
ret_tkey->rdata.tkey_record.error = DNS_RCODE_BADKEY;
diff -Nru samba-4.22.10+dfsg/source4/dsdb/samdb/ldb_modules/audit_util.c samba-4.22.11+dfsg/source4/dsdb/samdb/ldb_modules/audit_util.c
--- samba-4.22.10+dfsg/source4/dsdb/samdb/ldb_modules/audit_util.c 2025-01-30 16:57:44.154316000 +0300
+++ samba-4.22.11+dfsg/source4/dsdb/samdb/ldb_modules/audit_util.c 2026-07-21 18:37:04.183276200 +0300
@@ -694,3 +694,183 @@
DBG_ERR("Unable to create ldb attributes JSON audit message\n");
return attributes;
}
+
+/*
+ * @brief Generate a human readable string, detailing attributes in a message
+ *
+ * For modify operations each attribute is prefixed with the action.
+ * Normal values are enclosed in []
+ * Base64 values are enclosed in {}
+ * Truncated values are indicated by three trailing dots "..."
+ *
+ * @param[in] ldb the ldb_context
+ * @param[out] buffer the attributes will be appended to the buffer.
+ * assumed to have been allocated via talloc.
+ * @param[in] operation the operation type
+ * @param[in] message the message to process
+ *
+ * @return a pointer to buffer
+ *
+ */
+char *dsdb_audit_log_attributes(
+ struct ldb_context *ldb,
+ char *buffer,
+ enum ldb_request_type operation,
+ const struct ldb_message *message)
+{
+ size_t i, j;
+ for (i=0;i<message->num_elements;i++) {
+ if (i > 0) {
+ buffer = talloc_asprintf_append_buffer(buffer, " ");
+ }
+
+ if (message->elements[i].name == NULL) {
+ ldb_debug(
+ ldb,
+ LDB_DEBUG_ERROR,
+ "Error: Invalid element name (NULL) at "
+ "position %zu", i);
+ return NULL;
+ }
+
+ if (operation == LDB_MODIFY) {
+ const char *action =NULL;
+ action = dsdb_audit_get_modification_action(
+ message->elements[i].flags);
+ buffer = talloc_asprintf_append_buffer(
+ buffer,
+ "%s: %s ",
+ action,
+ message->elements[i].name);
+ } else {
+ buffer = talloc_asprintf_append_buffer(
+ buffer,
+ "%s ",
+ message->elements[i].name);
+ }
+
+ if (dsdb_audit_redact_attribute(message->elements[i].name)) {
+ /*
+ * Do not log the value of any secret or password
+ * attributes
+ */
+ buffer = talloc_asprintf_append_buffer(
+ buffer,
+ "[REDACTED SECRET ATTRIBUTE]");
+ continue;
+ }
+
+ for (j=0;j<message->elements[i].num_values;j++) {
+ struct ldb_val v;
+ bool use_b64_encode = false;
+ size_t length;
+ if (j > 0) {
+ buffer = talloc_asprintf_append_buffer(
+ buffer,
+ " ");
+ }
+
+ v = message->elements[i].values[j];
+ length = MIN(MAX_LENGTH, v.length);
+ use_b64_encode = ldb_should_b64_encode(ldb, &v);
+ if (use_b64_encode) {
+ const char *encoded = ldb_base64_encode(
+ buffer,
+ (char *)v.data,
+ length);
+ buffer = talloc_asprintf_append_buffer(
+ buffer,
+ "{%s%s}",
+ encoded,
+ (v.length > MAX_LENGTH ? "..." : ""));
+ } else {
+ buffer = talloc_asprintf_append_buffer(
+ buffer,
+ "[%*.*s%s]",
+ (int)length,
+ (int)length,
+ (char *)v.data,
+ (v.length > MAX_LENGTH ? "..." : ""));
+ }
+ }
+ }
+ return buffer;
+}
+
+/*
+ * @brief generate a human readable log entry detailing an ldb operation.
+ *
+ * Generate a human readable log entry detailing an ldb operation.
+ *
+ * @param[in] mem_ctx the talloc context owning the returned string.
+ * @param[in] module the ldb module
+ * @param[in] request the request
+ * @param[in] reply the result of the operation
+ *
+ * @return the log entry.
+ *
+ */
+char *dsdb_audit_operation_human_readable(
+ TALLOC_CTX *mem_ctx,
+ struct ldb_module *module,
+ const struct ldb_request *request,
+ const struct ldb_reply *reply)
+{
+ struct ldb_context *ldb = NULL;
+ const char *remote_host = NULL;
+ const struct tsocket_address *remote = NULL;
+ const struct dom_sid *sid = NULL;
+ struct dom_sid_buf user_sid;
+ const char *timestamp = NULL;
+ const char *op_name = NULL;
+ char *log_entry = NULL;
+ const char *dn = NULL;
+ const char *new_dn = NULL;
+ const struct ldb_message *message = NULL;
+
+ TALLOC_CTX *ctx = talloc_new(NULL);
+
+ ldb = ldb_module_get_ctx(module);
+
+ remote_host = dsdb_audit_get_remote_host(ldb, ctx);
+ remote = dsdb_audit_get_remote_address(ldb);
+ if (remote != NULL && dsdb_audit_is_system_session(module)) {
+ sid = dsdb_audit_get_actual_sid(ldb);
+ } else {
+ sid = dsdb_audit_get_user_sid(module);
+ }
+ timestamp = audit_get_timestamp(ctx);
+ op_name = dsdb_audit_get_operation_name(request);
+ dn = dsdb_audit_get_primary_dn(request);
+ new_dn = dsdb_audit_get_secondary_dn(request);
+
+ message = dsdb_audit_get_message(request);
+
+ log_entry = talloc_asprintf(
+ mem_ctx,
+ "[%s] at [%s] status [%s] "
+ "remote host [%s] SID [%s] DN [%s]",
+ op_name,
+ timestamp,
+ ldb_strerror(reply->error),
+ remote_host,
+ dom_sid_str_buf(sid, &user_sid),
+ dn);
+ if (new_dn != NULL) {
+ log_entry = talloc_asprintf_append_buffer(
+ log_entry,
+ " New DN [%s]",
+ new_dn);
+ }
+ if (message != NULL) {
+ log_entry = talloc_asprintf_append_buffer(log_entry,
+ " attributes [");
+ log_entry = dsdb_audit_log_attributes(ldb,
+ log_entry,
+ request->operation,
+ message);
+ log_entry = talloc_asprintf_append_buffer(log_entry, "]");
+ }
+ TALLOC_FREE(ctx);
+ return log_entry;
+}
diff -Nru samba-4.22.10+dfsg/source4/dsdb/samdb/ldb_modules/rootdse.c samba-4.22.11+dfsg/source4/dsdb/samdb/ldb_modules/rootdse.c
--- samba-4.22.10+dfsg/source4/dsdb/samdb/ldb_modules/rootdse.c 2025-01-30 16:57:44.161316000 +0300
+++ samba-4.22.11+dfsg/source4/dsdb/samdb/ldb_modules/rootdse.c 2026-07-21 18:37:04.183276200 +0300
@@ -28,6 +28,7 @@
#include "dsdb/samdb/samdb.h"
#include "version.h"
#include "dsdb/samdb/ldb_modules/util.h"
+#include "dsdb/samdb/ldb_modules/audit_util_proto.h"
#include "libcli/security/security.h"
#include "librpc/ndr/libndr.h"
#include "auth/auth.h"
@@ -746,18 +747,68 @@
return LDB_SUCCESS;
}
-/* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
-
+/*
+ * Ensure that anonymous users are not allowed to make anything other than
+ * rootDSE search operations and special dns like @MODULES are not allowed
+ * over an untrusted connection.
+ */
static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
{
struct auth_session_info *session_info;
struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
bool is_untrusted = ldb_req_is_untrusted(req);
bool is_anonymous = true;
+ struct ldb_dn *dn = NULL;
+ struct ldb_dn *dn2 = NULL;
+
if (is_untrusted == false) {
return LDB_SUCCESS;
}
+ switch (req->operation) {
+ case LDB_SEARCH:
+ dn = req->op.search.base;
+ break;
+ case LDB_ADD:
+ dn = req->op.add.message->dn;
+ break;
+ case LDB_MODIFY:
+ dn = req->op.mod.message->dn;
+ break;
+ case LDB_DELETE:
+ dn = req->op.del.dn;
+ break;
+ case LDB_RENAME:
+ dn = req->op.rename.olddn;
+ dn2 = req->op.rename.newdn;
+ break;
+ case LDB_EXTENDED:
+ break;
+ case LDB_REQ_REGISTER_CONTROL:
+ case LDB_REQ_REGISTER_PARTITION:
+ ldb_set_errstring(ldb_module_get_ctx(module), "Invalid OP");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (ldb_dn_is_special(dn)) {
+ struct ldb_reply reply = { .error = LDB_ERR_OPERATIONS_ERROR, };
+
+ D_ERR("CVE-2026-58221-ATTACK: %s\n",
+ dsdb_audit_operation_human_readable(req, module, req, &reply));
+
+ ldb_set_errstring(ldb_module_get_ctx(module), "Invalid DN");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (ldb_dn_is_special(dn2)) {
+ struct ldb_reply reply = { .error = LDB_ERR_OPERATIONS_ERROR, };
+
+ D_ERR("CVE-2026-58221-ATTACK: %s\n",
+ dsdb_audit_operation_human_readable(req, module, req, &reply));
+
+ ldb_set_errstring(ldb_module_get_ctx(module), "Invalid DN");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
session_info = (struct auth_session_info *)ldb_get_opaque(
ldb_module_get_ctx(module),
DSDB_SESSION_INFO);
diff -Nru samba-4.22.10+dfsg/source4/dsdb/samdb/ldb_modules/wscript_build_server samba-4.22.11+dfsg/source4/dsdb/samdb/ldb_modules/wscript_build_server
--- samba-4.22.10+dfsg/source4/dsdb/samdb/ldb_modules/wscript_build_server 2025-06-04 12:08:46.438111500 +0300
+++ samba-4.22.11+dfsg/source4/dsdb/samdb/ldb_modules/wscript_build_server 2026-07-21 18:37:04.183276200 +0300
@@ -185,7 +185,7 @@
init_function='ldb_rootdse_module_init',
module_init_name='ldb_init_module',
internal_module=False,
- deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC'
+ deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS DSDB_MODULE_HELPERS_AUDIT RPC_NDR_IRPC'
)
diff -Nru samba-4.22.10+dfsg/source4/kdc/kpasswd-service.c samba-4.22.11+dfsg/source4/kdc/kpasswd-service.c
--- samba-4.22.10+dfsg/source4/kdc/kpasswd-service.c 2025-01-30 16:57:44.178315900 +0300
+++ samba-4.22.11+dfsg/source4/kdc/kpasswd-service.c 2026-07-21 18:37:04.183276200 +0300
@@ -137,7 +137,7 @@
ap_req_blob = data_blob_const(&request->data[HEADER_LEN], ap_req_len);
- enc_data_len = len - ap_req_len;
+ enc_data_len = len - (ap_req_len + HEADER_LEN);
enc_data_blob = data_blob_const(&request->data[HEADER_LEN + ap_req_len],
enc_data_len);
diff -Nru samba-4.22.10+dfsg/source4/ldap_server/ldap_backend.c samba-4.22.11+dfsg/source4/ldap_server/ldap_backend.c
--- samba-4.22.10+dfsg/source4/ldap_server/ldap_backend.c 2025-01-30 16:57:44.187316000 +0300
+++ samba-4.22.11+dfsg/source4/ldap_server/ldap_backend.c 2026-07-21 18:37:04.183276200 +0300
@@ -29,6 +29,7 @@
#include "samba/service_stream.h"
#include "dsdb/gmsa/util.h"
#include "dsdb/samdb/samdb.h"
+#include "dsdb/common/util.h"
#include <ldb_errors.h>
#include <ldb_module.h>
#include "ldb_wrap.h"
@@ -1449,6 +1450,7 @@
struct ldb_dn *dn;
const char *attrs[1];
const char *errstr = NULL;
+ const char *value = NULL;
const char *filter = NULL;
int result = LDAP_SUCCESS;
int ldb_ret;
@@ -1461,21 +1463,31 @@
dn = ldb_dn_new(local_ctx, samdb, req->dn);
NT_STATUS_HAVE_NO_MEMORY(dn);
+ compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
+ NT_STATUS_HAVE_NO_MEMORY(compare_r);
+
DBG_DEBUG("dn: [%s]\n", req->dn);
- filter = talloc_asprintf(local_ctx, "(%s=%*s)", req->attribute,
- (int)req->value.length, req->value.data);
+
+ if (!ldb_valid_attr_name(req->attribute)) {
+ result = LDAP_INVALID_ATTRIBUTE_SYNTAX;
+ errstr = "Invalid Compare attribute name";
+ goto reply;
+ }
+ value = ldb_binary_encode(local_ctx, req->value);
+ NT_STATUS_HAVE_NO_MEMORY(value);
+
+ filter = talloc_asprintf(local_ctx, "%s=%s", req->attribute, value);
NT_STATUS_HAVE_NO_MEMORY(filter);
DBG_DEBUG("attribute: [%s]\n", filter);
attrs[0] = NULL;
- compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
- NT_STATUS_HAVE_NO_MEMORY(compare_r);
-
if (result == LDAP_SUCCESS) {
- ldb_ret = ldb_search(samdb, local_ctx, &res,
- dn, LDB_SCOPE_BASE, attrs, "%s", filter);
+ ldb_ret = dsdb_search(samdb, local_ctx, &res,
+ dn, LDB_SCOPE_BASE, attrs,
+ DSDB_MARK_REQ_UNTRUSTED,
+ "%s", filter);
if (ldb_ret != LDB_SUCCESS) {
result = map_ldb_error(local_ctx, ldb_ret,
ldb_errstring(samdb), &errstr);
@@ -1497,6 +1509,7 @@
}
}
+reply:
compare = &compare_r->msg->r.CompareResponse;
compare->dn = NULL;
compare->resultcode = result;
diff -Nru samba-4.22.10+dfsg/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt samba-4.22.11+dfsg/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt
--- samba-4.22.10+dfsg/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt 2025-01-30 16:57:44.210316000 +0300
+++ samba-4.22.11+dfsg/source4/librpc/tests/dns-decode_dns_name_packet-hex.txt 2026-07-21 18:37:04.183276200 +0300
@@ -21,6 +21,7 @@
answers: ARRAY(0)
nsrecs: ARRAY(1)
nsrecs: struct dns_res_rec
+ start_ndr_offset : 0x00000027 (39)
name : 'cnamedotprefix0.samba2003.example.com'
rr_type : DNS_QTYPE_CNAME (0x5)
rr_class : DNS_QCLASS_IN (0x1)
More information about the Pkg-samba-maint
mailing list