From 197d1f09158ee0575cd92c461ed12bdbf4efc074 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet@samba.org>
Date: Mon, 13 Mar 2023 14:25:56 +1300
Subject: [PATCH 01/35] CVE-2023-0614 lib/ldb: Avoid allocation and memcpy()
 for every wildcard match candidate

The value can be quite large, the allocation will take much
longer than the actual match and is repeated per candidate
record.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15331
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15270

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
(cherry picked from commit cad96f59a08192df927fb1df4e9787c7f70991a2)

[abartlet@samba.org Included in the security release as this
 makes the new large_ldap.py timeout test more reliable]

Conflict: NA
Reference: https://attachments.samba.org/attachment.cgi?id=17821
---
 common/ldb_match.c | 60 +++++++++++++++++++++++++++++++-------
 1 file changed, 50 insertions(+), 10 deletions(-)

diff --git a/common/ldb_match.c b/common/ldb_match.c
index 2f4d41f3441..51376871b4c 100644
--- a/common/ldb_match.c
+++ b/common/ldb_match.c
@@ -34,6 +34,7 @@
 
 #include "ldb_private.h"
 #include "dlinklist.h"
+#include "ldb_handlers.h"
 
 /*
   check if the scope matches in a search result
@@ -259,20 +260,42 @@ static int ldb_wildcard_compare(struct ldb_context *ldb,
 		return LDB_SUCCESS;
 	}
 
-	if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
-		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+	/* No need to just copy this value for a binary match */
+	if (a->syntax->canonicalise_fn != ldb_handler_copy) {
+		if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
+			return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+		}
+
+		/*
+		 * Only set save_p if we allocate (call
+		 * a->syntax->canonicalise_fn()), as we
+		 * talloc_free(save_p) below to clean up
+		 */
+		save_p = val.data;
+	} else {
+		val = value;
 	}
 
-	save_p = val.data;
 	cnk.data = NULL;
 
 	if ( ! tree->u.substring.start_with_wildcard ) {
+		uint8_t *cnk_to_free = NULL;
 
 		chunk = tree->u.substring.chunks[c];
-		if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
+		/* No need to just copy this value for a binary match */
+		if (a->syntax->canonicalise_fn != ldb_handler_copy) {
+			if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) {
+				goto mismatch;
+			}
+
+			cnk_to_free = cnk.data;
+		} else {
+			cnk = *chunk;
+		}
 
 		/* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
 		if (cnk.length > val.length) {
+			TALLOC_FREE(cnk_to_free);
 			goto mismatch;
 		}
 		/*
@@ -280,32 +303,47 @@ static int ldb_wildcard_compare(struct ldb_context *ldb,
 		 * we can cope with this.
 		 */
 		if (cnk.length == 0) {
+			TALLOC_FREE(cnk_to_free);
+			goto mismatch;
+		}
+
+		if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) {
+			TALLOC_FREE(cnk_to_free);
 			goto mismatch;
 		}
 
-		if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch;
 		val.length -= cnk.length;
 		val.data += cnk.length;
 		c++;
-		talloc_free(cnk.data);
+		TALLOC_FREE(cnk_to_free);
 		cnk.data = NULL;
 	}
 
 	while (tree->u.substring.chunks[c]) {
 		uint8_t *p;
+		uint8_t *cnk_to_free = NULL;
 
 		chunk = tree->u.substring.chunks[c];
-		if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) {
-			goto mismatch;
+		/* No need to just copy this value for a binary match */
+		if (a->syntax->canonicalise_fn != ldb_handler_copy) {
+			if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) {
+				goto mismatch;
+			}
+
+			cnk_to_free = cnk.data;
+		} else {
+			cnk = *chunk;
 		}
 		/*
 		 * Empty strings are returned as length 0. Ensure
 		 * we can cope with this.
 		 */
 		if (cnk.length == 0) {
+			TALLOC_FREE(cnk_to_free);
 			goto mismatch;
 		}
 		if (cnk.length > val.length) {
+			TALLOC_FREE(cnk_to_free);
 			goto mismatch;
 		}
 
@@ -320,6 +358,8 @@ static int ldb_wildcard_compare(struct ldb_context *ldb,
 			cmp = memcmp(p,
 				     cnk.data,
 				     cnk.length);
+			TALLOC_FREE(cnk_to_free);
+
 			if (cmp != 0) {
 				goto mismatch;
 			}
@@ -331,15 +371,16 @@ static int ldb_wildcard_compare(struct ldb_context *ldb,
 			p = memmem((const void *)val.data, val.length,
 				   (const void *)cnk.data, cnk.length);
 			if (p == NULL) {
+				TALLOC_FREE(cnk_to_free);
 				goto mismatch;
 			}
 			/* move val to the end of the match */
 			p += cnk.length;
 			val.length -= (p - val.data);
 			val.data = p;
+			TALLOC_FREE(cnk_to_free);
 		}
 		c++;
-		TALLOC_FREE(cnk.data);
 	}
 
 	talloc_free(save_p);
@@ -349,7 +390,6 @@ static int ldb_wildcard_compare(struct ldb_context *ldb,
 mismatch:
 	*matched = false;
 	talloc_free(save_p);
-	talloc_free(cnk.data);
 	return LDB_SUCCESS;
 }
 
-- 
2.25.1
