Your message dated Sat, 10 Jan 2026 11:59:46 +0000
with message-id <[email protected]>
and subject line Released with 12.13
has caused the Debian Bug report #1121733,
regarding bookworm-pu: package samba/2:4.17.12+dfsg-0+deb12u3
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1121733: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1121733
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:samba
User: [email protected]
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 <[email protected]>  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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Bartlett <[email protected]>
+(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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Bartlett <[email protected]>
+(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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Bartlett <[email protected]>
+(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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Bartlett <[email protected]>
+(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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Bartlett <[email protected]>
+(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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Andrew Bartlett <[email protected]>
+(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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Gary Lockyer <[email protected]>
+---
+ 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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Gary Lockyer <[email protected]>
+---
+ 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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Volker Lendecke <[email protected]>
+---
+ 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 <[email protected]>
+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 <[email protected]>
+Reviewed-by: Volker Lendecke <[email protected]>
+---
+ 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

--- End Message ---
--- Begin Message ---
Package: release.debian.org\nVersion: 12.13\n\nThis update has been released as 
part of Debian 12.13.

--- End Message ---

Reply via email to