[Pkg-samba-maint] Bug#1121733: bookworm-pu: package samba/2:4.17.12+dfsg-0+deb12u3
Michael Tokarev
mjt at tls.msk.ru
Mon Dec 1 13:22:28 GMT 2025
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: samba at packages.debian.org
Control: affects -1 + src:samba
User: release.debian.org at packages.debian.org
Usertags: pu
[ Reason ]
There are 3 known security hole exists in bookworm version
of samba. These holes has been fixed in more recent versions
of the package, including trixie version, and the fixes has
been back-ported to earlier releases by the LTS samba community
(https://gitlab.com/samba-team/lts-community and the git tree
in there).
The vulnerabilities are:
CVE-2018-14628: Unprivileged read of deleted object tombstones
in AD LDAP server (#1034803)
CVE-2025-10230: Command injection via WINS server hook script
CVE-2025-9640: Uninitialized memory disclosure via vfs_streams_xattr
These aren't really huge holes, but it is still good to be able
to fix these.
[ Tests ]
There aren't much testing done for this release, because I don't
have the necessary testing environment. The fixes are rather
targetted and has been well-tested in more recent versions.
[ Risks ]
I don't see much risks from these changes. While the amount of
changes needed for CVE-2018-14628 fix is rather large, it is also
very well tested.
It would help still, if this release is available in proposed-updates
for a while.
[ 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
[ Other info ]
4.17 series of samba reached its end-of-line wrt the upstream
support, however it is still maintained by the lts community.
With no official releases, - just as a collection of fixes in
the git tree. This is the source of the changes.
Thanks,
/mjt
diff -Nru samba-4.17.12+dfsg/debian/changelog samba-4.17.12+dfsg/debian/changelog
--- samba-4.17.12+dfsg/debian/changelog 2025-07-11 11:21:51.000000000 +0300
+++ samba-4.17.12+dfsg/debian/changelog 2025-11-30 11:35:04.000000000 +0300
@@ -1,3 +1,12 @@
+samba (2:4.17.12+dfsg-0+deb12u3) bookworm; urgency=medium
+
+ * CVE-2018-14628: Unprivileged read of deleted object tombstones
+ in AD LDAP server. Closes: #1034803
+ * CVE-2025-10230: Command injection via WINS server hook script
+ * CVE-2025-9640: Uninitialized memory disclosure via vfs_streams_xattr
+
+ -- Michael Tokarev <mjt at tls.msk.ru> Sun, 30 Nov 2025 11:35:04 +0300
+
samba (2:4.17.12+dfsg-0+deb12u2) bookworm; urgency=medium
[ Salvatore Bonaccorso ]
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/01-python-descriptor-add-get_deletedobjects_descriptor.patch samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/01-python-descriptor-add-get_deletedobjects_descriptor.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/01-python-descriptor-add-get_deletedobjects_descriptor.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/01-python-descriptor-add-get_deletedobjects_descriptor.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,43 @@
+From: Stefan Metzmacher <metze at samba.org>
+Date: Fri, 29 Jan 2016 23:30:59 +0100
+Subject: CVE-2018-14628: python:descriptor: add get_deletedobjects_descriptor()
+
+samba-tool drs clone-dc-database was quite useful to find
+the true value of nTSecurityDescriptor of the CN=Delete Objects
+containers.
+
+Only the auto inherited SACL is available via a ldap search.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andrew Bartlett <abartlet at samba.org>
+(cherry picked from commit 3be190dcf7153e479383f7f3d29ddca43fe121b8)
+---
+ python/samba/descriptor.py | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/python/samba/descriptor.py b/python/samba/descriptor.py
+index ac4c7e3273d..08c7518f56a 100644
+--- a/python/samba/descriptor.py
++++ b/python/samba/descriptor.py
+@@ -52,6 +52,16 @@ def get_empty_descriptor(domain_sid, name_map={}):
+ # "get_schema_descriptor" is located in "schema.py"
+
+
++def get_deletedobjects_descriptor(domain_sid, name_map=None):
++ if name_map is None:
++ name_map = {}
++
++ sddl = "O:SYG:SYD:PAI" \
++ "(A;;RPWPCCDCLCRCWOWDSDSW;;;SY)" \
++ "(A;;RPLC;;;BA)"
++ return sddl2binary(sddl, domain_sid, name_map)
++
++
+ def get_config_descriptor(domain_sid, name_map={}):
+ sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/02-python-provision-make-DELETEDOBJECTS_DESCRIPTOR-availab.patch samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/02-python-provision-make-DELETEDOBJECTS_DESCRIPTOR-availab.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/02-python-provision-make-DELETEDOBJECTS_DESCRIPTOR-availab.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/02-python-provision-make-DELETEDOBJECTS_DESCRIPTOR-availab.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,91 @@
+From: Stefan Metzmacher <metze at samba.org>
+Date: Fri, 29 Jan 2016 23:33:37 +0100
+Subject: CVE-2018-14628: python:provision: make DELETEDOBJECTS_DESCRIPTOR
+ available in the ldif files
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andrew Bartlett <abartlet at samba.org>
+(cherry picked from commit 0c329a0fda37d87ed737e4b579b6d04ec907604c)
+---
+ python/samba/provision/__init__.py | 5 +++++
+ python/samba/provision/sambadns.py | 4 ++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py
+index ff9b8fac916..f7d7468e4fa 100644
+--- a/python/samba/provision/__init__.py
++++ b/python/samba/provision/__init__.py
+@@ -78,6 +78,7 @@ from samba.provision.backend import (
+ LDBBackend,
+ )
+ from samba.descriptor import (
++ get_deletedobjects_descriptor,
+ get_empty_descriptor,
+ get_config_descriptor,
+ get_config_partitions_descriptor,
+@@ -1441,6 +1442,8 @@ def fill_samdb(samdb, lp, names, logger, policyguid,
+ msg["subRefs"] = ldb.MessageElement(names.configdn, ldb.FLAG_MOD_ADD,
+ "subRefs")
+
++ deletedobjects_descr = b64encode(get_deletedobjects_descriptor(names.domainsid)).decode('utf8')
++
+ samdb.invocation_id = invocationid
+
+ # If we are setting up a subdomain, then this has been replicated in, so we don't need to add it
+@@ -1472,6 +1475,7 @@ def fill_samdb(samdb, lp, names, logger, policyguid,
+ "FOREST_FUNCTIONALITY": str(forestFunctionality),
+ "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
+ "NTDSQUOTAS_DESCRIPTOR": ntdsquotas_descr,
++ "DELETEDOBJECTS_DESCRIPTOR": deletedobjects_descr,
+ "LOSTANDFOUND_DESCRIPTOR": protected1wd_descr,
+ "SERVICES_DESCRIPTOR": protected1_descr,
+ "PHYSICALLOCATIONS_DESCRIPTOR": protected1wd_descr,
+@@ -1536,6 +1540,7 @@ def fill_samdb(samdb, lp, names, logger, policyguid,
+ "RIDAVAILABLESTART": str(next_rid + 600),
+ "POLICYGUID_DC": policyguid_dc,
+ "INFRASTRUCTURE_DESCRIPTOR": infrastructure_desc,
++ "DELETEDOBJECTS_DESCRIPTOR": deletedobjects_descr,
+ "LOSTANDFOUND_DESCRIPTOR": lostandfound_desc,
+ "SYSTEM_DESCRIPTOR": system_desc,
+ "BUILTIN_DESCRIPTOR": builtin_desc,
+diff --git a/python/samba/provision/sambadns.py b/python/samba/provision/sambadns.py
+index 9184711a764..d057b7830ad 100644
+--- a/python/samba/provision/sambadns.py
++++ b/python/samba/provision/sambadns.py
+@@ -42,6 +42,7 @@ from samba.dsdb import (
+ DS_GUID_USERS_CONTAINER
+ )
+ from samba.descriptor import (
++ get_deletedobjects_descriptor,
+ get_domain_descriptor,
+ get_domain_delete_protected1_descriptor,
+ get_domain_delete_protected2_descriptor,
+@@ -256,6 +257,7 @@ def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
+ domainzone_dn = "DC=DomainDnsZones,%s" % domaindn
+ forestzone_dn = "DC=ForestDnsZones,%s" % forestdn
+ descriptor = get_dns_partition_descriptor(domainsid)
++ deletedobjects_desc = get_deletedobjects_descriptor(domainsid)
+
+ setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
+ "ZONE_DN": domainzone_dn,
+@@ -278,6 +280,7 @@ def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
+ "ZONE_DNS": domainzone_dns,
+ "CONFIGDN": configdn,
+ "SERVERDN": serverdn,
++ "DELETEDOBJECTS_DESCRIPTOR": b64encode(deletedobjects_desc).decode('utf8'),
+ "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc).decode('utf8'),
+ "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc).decode('utf8'),
+ })
+@@ -297,6 +300,7 @@ def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
+ "ZONE_DNS": forestzone_dns,
+ "CONFIGDN": configdn,
+ "SERVERDN": serverdn,
++ "DELETEDOBJECTS_DESCRIPTOR": b64encode(deletedobjects_desc).decode('utf8'),
+ "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc).decode('utf8'),
+ "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc).decode('utf8'),
+ })
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/03-s4-setup-set-the-correct-nTSecurityDescriptor-on-the-CN.patch samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/03-s4-setup-set-the-correct-nTSecurityDescriptor-on-the-CN.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/03-s4-setup-set-the-correct-nTSecurityDescriptor-on-the-CN.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/03-s4-setup-set-the-correct-nTSecurityDescriptor-on-the-CN.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,67 @@
+From: Stefan Metzmacher <metze at samba.org>
+Date: Fri, 29 Jan 2016 23:34:15 +0100
+Subject: CVE-2018-14628: s4:setup: set the correct nTSecurityDescriptor on the
+ CN=Deleted Objects container
+
+This revealed a bug in our dirsync code, so we mark
+test_search_with_dirsync_deleted_objects as knownfail.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andrew Bartlett <abartlet at samba.org>
+(cherry picked from commit 7f8b15faa76d05023c987fac2c4c31f9ac61bb47)
+---
+ selftest/knownfail.d/samba4.ldap.confidential_attr | 1 +
+ source4/setup/provision.ldif | 1 +
+ source4/setup/provision_configuration.ldif | 1 +
+ source4/setup/provision_dnszones_add.ldif | 1 +
+ 4 files changed, 4 insertions(+)
+ create mode 100644 selftest/knownfail.d/samba4.ldap.confidential_attr
+
+diff --git a/selftest/knownfail.d/samba4.ldap.confidential_attr b/selftest/knownfail.d/samba4.ldap.confidential_attr
+new file mode 100644
+index 00000000000..46a75ce928b
+--- /dev/null
++++ b/selftest/knownfail.d/samba4.ldap.confidential_attr
+@@ -0,0 +1 @@
++^samba4.ldap.confidential_attr.python.*.__main__.*.test_search_with_dirsync_deleted_objects
+diff --git a/source4/setup/provision.ldif b/source4/setup/provision.ldif
+index 5d9eba49f86..7f966fd57f8 100644
+--- a/source4/setup/provision.ldif
++++ b/source4/setup/provision.ldif
+@@ -34,6 +34,7 @@ isDeleted: TRUE
+ isCriticalSystemObject: TRUE
+ showInAdvancedViewOnly: TRUE
+ systemFlags: -1946157056
++nTSecurityDescriptor:: ${DELETEDOBJECTS_DESCRIPTOR}
+
+ # Computers located in "provision_computers*.ldif"
+ # Users/Groups located in "provision_users*.ldif"
+diff --git a/source4/setup/provision_configuration.ldif b/source4/setup/provision_configuration.ldif
+index 53c9c8536de..8fcbddbdae4 100644
+--- a/source4/setup/provision_configuration.ldif
++++ b/source4/setup/provision_configuration.ldif
+@@ -14,6 +14,7 @@ description: Container for deleted objects
+ isDeleted: TRUE
+ isCriticalSystemObject: TRUE
+ systemFlags: -1946157056
++nTSecurityDescriptor:: ${DELETEDOBJECTS_DESCRIPTOR}
+
+ # Extended rights
+
+diff --git a/source4/setup/provision_dnszones_add.ldif b/source4/setup/provision_dnszones_add.ldif
+index 860aa4b72b3..a2d6b6bab8f 100644
+--- a/source4/setup/provision_dnszones_add.ldif
++++ b/source4/setup/provision_dnszones_add.ldif
+@@ -8,6 +8,7 @@ description: Deleted objects
+ isDeleted: TRUE
+ isCriticalSystemObject: TRUE
+ systemFlags: -1946157056
++nTSecurityDescriptor:: ${DELETEDOBJECTS_DESCRIPTOR}
+
+ dn: CN=LostAndFound,${ZONE_DN}
+ objectClass: top
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/04-s4-dsdb-remove-unused-code-in-dirsync_filter_entry.patch samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/04-s4-dsdb-remove-unused-code-in-dirsync_filter_entry.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/04-s4-dsdb-remove-unused-code-in-dirsync_filter_entry.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/04-s4-dsdb-remove-unused-code-in-dirsync_filter_entry.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,99 @@
+From: Stefan Metzmacher <metze at samba.org>
+Date: Mon, 26 Jun 2023 15:14:24 +0200
+Subject: CVE-2018-14628: s4:dsdb: remove unused code in dirsync_filter_entry()
+
+This makes the next change easier to understand.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andrew Bartlett <abartlet at samba.org>
+(cherry picked from commit 498542be0bbf4f26558573c1f87b77b8e3509371)
+---
+ source4/dsdb/samdb/ldb_modules/dirsync.c | 53 +++---------------------
+ 1 file changed, 5 insertions(+), 48 deletions(-)
+
+diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c
+index fbb75790095..124cff25e39 100644
+--- a/source4/dsdb/samdb/ldb_modules/dirsync.c
++++ b/source4/dsdb/samdb/ldb_modules/dirsync.c
+@@ -151,10 +151,6 @@ static int dirsync_filter_entry(struct ldb_request *req,
+ * list only the attribute that have been modified since last interogation
+ *
+ */
+- newmsg = ldb_msg_new(dsc->req);
+- if (newmsg == NULL) {
+- return ldb_oom(ldb);
+- }
+ for (i = msg->num_elements - 1; i >= 0; i--) {
+ if (ldb_attr_cmp(msg->elements[i].name, "uSNChanged") == 0) {
+ int error = 0;
+@@ -201,11 +197,6 @@ static int dirsync_filter_entry(struct ldb_request *req,
+ */
+ return LDB_SUCCESS;
+ }
+- newmsg->dn = ldb_dn_new(newmsg, ldb, "");
+- if (newmsg->dn == NULL) {
+- return ldb_oom(ldb);
+- }
+-
+ el = ldb_msg_find_element(msg, "objectGUID");
+ if ( el != NULL) {
+ guidfound = true;
+@@ -216,48 +207,14 @@ static int dirsync_filter_entry(struct ldb_request *req,
+ * well will uncomment the code bellow
+ */
+ SMB_ASSERT(guidfound == true);
+- /*
+- if (guidfound == false) {
+- struct GUID guid;
+- struct ldb_val *new_val;
+- DATA_BLOB guid_blob;
+-
+- tmp[0] = '\0';
+- txt = strrchr(txt, ':');
+- if (txt == NULL) {
+- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+- }
+- txt++;
+-
+- status = GUID_from_string(txt, &guid);
+- if (!NT_STATUS_IS_OK(status)) {
+- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+- }
+-
+- status = GUID_to_ndr_blob(&guid, msg, &guid_blob);
+- if (!NT_STATUS_IS_OK(status)) {
+- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+- }
+-
+- new_val = talloc(msg, struct ldb_val);
+- if (new_val == NULL) {
+- return ldb_oom(ldb);
+- }
+- new_val->data = talloc_steal(new_val, guid_blob.data);
+- new_val->length = guid_blob.length;
+- if (ldb_msg_add_value(msg, "objectGUID", new_val, NULL) != 0) {
+- return ldb_module_done(dsc->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
+- }
+- }
+- */
+- ldb_msg_add(newmsg, el, LDB_FLAG_MOD_ADD);
+- talloc_steal(newmsg->elements, el->name);
+- talloc_steal(newmsg->elements, el->values);
+-
+- talloc_steal(newmsg->elements, msg);
+ return ldb_module_send_entry(dsc->req, msg, controls);
+ }
+
++ newmsg = ldb_msg_new(dsc->req);
++ if (newmsg == NULL) {
++ return ldb_oom(ldb);
++ }
++
+ ndr_err = ndr_pull_struct_blob(replMetaData, dsc, &rmd,
+ (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/05-dbchecker-use-get_deletedobjects_descriptor-for-missing.patch samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/05-dbchecker-use-get_deletedobjects_descriptor-for-missing.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/05-dbchecker-use-get_deletedobjects_descriptor-for-missing.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/05-dbchecker-use-get_deletedobjects_descriptor-for-missing.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,66 @@
+From: Stefan Metzmacher <metze at samba.org>
+Date: Wed, 7 Jun 2023 18:18:58 +0200
+Subject: CVE-2018-14628: dbchecker: use get_deletedobjects_descriptor for
+ missing deleted objects container
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andrew Bartlett <abartlet at samba.org>
+(cherry picked from commit 70586061128f90afa33f25e104d4570a1cf778db)
+---
+ python/samba/dbchecker.py | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
+index 449b0a7d985..e124b1a0d67 100644
+--- a/python/samba/dbchecker.py
++++ b/python/samba/dbchecker.py
+@@ -20,7 +20,7 @@
+ import ldb
+ import samba
+ import time
+-from base64 import b64decode
++from base64 import b64decode, b64encode
+ from samba import dsdb
+ from samba import common
+ from samba.dcerpc import misc
+@@ -29,7 +29,11 @@ from samba.ndr import ndr_unpack, ndr_pack
+ from samba.dcerpc import drsblobs
+ from samba.samdb import dsdb_Dn
+ from samba.dcerpc import security
+-from samba.descriptor import get_wellknown_sds, get_diff_sds
++from samba.descriptor import (
++ get_wellknown_sds,
++ get_deletedobjects_descriptor,
++ get_diff_sds
++)
+ from samba.auth import system_session, admin_session
+ from samba.netcmd import CommandError
+ from samba.netcmd.fsmo import get_fsmo_roleowner
+@@ -341,6 +345,12 @@ class dbcheck(object):
+ listwko.append('%s:%s' % (wko_prefix, dn))
+ guid_suffix = ""
+
++
++ domain_sid = security.dom_sid(self.samdb.get_domain_sid())
++ sec_desc = get_deletedobjects_descriptor(domain_sid,
++ name_map=self.name_map)
++ sec_desc_b64 = b64encode(sec_desc).decode('utf8')
++
+ # Insert a brand new Deleted Objects container
+ self.samdb.add_ldif("""dn: %s
+ objectClass: top
+@@ -349,7 +359,8 @@ description: Container for deleted objects
+ isDeleted: TRUE
+ isCriticalSystemObject: TRUE
+ showInAdvancedViewOnly: TRUE
+-systemFlags: -1946157056%s""" % (dn, guid_suffix),
++nTSecurityDescriptor:: %s
++systemFlags: -1946157056%s""" % (dn, sec_desc_b64, guid_suffix),
+ controls=["relax:0", "provision:0"])
+
+ delta = ldb.Message()
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/06-python-descriptor-let-samba-tool-dbch.patch samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/06-python-descriptor-let-samba-tool-dbch.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/06-python-descriptor-let-samba-tool-dbch.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2018-14628/06-python-descriptor-let-samba-tool-dbch.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,138 @@
+From: Stefan Metzmacher <metze at samba.org>
+Date: Fri, 29 Jan 2016 23:35:31 +0100
+Subject: CVE-2018-14628: python:descriptor: let samba-tool dbcheck fix
+ the nTSecurityDescriptor on CN=Deleted Objects containers
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=13595
+
+Signed-off-by: Stefan Metzmacher <metze at samba.org>
+Reviewed-by: Andrew Bartlett <abartlet at samba.org>
+(cherry picked from commit 97e4aab1a6e2feda7c6c6fdeaa7c3e1818c55566)
+---
+ python/samba/dbchecker.py | 10 ++++++++--
+ python/samba/descriptor.py | 15 ++++++++++++++-
+ testprogs/blackbox/dbcheck-links.sh | 12 ++++++++++++
+ 3 files changed, 34 insertions(+), 3 deletions(-)
+
+diff --git a/python/samba/dbchecker.py b/python/samba/dbchecker.py
+index e124b1a0d67..28d99c01d04 100644
+--- a/python/samba/dbchecker.py
++++ b/python/samba/dbchecker.py
+@@ -2444,7 +2444,7 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
+ error_count += 1
+ continue
+
+- if self.reset_well_known_acls:
++ if dn == deleted_objects_dn or self.reset_well_known_acls:
+ try:
+ well_known_sd = self.get_wellknown_sd(dn)
+ except KeyError:
+@@ -2453,7 +2453,13 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
+ current_sd = ndr_unpack(security.descriptor,
+ obj[attrname][0])
+
+- diff = get_diff_sds(well_known_sd, current_sd, security.dom_sid(self.samdb.get_domain_sid()))
++ ignoreAdditionalACEs = False
++ if not self.reset_well_known_acls:
++ ignoreAdditionalACEs = True
++
++ diff = get_diff_sds(well_known_sd, current_sd,
++ security.dom_sid(self.samdb.get_domain_sid()),
++ ignoreAdditionalACEs=ignoreAdditionalACEs)
+ if diff != "":
+ self.err_wrong_default_sd(dn, well_known_sd, diff)
+ error_count += 1
+diff --git a/python/samba/descriptor.py b/python/samba/descriptor.py
+index 08c7518f56a..34877fa4814 100644
+--- a/python/samba/descriptor.py
++++ b/python/samba/descriptor.py
+@@ -417,6 +417,7 @@ def get_wellknown_sds(samdb):
+ # Then subcontainers
+ subcontainers = [
+ (ldb.Dn(samdb, "%s" % str(samdb.domain_dn())), get_domain_descriptor),
++ (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(samdb.domain_dn())), get_deletedobjects_descriptor),
+ (ldb.Dn(samdb, "CN=LostAndFound,%s" % str(samdb.domain_dn())), get_domain_delete_protected2_descriptor),
+ (ldb.Dn(samdb, "CN=System,%s" % str(samdb.domain_dn())), get_domain_delete_protected1_descriptor),
+ (ldb.Dn(samdb, "CN=Infrastructure,%s" % str(samdb.domain_dn())), get_domain_infrastructure_descriptor),
+@@ -427,6 +428,7 @@ def get_wellknown_sds(samdb):
+ (ldb.Dn(samdb, "CN=MicrosoftDNS,CN=System,%s" % str(samdb.domain_dn())), get_dns_domain_microsoft_dns_descriptor),
+
+ (ldb.Dn(samdb, "%s" % str(samdb.get_config_basedn())), get_config_descriptor),
++ (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(samdb.get_config_basedn())), get_deletedobjects_descriptor),
+ (ldb.Dn(samdb, "CN=NTDS Quotas,%s" % str(samdb.get_config_basedn())), get_config_ntds_quotas_descriptor),
+ (ldb.Dn(samdb, "CN=LostAndFoundConfig,%s" % str(samdb.get_config_basedn())), get_config_delete_protected1wd_descriptor),
+ (ldb.Dn(samdb, "CN=Services,%s" % str(samdb.get_config_basedn())), get_config_delete_protected1_descriptor),
+@@ -451,6 +453,9 @@ def get_wellknown_sds(samdb):
+ if ldb.Dn(samdb, nc.decode('utf8')) == dnsforestdn:
+ c = (ldb.Dn(samdb, "%s" % str(dnsforestdn)), get_dns_partition_descriptor)
+ subcontainers.append(c)
++ c = (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(dnsforestdn)),
++ get_deletedobjects_descriptor)
++ subcontainers.append(c)
+ c = (ldb.Dn(samdb, "CN=Infrastructure,%s" % str(dnsforestdn)),
+ get_domain_delete_protected1_descriptor)
+ subcontainers.append(c)
+@@ -466,6 +471,9 @@ def get_wellknown_sds(samdb):
+ if ldb.Dn(samdb, nc.decode('utf8')) == dnsdomaindn:
+ c = (ldb.Dn(samdb, "%s" % str(dnsdomaindn)), get_dns_partition_descriptor)
+ subcontainers.append(c)
++ c = (ldb.Dn(samdb, "CN=Deleted Objects,%s" % str(dnsdomaindn)),
++ get_deletedobjects_descriptor)
++ subcontainers.append(c)
+ c = (ldb.Dn(samdb, "CN=Infrastructure,%s" % str(dnsdomaindn)),
+ get_domain_delete_protected1_descriptor)
+ subcontainers.append(c)
+@@ -558,7 +566,8 @@ def get_clean_sd(sd):
+ return sd_clean
+
+
+-def get_diff_sds(refsd, cursd, domainsid, checkSacl=True):
++def get_diff_sds(refsd, cursd, domainsid, checkSacl=True,
++ ignoreAdditionalACEs=False):
+ """Get the difference between 2 sd
+
+ This function split the textual representation of ACL into smaller
+@@ -613,6 +622,10 @@ def get_diff_sds(refsd, cursd, domainsid, checkSacl=True):
+ h_ref.remove(k)
+
+ if len(h_cur) + len(h_ref) > 0:
++ if txt == "" and len(h_ref) == 0:
++ if ignoreAdditionalACEs:
++ return ""
++
+ txt = "%s\tPart %s is different between reference" \
+ " and current here is the detail:\n" % (txt, part)
+
+diff --git a/testprogs/blackbox/dbcheck-links.sh b/testprogs/blackbox/dbcheck-links.sh
+index 29fb5b85abc..a91ed00fb0f 100755
+--- a/testprogs/blackbox/dbcheck-links.sh
++++ b/testprogs/blackbox/dbcheck-links.sh
+@@ -59,6 +59,16 @@ dbcheck()
+ fi
+ }
+
++dbcheck_acl_reset()
++{
++ $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --cross-ncs --fix --yes --attrs=nTSecurityDescriptor
++}
++
++dbcheck_acl_clean()
++{
++ $PYTHON $BINDIR/samba-tool dbcheck -H tdb://$PREFIX_ABS/${RELEASE}/private/sam.ldb --cross-ncs --attrs=nTSecurityDescriptor
++}
++
+ dbcheck_dangling()
+ {
+ dbcheck "" "1" "--selftest-check-expired-tombstones"
+@@ -925,6 +935,8 @@ EOF
+ remove_directory $PREFIX_ABS/${RELEASE}
+
+ testit $RELEASE undump || failed=$(expr $failed + 1)
++testit_expect_failure "dbcheck_acl_reset" dbcheck_acl_reset || failed=$(expr $failed + 1)
++testit "dbcheck_acl_clean" dbcheck_acl_clean || failed=$(expr $failed + 1)
+ testit "add_two_more_users" add_two_more_users || failed=$(expr $failed + 1)
+ testit "add_four_more_links" add_four_more_links || failed=$(expr $failed + 1)
+ testit "remove_one_link" remove_one_link || failed=$(expr $failed + 1)
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-tests-check-that-wins-hook-sanitizes-names.patch samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-tests-check-that-wins-hook-sanitizes-names.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-tests-check-that-wins-hook-sanitizes-names.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-tests-check-that-wins-hook-sanitizes-names.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,286 @@
+From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+Date: Tue, 9 Sep 2025 13:36:16 +1200
+Subject: CVE-2025-10230: s4/tests: check that wins hook sanitizes names
+
+An smb.conf can contain a 'wins hook' parameter, which names a script
+to run when a WINS name is changed. The man page says
+
+ The second argument is the NetBIOS name. If the name is not a
+ legal name then the wins hook is not called. Legal names contain
+ only letters, digits, hyphens, underscores and periods.
+
+but it turns out the legality check is not performed if the WINS
+server in question is the source4 nbt one. It is not expected that
+people will run this server, but they can. This is bad because the
+name is passed unescaped into a shell command line, allowing command
+injection.
+
+For this test we don't care whether the WINS server is returning an
+error code, just whether it is running the wins hook. The tests show
+it often runs the hook it shouldn't, though some characters are
+incidentally blocked because the name has to fit in a DN before it
+gets to the hook, and DNs have a few syntactic restrictions (e.g.,
+blocking '<', '>', and ';').
+
+The source3 WINS server that is used by Samba when not run as a DC is
+not affected and not here tested.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15903
+
+Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
+---
+ python/samba/tests/usage.py | 2 +
+ .../samba4.nbt.wins.wins_bad_names | 1 +
+ selftest/target/Samba4.pm | 1 +
+ source4/torture/nbt/wins.c | 136 +++++++++++++++++-
+ testprogs/blackbox/wins_hook_test | 15 ++
+ 5 files changed, 152 insertions(+), 3 deletions(-)
+ create mode 100644 selftest/knownfail.d/samba4.nbt.wins.wins_bad_names
+ create mode 100755 testprogs/blackbox/wins_hook_test
+
+diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py
+index 0286be15ec3..3dead1958a4 100644
+--- a/python/samba/tests/usage.py
++++ b/python/samba/tests/usage.py
+@@ -75,6 +75,7 @@ EXCLUDE_USAGE = {
+ 'lib/ldb/tests/python/api.py',
+ 'source4/selftest/tests.py',
+ 'buildtools/bin/waf',
++ 'testprogs/blackbox/wins_hook_test',
+ 'selftest/tap2subunit',
+ 'script/show_test_time',
+ 'source4/scripting/bin/subunitrun',
+@@ -121,6 +122,7 @@ EXCLUDE_HELP = {
+ 'selftest/tap2subunit',
+ 'wintest/test-s3.py',
+ 'wintest/test-s4-howto.py',
++ 'testprogs/blackbox/wins_hook_test',
+ }
+
+
+diff --git a/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names b/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names
+new file mode 100644
+index 00000000000..52388ce5749
+--- /dev/null
++++ b/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names
+@@ -0,0 +1 @@
++samba4.nbt.wins.wins_bad_names
+diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
+index 7033146f46a..8d93b50b1ee 100755
+--- a/selftest/target/Samba4.pm
++++ b/selftest/target/Samba4.pm
+@@ -1613,6 +1613,7 @@ sub provision_ad_dc_ntvfs($$$)
+ ldap server require strong auth = allow_sasl_over_tls
+ raw NTLMv2 auth = yes
+ lsa over netlogon = yes
++ wins hook = $ENV{SRCDIR_ABS}/testprogs/blackbox/wins_hook_test
+ rpc server port = 1027
+ auth event notification = true
+ dsdb event notification = true
+diff --git a/source4/torture/nbt/wins.c b/source4/torture/nbt/wins.c
+index 8c847b5ac50..7d7321752d6 100644
+--- a/source4/torture/nbt/wins.c
++++ b/source4/torture/nbt/wins.c
+@@ -31,6 +31,10 @@
+ #include "torture/nbt/proto.h"
+ #include "param/param.h"
+
++/* rcode used when you don't want to check the rcode */
++#define WINS_TEST_RCODE_WE_DONT_CARE 255
++
++
+ #define CHECK_VALUE(tctx, v, correct) \
+ torture_assert_int_equal(tctx, v, correct, "Incorrect value")
+
+@@ -137,7 +141,9 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address
+ address));
+
+ CHECK_STRING(tctx, io.out.wins_server, address);
+- CHECK_VALUE(tctx, io.out.rcode, 0);
++ if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) {
++ CHECK_VALUE(tctx, io.out.rcode, 0);
++ }
+
+ torture_comment(tctx, "register the name correct address\n");
+ name_register.in.name = *name;
+@@ -185,7 +191,9 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address
+ talloc_asprintf(tctx, "Bad response from %s for name register\n",
+ address));
+
+- CHECK_VALUE(tctx, name_register.out.rcode, 0);
++ if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) {
++ CHECK_VALUE(tctx, name_register.out.rcode, 0);
++ }
+ CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
+ }
+
+@@ -203,7 +211,9 @@ static bool nbt_test_wins_name(struct torture_context *tctx, const char *address
+ torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
+
+ CHECK_STRING(tctx, io.out.wins_server, address);
+- CHECK_VALUE(tctx, io.out.rcode, register_rcode);
++ if (register_rcode != WINS_TEST_RCODE_WE_DONT_CARE) {
++ CHECK_VALUE(tctx, io.out.rcode, register_rcode);
++ }
+
+ if (register_rcode != NBT_RCODE_OK) {
+ return true;
+@@ -532,6 +542,124 @@ static bool nbt_test_wins(struct torture_context *tctx)
+ return ret;
+ }
+
++/*
++ * Test that the WINS server does not call 'wins hook' when the name
++ * contains dodgy characters.
++ */
++static bool nbt_test_wins_bad_names(struct torture_context *tctx)
++{
++ const char *address = NULL;
++ const char *wins_hook_file = NULL;
++ bool ret = true;
++ int err;
++ bool ok;
++ struct nbt_name name = {};
++ size_t i, j;
++ FILE *fh = NULL;
++
++ struct {
++ const char *name;
++ bool should_succeed;
++ } test_cases[] = {
++ {"NORMAL", true},
++ {"|look|", false},
++ {"look&true", false},
++ {"look\\;false", false},
++ {"&ls>foo", false}, /* already fails due to DN syntax */
++ {"has spaces", false},
++ {"hyphen-dot.0", true},
++ };
++
++ wins_hook_file = talloc_asprintf(tctx, "%s/wins_hook_writes_here",
++ getenv("SELFTEST_TMPDIR"));
++
++ if (!torture_nbt_get_name(tctx, &name, &address)) {
++ return false;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
++ err = unlink(wins_hook_file);
++ if (err != 0 && errno != ENOENT) {
++ /* we expect ENOENT, but nothing else */
++ torture_comment(tctx,
++ "unlink %zu of '%s' failed\n",
++ i, wins_hook_file);
++ }
++
++ name.name = test_cases[i].name;
++ name.type = NBT_NAME_CLIENT;
++ ok = nbt_test_wins_name(tctx, address,
++ &name,
++ NBT_NODE_H,
++ true,
++ WINS_TEST_RCODE_WE_DONT_CARE
++ );
++ if (ok == false) {
++ /*
++ * This happens when the name interferes with
++ * the DN syntax when it is put in winsdb.
++ *
++ * The wins hook will not be reached.
++ */
++ torture_comment(tctx, "tests for '%s' failed\n",
++ name.name);
++ }
++
++ /*
++ * poll for the file being created by the wins hook.
++ */
++ for (j = 0; j < 10; j++) {
++ usleep(200000);
++ fh = fopen(wins_hook_file, "r");
++ if (fh != NULL) {
++ break;
++ }
++ }
++
++ if (fh == NULL) {
++ if (errno == ENOENT) {
++ if (test_cases[i].should_succeed) {
++ torture_comment(
++ tctx,
++ "wins hook for '%s' failed\n",
++ test_cases[i].name);
++ ret = false;
++ }
++ } else {
++ torture_comment(
++ tctx,
++ "wins hook for '%s' unexpectedly failed with %d\n",
++ test_cases[i].name,
++ errno);
++ ret = false;
++ }
++ } else {
++ char readback[17] = {0};
++ size_t n = fread(readback, 1, 16, fh);
++ torture_comment(tctx,
++ "wins hook wrote '%s' read '%.*s'\n",
++ test_cases[i].name,
++ (int)n, readback);
++
++ if (! test_cases[i].should_succeed) {
++ torture_comment(tctx,
++ "wins hook for '%s' should fail\n",
++ test_cases[i].name);
++ ret = false;
++ }
++ fclose(fh);
++ }
++ }
++ err = unlink(wins_hook_file);
++ if (err != 0 && errno != ENOENT) {
++ torture_comment(tctx, "final unlink of '%s' failed\n",
++ wins_hook_file);
++ }
++ torture_assert(tctx, ret, "wins hook failure\n");
++ return ret;
++}
++
++
+ /*
+ test WINS operations
+ */
+@@ -540,6 +668,8 @@ struct torture_suite *torture_nbt_wins(TALLOC_CTX *mem_ctx)
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "wins");
+
+ torture_suite_add_simple_test(suite, "wins", nbt_test_wins);
++ torture_suite_add_simple_test(suite, "wins_bad_names",
++ nbt_test_wins_bad_names);
+
+ return suite;
+ }
+diff --git a/testprogs/blackbox/wins_hook_test b/testprogs/blackbox/wins_hook_test
+new file mode 100755
+index 00000000000..f15379c28ca
+--- /dev/null
++++ b/testprogs/blackbox/wins_hook_test
+@@ -0,0 +1,15 @@
++#!/usr/bin/python3
++
++import os
++import sys
++
++filename = f"{os.environ['SELFTEST_TMPDIR']}/wins_hook_writes_here"
++
++f = open(filename, 'wb')
++
++# Some names may truncate argv (e.g. '&'), for which we leave the file
++# empty.
++if len(sys.argv) > 2:
++ f.write(os.fsencode(sys.argv[2]))
++
++f.close()
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-wins-restrict-names-fed-to-shell.patch samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-wins-restrict-names-fed-to-shell.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-wins-restrict-names-fed-to-shell.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2025-10230/s4-wins-restrict-names-fed-to-shell.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,71 @@
+From: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+Date: Wed, 3 Sep 2025 14:20:24 +1200
+Subject: CVE-2025-10230: s4:wins: restrict names fed to shell
+
+If the "wins hook" smb.conf parameter is set, the WINS server will
+attempt to execute that value in a shell command line when a client
+asks to modify a name. The WINS system is a trusting one, and clients
+can claim any NETBIOS name they wish.
+
+With the source3 nmbd WINS server (since the 1999 commit now called
+3db52feb1f3b2c07ce0b06ad4a7099fa6efe3fc7) the wins hook will not be
+run for names that contain shell metacharacters. This restriction has
+not been present on the source4 nbt WINS server, which is the WINS
+server that will be used in the event that an Active Directory Domain
+Controller is also running WINS.
+
+This allowed an unauthenticated client to execute arbitrary commands
+on the server.
+
+This commit brings the nmbd check into the nbt WINS server, so that
+the wins hook will only be run for names that contain only letters,
+digits, hyphens, underscores and periods. This matches the behaviour
+described in the smb.conf man page.
+
+The source3 nmbd WINS server has another layer of protection, in that
+it uses the smb_run() exec wrapper that tries to escape arguments. We
+don't do that here.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15903
+
+Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
+Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
+---
+ selftest/knownfail.d/samba4.nbt.wins.wins_bad_names | 1 -
+ source4/nbt_server/wins/wins_hook.c | 9 +++++++++
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+ delete mode 100644 selftest/knownfail.d/samba4.nbt.wins.wins_bad_names
+
+diff --git a/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names b/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names
+deleted file mode 100644
+index 52388ce5749..00000000000
+--- a/selftest/knownfail.d/samba4.nbt.wins.wins_bad_names
++++ /dev/null
+@@ -1 +0,0 @@
+-samba4.nbt.wins.wins_bad_names
+diff --git a/source4/nbt_server/wins/wins_hook.c b/source4/nbt_server/wins/wins_hook.c
+index 1af471b15bc..442141fecdd 100644
+--- a/source4/nbt_server/wins/wins_hook.c
++++ b/source4/nbt_server/wins/wins_hook.c
+@@ -43,9 +43,18 @@ void wins_hook(struct winsdb_handle *h, const struct winsdb_record *rec,
+ int child;
+ char *cmd = NULL;
+ TALLOC_CTX *tmp_mem = NULL;
++ const char *p = NULL;
+
+ if (!wins_hook_script || !wins_hook_script[0]) return;
+
++ for (p = rec->name->name; *p; p++) {
++ if (!(isalnum((int)*p) || strchr_m("._-", *p))) {
++ DBG_ERR("not calling wins hook for invalid name %s\n",
++ rec->name->name);
++ return;
++ }
++ }
++
+ tmp_mem = talloc_new(h);
+ if (!tmp_mem) goto failed;
+
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/Add-torture-test-for-inserting-hole-in-stream.patch samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/Add-torture-test-for-inserting-hole-in-stream.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/Add-torture-test-for-inserting-hole-in-stream.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/Add-torture-test-for-inserting-hole-in-stream.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,286 @@
+From: Andrew Walker <andrew.walker at truenas.com>
+Date: Thu, 28 Aug 2025 19:39:34 +0000
+Subject: CVE-2025-9640: Add torture test for inserting hole in stream
+
+This commit adds an smb torture test for inserting a hole into
+an alternate data stream and then verifying that hole contains
+null bytes.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15885
+
+Signed-off-by: Andrew Walker <andrew.walker at truenas.com>
+Reviewed-by: Volker Lendecke <vl at samba.org>
+---
+ source3/selftest/tests.py | 3 +
+ source4/torture/vfs/streams_xattr.c | 211 ++++++++++++++++++++++++++++
+ source4/torture/vfs/vfs.c | 1 +
+ source4/torture/wscript_build | 2 +-
+ 4 files changed, 216 insertions(+), 1 deletion(-)
+ create mode 100644 source4/torture/vfs/streams_xattr.c
+
+diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
+index e93365e3db5..6d7c41c37d1 100755
+--- a/source3/selftest/tests.py
++++ b/source3/selftest/tests.py
+@@ -919,6 +919,7 @@ nbt = ["nbt.dgram"]
+ vfs = [
+ "vfs.fruit",
+ "vfs.acl_xattr",
++ "vfs.streams_xattr",
+ "vfs.fruit_netatalk",
+ "vfs.fruit_file_id",
+ "vfs.fruit_timemachine",
+@@ -1107,6 +1108,8 @@ for t in tests:
+ plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
+ elif t == "vfs.acl_xattr":
+ plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
++ elif t == "vfs.streams_xattr":
++ plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_wo_fruit -U$USERNAME%$PASSWORD')
+ elif t == "smb2.compound_find":
+ plansmbtorture4testsuite(t, "fileserver", '//$SERVER/compound_find -U$USERNAME%$PASSWORD')
+ plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
+diff --git a/source4/torture/vfs/streams_xattr.c b/source4/torture/vfs/streams_xattr.c
+new file mode 100644
+index 00000000000..0eb83e092e7
+--- /dev/null
++++ b/source4/torture/vfs/streams_xattr.c
+@@ -0,0 +1,211 @@
++/*
++ Unix SMB/CIFS implementation.
++
++ Copyright (C) Andrew Walker (2025)
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 3 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program. If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "includes.h"
++#include "lib/cmdline/cmdline.h"
++#include "libcli/smb2/smb2.h"
++#include "libcli/smb2/smb2_calls.h"
++#include "libcli/smb/smbXcli_base.h"
++#include "torture/torture.h"
++#include "torture/vfs/proto.h"
++#include "libcli/resolve/resolve.h"
++#include "torture/util.h"
++#include "torture/smb2/proto.h"
++#include "lib/param/param.h"
++
++#define BASEDIR "smb2-testads"
++
++
++static bool get_stream_handle(struct torture_context *tctx,
++ struct smb2_tree *tree,
++ const char *dname,
++ const char *fname,
++ const char *sname,
++ struct smb2_handle *hdl_in)
++{
++ bool ret = true;
++ NTSTATUS status;
++ struct smb2_handle fhandle = {{0}};
++ struct smb2_handle dhandle = {{0}};
++
++ torture_comment(tctx, "Create dir\n");
++
++ status = torture_smb2_testdir(tree, dname, &dhandle);
++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n");
++
++ torture_comment(tctx, "Create file\n");
++
++ status = torture_smb2_testfile(tree, fname, &fhandle);
++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testfile\n");
++
++ status = torture_smb2_testfile(tree, sname, hdl_in);
++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testfile\n");
++
++done:
++ if (!smb2_util_handle_empty(fhandle)) {
++ smb2_util_close(tree, fhandle);
++ }
++ if (!smb2_util_handle_empty(dhandle)) {
++ smb2_util_close(tree, dhandle);
++ }
++ return ret;
++}
++
++static bool read_stream(struct torture_context *tctx,
++ TALLOC_CTX *mem_ctx,
++ struct smb2_tree *tree,
++ struct smb2_handle *stream_hdl,
++ off_t read_offset,
++ size_t read_count,
++ char **data_out,
++ size_t *data_out_sz)
++{
++ NTSTATUS status;
++ struct smb2_read r;
++ bool ret = true;
++
++ ZERO_STRUCT(r);
++ r.in.file.handle = *stream_hdl;
++ r.in.length = read_count;
++ r.in.offset = read_offset;
++
++ status = smb2_read(tree, mem_ctx, &r);
++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "stream read\n");
++
++ *data_out = (char *)r.out.data.data;
++ *data_out_sz = r.out.data.length;
++
++done:
++ return ret;
++}
++
++
++#define WRITE_PAYLOAD "canary"
++#define ADS_LEN 1024
++#define ADS_OFF_TAIL ADS_LEN - sizeof(WRITE_PAYLOAD)
++
++static bool test_streams_pwrite_hole(struct torture_context *tctx,
++ struct smb2_tree *tree)
++{
++ NTSTATUS status;
++ bool ok;
++ bool ret = true;
++ const char *dname = BASEDIR "\\testdir";
++ const char *fname = BASEDIR "\\testdir\\testfile";
++ const char *sname = BASEDIR "\\testdir\\testfile:test_stream";
++ const char *canary = "canary";
++ struct smb2_handle shandle = {{0}};
++ TALLOC_CTX *tmp_ctx = NULL;
++ char *data = NULL;
++ size_t data_sz, i;
++
++ ok = smb2_util_setup_dir(tctx, tree, BASEDIR);
++ torture_assert_goto(tctx, ok == true, ret, done, "Unable to setup testdir\n");
++
++ tmp_ctx = talloc_new(tree);
++ torture_assert_goto(tctx, tmp_ctx != NULL, ret, done, "Memory failure\n");
++
++ ok = get_stream_handle(tctx, tree, dname, fname, sname, &shandle);
++ if (!ok) {
++ // torture assert already set
++ goto done;
++ }
++
++ /*
++ * We're going to write a string at the beginning at the ADS, then write the same
++ * string at a later offset, introducing a hole in the file
++ */
++ torture_comment(tctx, "writing at varying offsets to create hole\n");
++ status = smb2_util_write(tree, shandle, WRITE_PAYLOAD, 0, sizeof(WRITE_PAYLOAD));
++ if (!NT_STATUS_IS_OK(status)) {
++ torture_comment(tctx, "Failed to write %zu bytes to "
++ "stream at offset 0\n", sizeof(canary));
++ return false;
++ }
++
++ status = smb2_util_write(tree, shandle, WRITE_PAYLOAD, ADS_OFF_TAIL, sizeof(WRITE_PAYLOAD));
++ if (!NT_STATUS_IS_OK(status)) {
++ torture_comment(tctx, "Failed to write %zu bytes to "
++ "stream at offset 1018\n", sizeof(canary));
++ return false;
++ }
++
++ /* Now we'll read the stream contents */
++ torture_comment(tctx, "Read stream data\n");
++ ok = read_stream(tctx, tmp_ctx, tree, &shandle, 0, ADS_LEN, &data, &data_sz);
++ if (!ok) {
++ // torture assert already set
++ goto done;
++ }
++
++ torture_assert_goto(tctx, data_sz == ADS_LEN, ret, done, "Short read on ADS\n");
++
++ /* Make sure our strings actually got written */
++ if (strncmp(data, WRITE_PAYLOAD, sizeof(WRITE_PAYLOAD)) != 0) {
++ torture_result(tctx, TORTURE_FAIL,
++ "Payload write at beginning of file failed");
++ ret = false;
++ goto done;
++ }
++
++ if (strncmp(data + ADS_OFF_TAIL, WRITE_PAYLOAD, sizeof(WRITE_PAYLOAD)) != 0) {
++ torture_result(tctx, TORTURE_FAIL,
++ "Payload write at end of file failed");
++ ret = false;
++ goto done;
++ }
++
++ /* Now we'll check that the hole is full of null bytes */
++ for (i = sizeof(WRITE_PAYLOAD); i < ADS_OFF_TAIL; i++) {
++ if (data[i] != '\0') {
++ torture_comment(tctx, "idx: %zu, got 0x%02x when expected 0x00\n",
++ i, (uint8_t)data[i]);
++ torture_result(tctx, TORTURE_FAIL,
++ "0x%08x: unexpected non-null byte in ADS read\n",
++ data[i]);
++ ret = false;
++ goto done;
++ }
++ }
++
++done:
++ talloc_free(tmp_ctx);
++
++ if (!smb2_util_handle_empty(shandle)) {
++ smb2_util_close(tree, shandle);
++ }
++
++ smb2_deltree(tree, BASEDIR);
++
++ return ret;
++}
++
++/*
++ basic testing of vfs_streams_xattr
++*/
++struct torture_suite *torture_vfs_streams_xattr(TALLOC_CTX *ctx)
++{
++ struct torture_suite *suite = torture_suite_create(ctx, "streams_xattr");
++
++ torture_suite_add_1smb2_test(suite, "streams-pwrite-hole", test_streams_pwrite_hole);
++
++ suite->description = talloc_strdup(suite, "vfs_streams_xattr tests");
++
++ return suite;
++}
+diff --git a/source4/torture/vfs/vfs.c b/source4/torture/vfs/vfs.c
+index 69da13f6d28..28e0b16ed95 100644
+--- a/source4/torture/vfs/vfs.c
++++ b/source4/torture/vfs/vfs.c
+@@ -115,6 +115,7 @@ NTSTATUS torture_vfs_init(TALLOC_CTX *ctx)
+ torture_suite_add_suite(suite, torture_vfs_fruit_timemachine(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_conversion(suite));
+ torture_suite_add_suite(suite, torture_vfs_fruit_unfruit(suite));
++ torture_suite_add_suite(suite, torture_vfs_streams_xattr(suite));
+
+ torture_register_suite(ctx, suite);
+
+diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build
+index 6bfc6aeae65..57e006dcaf8 100644
+--- a/source4/torture/wscript_build
++++ b/source4/torture/wscript_build
+@@ -305,7 +305,7 @@ bld.SAMBA_MODULE('TORTURE_NTP',
+ )
+
+ bld.SAMBA_MODULE('TORTURE_VFS',
+- source='vfs/vfs.c vfs/fruit.c vfs/acl_xattr.c',
++ source='vfs/vfs.c vfs/fruit.c vfs/acl_xattr.c vfs/streams_xattr.c',
+ subsystem='smbtorture',
+ deps='LIBCLI_SMB TORTURE_UTIL smbclient-raw TORTURE_RAW',
+ internal_module=True,
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/s3-modules-vfs_streams_xattr-fix-unitialized-write.patch samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/s3-modules-vfs_streams_xattr-fix-unitialized-write.patch
--- samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/s3-modules-vfs_streams_xattr-fix-unitialized-write.patch 1970-01-01 03:00:00.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/CVE-2025-9640/s3-modules-vfs_streams_xattr-fix-unitialized-write.patch 2025-11-30 11:35:04.000000000 +0300
@@ -0,0 +1,44 @@
+From: Andrew Walker <andrew.walker at truenas.com>
+Date: Thu, 28 Aug 2025 19:36:19 +0000
+Subject: CVE-2025-9640: s3/modules/vfs_streams_xattr fix unitialized write
+
+This commit fixes a situation in which vfs_streams_xattr could
+write unitialized memory into alternate data streams if the
+user writes to an offset that is beyond the current end of file
+to insert a hole in it.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=15885
+
+Signed-off-by: Andrew Walker <andrew.walker at truenas.com>
+Reviewed-by: Volker Lendecke <vl at samba.org>
+---
+ source3/modules/vfs_streams_xattr.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
+index f3371ca9b7e..5a419dbb705 100644
+--- a/source3/modules/vfs_streams_xattr.c
++++ b/source3/modules/vfs_streams_xattr.c
+@@ -963,15 +963,18 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
+
+ if ((offset + n) > ea.value.length-1) {
+ uint8_t *tmp;
++ size_t new_sz = offset + n + 1;
+
+ tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
+- offset + n + 1);
++ new_sz);
+
+ if (tmp == NULL) {
+ TALLOC_FREE(ea.value.data);
+ errno = ENOMEM;
+ return -1;
+ }
++
++ memset(tmp + ea.value.length, 0, new_sz - ea.value.length);
+ ea.value.data = tmp;
+ ea.value.length = offset + n + 1;
+ ea.value.data[offset+n] = 0;
+--
+2.47.3
+
diff -Nru samba-4.17.12+dfsg/debian/patches/series samba-4.17.12+dfsg/debian/patches/series
--- samba-4.17.12+dfsg/debian/patches/series 2025-07-10 16:02:07.000000000 +0300
+++ samba-4.17.12+dfsg/debian/patches/series 2025-11-30 11:35:04.000000000 +0300
@@ -30,3 +30,17 @@
s3-winbindd-use-better-debug-messages-than-talloc_st.patch
s3-winbindd-avoid-using-any-netlogon-call-to-get-a-d.patch
s3-winbindd-Fix-internal-winbind-dsgetdcname-calls-w.patch
+# CVE-2018-14628: Unprivileged read of deleted object tombstones in AD LDAP server
+# https://gitlab.com/samba-team/lts-community/samba/-/merge_requests/3
+CVE-2018-14628/01-python-descriptor-add-get_deletedobjects_descriptor.patch
+CVE-2018-14628/02-python-provision-make-DELETEDOBJECTS_DESCRIPTOR-availab.patch
+CVE-2018-14628/03-s4-setup-set-the-correct-nTSecurityDescriptor-on-the-CN.patch
+CVE-2018-14628/04-s4-dsdb-remove-unused-code-in-dirsync_filter_entry.patch
+CVE-2018-14628/05-dbchecker-use-get_deletedobjects_descriptor-for-missing.patch
+CVE-2018-14628/06-python-descriptor-let-samba-tool-dbch.patch
+# CVE-2025-10230: Command injection via WINS server hook script
+CVE-2025-10230/s4-tests-check-that-wins-hook-sanitizes-names.patch
+CVE-2025-10230/s4-wins-restrict-names-fed-to-shell.patch
+# CVE-2025-9640: Uninitialized memory disclosure via vfs_streams_xattr
+CVE-2025-9640/Add-torture-test-for-inserting-hole-in-stream.patch
+CVE-2025-9640/s3-modules-vfs_streams_xattr-fix-unitialized-write.patch
More information about the Pkg-samba-maint
mailing list