d3d5e6
From 98464c11df8247d6a11b52e294ba5dd4f0380440 Mon Sep 17 00:00:00 2001
d3d5e6
From: Howard Chu <hyc@openldap.org>
d3d5e6
Date: Thu, 16 Apr 2020 01:08:19 +0100
d3d5e6
Subject: [PATCH] ITS#9202 limit depth of nested filters
d3d5e6
d3d5e6
Using a hardcoded limit for now; no reasonable apps
d3d5e6
should ever run into it.
d3d5e6
---
d3d5e6
 servers/slapd/filter.c | 41 ++++++++++++++++++++++++++++++++---------
d3d5e6
 1 file changed, 32 insertions(+), 9 deletions(-)
d3d5e6
d3d5e6
diff --git a/servers/slapd/filter.c b/servers/slapd/filter.c
d3d5e6
index 3252cf2a7..ed57bbd7b 100644
d3d5e6
--- a/servers/slapd/filter.c
d3d5e6
+++ b/servers/slapd/filter.c
d3d5e6
@@ -37,11 +37,16 @@
d3d5e6
 const Filter *slap_filter_objectClass_pres;
d3d5e6
 const struct berval *slap_filterstr_objectClass_pres;
d3d5e6
 
d3d5e6
+#ifndef SLAPD_MAX_FILTER_DEPTH
d3d5e6
+#define SLAPD_MAX_FILTER_DEPTH	5000
d3d5e6
+#endif
d3d5e6
+
d3d5e6
 static int	get_filter_list(
d3d5e6
 	Operation *op,
d3d5e6
 	BerElement *ber,
d3d5e6
 	Filter **f,
d3d5e6
-	const char **text );
d3d5e6
+	const char **text,
d3d5e6
+	int depth );
d3d5e6
 
d3d5e6
 static int	get_ssa(
d3d5e6
 	Operation *op,
d3d5e6
@@ -80,12 +85,13 @@ filter_destroy( void )
d3d5e6
 	return;
d3d5e6
 }
d3d5e6
 
d3d5e6
-int
d3d5e6
-get_filter(
d3d5e6
+static int
d3d5e6
+get_filter0(
d3d5e6
 	Operation *op,
d3d5e6
 	BerElement *ber,
d3d5e6
 	Filter **filt,
d3d5e6
-	const char **text )
d3d5e6
+	const char **text,
d3d5e6
+	int depth )
d3d5e6
 {
d3d5e6
 	ber_tag_t	tag;
d3d5e6
 	ber_len_t	len;
d3d5e6
@@ -126,6 +132,11 @@ get_filter(
d3d5e6
 	 *
d3d5e6
 	 */
d3d5e6
 
d3d5e6
+	if( depth > SLAPD_MAX_FILTER_DEPTH ) {
d3d5e6
+		*text = "filter nested too deeply";
d3d5e6
+		return SLAPD_DISCONNECT;
d3d5e6
+	}
d3d5e6
+
d3d5e6
 	tag = ber_peek_tag( ber, &len );
d3d5e6
 
d3d5e6
 	if( tag == LBER_ERROR ) {
d3d5e6
@@ -221,7 +232,7 @@ get_filter(
d3d5e6
 
d3d5e6
 	case LDAP_FILTER_AND:
d3d5e6
 		Debug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
d3d5e6
-		err = get_filter_list( op, ber, &f.f_and, text );
d3d5e6
+		err = get_filter_list( op, ber, &f.f_and, text, depth+1 );
d3d5e6
 		if ( err != LDAP_SUCCESS ) {
d3d5e6
 			break;
d3d5e6
 		}
d3d5e6
@@ -234,7 +245,7 @@ get_filter(
d3d5e6
 
d3d5e6
 	case LDAP_FILTER_OR:
d3d5e6
 		Debug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
d3d5e6
-		err = get_filter_list( op, ber, &f.f_or, text );
d3d5e6
+		err = get_filter_list( op, ber, &f.f_or, text, depth+1 );
d3d5e6
 		if ( err != LDAP_SUCCESS ) {
d3d5e6
 			break;
d3d5e6
 		}
d3d5e6
@@ -248,7 +259,7 @@ get_filter(
d3d5e6
 	case LDAP_FILTER_NOT:
d3d5e6
 		Debug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
d3d5e6
 		(void) ber_skip_tag( ber, &len );
d3d5e6
-		err = get_filter( op, ber, &f.f_not, text );
d3d5e6
+		err = get_filter0( op, ber, &f.f_not, text, depth+1 );
d3d5e6
 		if ( err != LDAP_SUCCESS ) {
d3d5e6
 			break;
d3d5e6
 		}
d3d5e6
@@ -311,10 +322,22 @@ get_filter(
d3d5e6
 	return( err );
d3d5e6
 }
d3d5e6
 
d3d5e6
+int
d3d5e6
+get_filter(
d3d5e6
+	Operation *op,
d3d5e6
+	BerElement *ber,
d3d5e6
+	Filter **filt,
d3d5e6
+	const char **text )
d3d5e6
+{
d3d5e6
+	return get_filter0( op, ber, filt, text, 0 );
d3d5e6
+}
d3d5e6
+
d3d5e6
+
d3d5e6
 static int
d3d5e6
 get_filter_list( Operation *op, BerElement *ber,
d3d5e6
 	Filter **f,
d3d5e6
-	const char **text )
d3d5e6
+	const char **text,
d3d5e6
+	int depth )
d3d5e6
 {
d3d5e6
 	Filter		**new;
d3d5e6
 	int		err;
d3d5e6
@@ -328,7 +351,7 @@ get_filter_list( Operation *op, BerElement *ber,
d3d5e6
 		tag != LBER_DEFAULT;
d3d5e6
 		tag = ber_next_element( ber, &len, last ) )
d3d5e6
 	{
d3d5e6
-		err = get_filter( op, ber, new, text );
d3d5e6
+		err = get_filter0( op, ber, new, text, depth );
d3d5e6
 		if ( err != LDAP_SUCCESS )
d3d5e6
 			return( err );
d3d5e6
 		new = &(*new)->f_next;
d3d5e6
-- 
d3d5e6
2.26.2
d3d5e6