[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Wed Aug 2 12:11:01 UTC 2023


The branch, master has been updated
       via  00316255984 dsdb: Make a shallow copy of ldb_parse_tree in operational module
       via  3b51091c20a dsdb: Replace talloc_steal() with a shallow copy and reference in dsdb_paged_results
       via  1b68bd977af paged_results: add no memory checks in paged_search()
       via  c67534fe3ff selftest: Add test for combination of anr and paged_results
       via  8f4c1c67b4f vfs_aio_pthread: fix segfault if samba-tool ntacl get
      from  d23dd3e26c5 dsdb: Add tracing to dsdb_search_dn() similar to gendb_search_v()

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 003162559848ce45d4f5bd3fb66642960538120f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Aug 2 14:13:00 2023 +1200

    dsdb: Make a shallow copy of ldb_parse_tree in operational module
    
    We should not be making modifications to caller memory.  In
    particular, this causes problems for logging of requests if the
    original request becomes modified.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15442
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Wed Aug  2 12:10:20 UTC 2023 on atb-devel-224

commit 3b51091c20a3c807932bcc986ebb8a676e0ffe6a
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Aug 2 14:12:07 2023 +1200

    dsdb: Replace talloc_steal() with a shallow copy and reference in dsdb_paged_results
    
    We should not be stealing caller memory like this, and while a
    talloc_reference() is not much better, this combined with a
    shallow copy should be a little better in terms of polite
    memory management.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15442
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 1b68bd977af39263a71af2c6a314c5ccb29e348c
Author: Stefan Metzmacher <metze at samba.org>
Date:   Tue Feb 8 00:41:54 2022 +0100

    paged_results: add no memory checks in paged_search()
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15442
    
    Signed-off-by: Arvid Requate <requate at univention.de>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    
    [abartlet at samba.org combination of two patches by the above authors]

commit c67534fe3ff1652dcf95eac2030778b066cdf7a4
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Aug 2 13:40:03 2023 +1200

    selftest: Add test for combination of anr and paged_results
    
    This combination was known to cause a segfault in Samba 4.13, fixed by
    5f0590362c5c0c5ee20503a67467f9be2d50e73b in later versions.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14970
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 8f4c1c67b4f118a9a47b09ac7908cd3d969b19c2
Author: Jones Syue <jonessyue at qnap.com>
Date:   Wed Aug 2 09:48:40 2023 +0800

    vfs_aio_pthread: fix segfault if samba-tool ntacl get
    
    If configured as AD DC and aio_pthread appended into 'vfs objects'[1],
    run these commands would get segfault:
    1. sudo samba-tool ntacl get .
    2. sudo net vfs getntacl sysvol .
    gdb said it goes through aio_pthread_openat_fn() @ vfs_aio_pthread.c[2],
    and the fsp->conn->sconn->client is null (0x0).
    
    'sconn->client' memory is allocated when a new connection is accpeted:
    smbd_accept_connection > smbd_process > smbXsrv_client_create
    While running local commands looks like it would not go through
    smbXsrv_client_create so the 'client' is null, segfault might happen.
    We should not dereference 'client->server_multi_channel_enabled',
    if 'client' is null.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15441
    
    [1] smb.conf example, samba-4.18.5, ubuntu 22.04.2
    [global]
            dns forwarder = 127.0.0.53
            netbios name = U22-JONES-88X1
            realm = U22-JONES-88X1.X88X1.JONES
            server role = active directory domain controller
            workgroup = X88X1
            idmap_ldb:use rfc2307 = yes
            vfs objects = dfs_samba4 acl_xattr aio_pthread
    
    [sysvol]
            path = /var/lib/samba/sysvol
            read only = No
    
    [netlogon]
            path = /var/lib/samba/sysvol/u22-jones-88x1.x88x1.jones/scripts
            read only = No
    
    [2] gdb
    (gdb) run /usr/local/samba/bin/samba-tool ntacl get .
    Starting program: /usr/local/Python3/bin/python3 /usr/local/samba/bin/samba-tool ntacl get .
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/libthread_db.so.1".
    
    Program received signal SIGSEGV, Segmentation fault.
    0x00007fffd0eb809e in aio_pthread_openat_fn (handle=0x8d5cc0, dirfsp=0x8c3070, smb_fname=0x18ab4f0, fsp=0x1af3550, flags=196608, mode=0)
        at ../../source3/modules/vfs_aio_pthread.c:467
    warning: Source file is more recent than executable.
    467             if (fsp->conn->sconn->client->server_multi_channel_enabled) {
    (gdb) bt
        at ../../source3/modules/vfs_aio_pthread.c:467
        at ../../source3/smbd/pysmbd.c:320
    ---Type <return> to continue, or q <return> to quit---
    (gdb) f
        at ../../source3/modules/vfs_aio_pthread.c:467
    467             if (fsp->conn->sconn->client->server_multi_channel_enabled) {
    (gdb) p fsp->conn->sconn->client
    $1 = (struct smbXsrv_client *) 0x0
    (gdb)
    
    Signed-off-by: Jones Syue <jonessyue at qnap.com>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/modules/vfs_aio_pthread.c              |  3 +-
 source4/dsdb/samdb/ldb_modules/operational.c   | 93 +++++++++++++++++++++++---
 source4/dsdb/samdb/ldb_modules/paged_results.c | 39 ++++++++++-
 source4/dsdb/tests/python/vlv.py               | 21 ++++++
 4 files changed, 143 insertions(+), 13 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/modules/vfs_aio_pthread.c b/source3/modules/vfs_aio_pthread.c
index 428ae5f2a4c..0303ff04bc9 100644
--- a/source3/modules/vfs_aio_pthread.c
+++ b/source3/modules/vfs_aio_pthread.c
@@ -475,7 +475,8 @@ static int aio_pthread_openat_fn(vfs_handle_struct *handle,
 		aio_allow_open = false;
 	}
 
-	if (fsp->conn->sconn->client->server_multi_channel_enabled) {
+	if (fsp->conn->sconn->client != NULL &&
+	    fsp->conn->sconn->client->server_multi_channel_enabled) {
 		/*
 		 * This module is not compatible with multi channel yet.
 		 */
diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c
index 8821765a703..5d87a16564f 100644
--- a/source4/dsdb/samdb/ldb_modules/operational.c
+++ b/source4/dsdb/samdb/ldb_modules/operational.c
@@ -1556,6 +1556,7 @@ struct operational_context {
 	struct ldb_request *req;
 	enum ldb_scope scope;
 	const char * const *attrs;
+	struct ldb_parse_tree *tree;
 	struct op_controls_flags* controls_flags;
 	struct op_attributes_operations *list_operations;
 	unsigned int list_operations_size;
@@ -1681,12 +1682,57 @@ static struct op_attributes_operations* operation_get_op_list(TALLOC_CTX *ctx,
 	return list;
 }
 
+struct operational_present_ctx {
+	const char *attr;
+	bool found_operational;
+};
+
+/*
+  callback to determine if an operational attribute (needing
+  replacement) is in use at all
+ */
+static int operational_present(struct ldb_parse_tree *tree, void *private_context)
+{
+	struct operational_present_ctx *ctx = private_context;
+	switch (tree->operation) {
+	case LDB_OP_EQUALITY:
+	case LDB_OP_GREATER:
+	case LDB_OP_LESS:
+	case LDB_OP_APPROX:
+		if (ldb_attr_cmp(tree->u.equality.attr, ctx->attr) == 0) {
+			ctx->found_operational = true;
+		}
+		break;
+	case LDB_OP_SUBSTRING:
+		if (ldb_attr_cmp(tree->u.substring.attr, ctx->attr) == 0) {
+			ctx->found_operational = true;
+		}
+		break;
+	case LDB_OP_PRESENT:
+		if (ldb_attr_cmp(tree->u.present.attr, ctx->attr) == 0) {
+			ctx->found_operational = true;
+		}
+		break;
+	case LDB_OP_EXTENDED:
+		if (tree->u.extended.attr &&
+		    ldb_attr_cmp(tree->u.extended.attr, ctx->attr) == 0) {
+			ctx->found_operational = true;
+		}
+		break;
+	default:
+		break;
+	}
+	return LDB_SUCCESS;
+}
+
+
 static int operational_search(struct ldb_module *module, struct ldb_request *req)
 {
 	struct ldb_context *ldb;
 	struct operational_context *ac;
 	struct ldb_request *down_req;
 	const char **search_attrs = NULL;
+	struct operational_present_ctx ctx;
 	unsigned int i, a;
 	int ret;
 
@@ -1707,15 +1753,44 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
 	ac->scope = req->op.search.scope;
 	ac->attrs = req->op.search.attrs;
 
-	/*  FIXME: We must copy the tree and keep the original
-	 *  unmodified. SSS */
-	/* replace any attributes in the parse tree that are
-	   searchable, but are stored using a different name in the
-	   backend */
+	ctx.found_operational = false;
+
+	/*
+	 * find any attributes in the parse tree that are searchable,
+	 * but are stored using a different name in the backend, so we
+	 * only duplicate the memory when needed
+	 */
 	for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
-		ldb_parse_tree_attr_replace(req->op.search.tree,
-					    parse_tree_sub[i].attr,
-					    parse_tree_sub[i].replace);
+		ctx.attr = parse_tree_sub[i].attr;
+
+		ldb_parse_tree_walk(req->op.search.tree,
+				    operational_present,
+				    &ctx);
+		if (ctx.found_operational) {
+			break;
+		}
+	}
+
+	if (ctx.found_operational) {
+
+		ac->tree = ldb_parse_tree_copy_shallow(ac,
+						       req->op.search.tree);
+
+		if (ac->tree == NULL) {
+			return ldb_operr(ldb);
+		}
+
+		/* replace any attributes in the parse tree that are
+		   searchable, but are stored using a different name in the
+		   backend */
+		for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
+			ldb_parse_tree_attr_replace(ac->tree,
+						    parse_tree_sub[i].attr,
+						    parse_tree_sub[i].replace);
+		}
+	} else {
+		/* Avoid allocating a copy if we do not need to */
+		ac->tree = req->op.search.tree;
 	}
 
 	ac->controls_flags = talloc(ac, struct op_controls_flags);
@@ -1795,7 +1870,7 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
 	ret = ldb_build_search_req_ex(&down_req, ldb, ac,
 					req->op.search.base,
 					req->op.search.scope,
-					req->op.search.tree,
+					ac->tree,
 					/* use new set of attrs if any */
 					search_attrs == NULL?req->op.search.attrs:search_attrs,
 					req->controls,
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
index 2063e84e157..83729b02c0b 100644
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
@@ -681,6 +681,7 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
 		struct ldb_control *ext_ctrl;
 		struct ldb_control **controls;
 		static const char * const attrs[1] = { NULL };
+		void *ref = NULL;
 
 		if (paged_ctrl->size == 0) {
 			return LDB_ERR_OPERATIONS_ERROR;
@@ -705,9 +706,15 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
 			struct ldb_request *req_extended_dn;
 			struct ldb_extended_dn_control *ext_ctrl_data;
 			req_extended_dn = talloc_zero(req, struct ldb_request);
+			if (req_extended_dn == NULL) {
+				return ldb_module_oom(module);
+			}
 			req_extended_dn->controls = req->controls;
 			ext_ctrl_data = talloc_zero(req,
 					struct ldb_extended_dn_control);
+			if (ext_ctrl_data == NULL) {
+				return ldb_module_oom(module);
+			}
 			ext_ctrl_data->type = 1;
 
 			ret = ldb_request_add_control(req_extended_dn,
@@ -733,11 +740,37 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
 			return ret;
 		}
 
-		ac->store->expr = talloc_steal(ac->store, req->op.search.tree);
+		/*
+		 * LDB does not have a function to take a full copy of
+		 * this, but at least take a shallow copy
+		 */
+		ac->store->expr = ldb_parse_tree_copy_shallow(ac->store,
+							      req->op.search.tree);
+
+		if (ac->store->expr == NULL) {
+			return ldb_operr(ldb);
+		}
+
+		/*
+		 * As the above is only a shallow copy, take a
+		 * reference to ensure the values are kept around
+		 */
+		ref = talloc_reference(ac->store, req->op.search.tree);
+		if (ref == NULL) {
+			return ldb_module_oom(module);
+		}
 		ac->store->expr_str = ldb_filter_from_tree(ac->store,
 							  req->op.search.tree);
-		ac->store->attrs = paged_copy_attrs(ac->store,
-						    req->op.search.attrs);
+		if (ac->store->expr_str == NULL) {
+			return ldb_module_oom(module);
+		}
+		if (req->op.search.attrs != NULL) {
+			ac->store->attrs = paged_copy_attrs(ac->store,
+							    req->op.search.attrs);
+			if (ac->store->attrs == NULL) {
+				return ldb_module_oom(module);
+			}
+		}
 
 		/* save it locally and remove it from the list */
 		/* we do not need to replace them later as we
diff --git a/source4/dsdb/tests/python/vlv.py b/source4/dsdb/tests/python/vlv.py
index 33b51557ed3..13fccba75c9 100644
--- a/source4/dsdb/tests/python/vlv.py
+++ b/source4/dsdb/tests/python/vlv.py
@@ -1754,6 +1754,27 @@ class PagedResultsTestsRW(PagedResultsTests):
             (enum, estr) = e.args
             self.assertEqual(enum, ldb.ERR_UNSUPPORTED_CRITICAL_EXTENSION)
 
+    def test_anr_paged(self):
+        """Testing behaviour with anr= searches and paged_results set.
+
+        A problematic combination, as anr involves filter rewriting
+
+        """
+        prefix = "anr"
+        num_users = 5
+        users = [self.create_user(i, num_users, prefix=prefix)
+                 for i in range(num_users)]
+        expr = f"(|(anr={prefix})(&(objectClass=user)(facsimileTelephoneNumber={prefix}*)))"
+
+        results, cookie = self.paged_search(expr, page_size=1)
+        self.assertEqual(len(results), 1)
+
+        results, cookie = self.paged_search(expr, page_size=2, cookie=cookie)
+        self.assertEqual(len(results), 2)
+
+        results, cookie = self.paged_search(expr, page_size=2, cookie=cookie)
+        self.assertEqual(len(results), 2)
+
 
 if "://" not in host:
     if os.path.isfile(host):


-- 
Samba Shared Repository



More information about the samba-cvs mailing list