Преглед на файлове

Resolves: #182621 (#443955)
Summary: Allow larger regex buffer to enable long substring filters
Description: Applying the patches provided by [email protected].
regex.c: use dynamically allocated regex buffer, use ptrdiff_t to store the offsets to be restored after the realloc, and use a constant for the value of "how much the NFA buffer can grow in one iteration on the pattern".
string.c: use dynamically allocated buffer if the prepared buffer is not large enough, used wrong pointer (pat instead of p) in a debug message, and performed an unneeded strcat of ".*"

Noriko Hosoi преди 17 години
родител
ревизия
b7e14a574e
променени са 2 файла, в които са добавени 106 реда и са изтрити 60 реда
  1. 43 31
      ldap/servers/plugins/syntaxes/string.c
  2. 63 29
      ldap/servers/slapd/regex.c

+ 43 - 31
ldap/servers/plugins/syntaxes/string.c

@@ -189,8 +189,8 @@ int
 string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
     Slapi_Value **bvals, int syntax )
 {
-	int		i, j, rc;
-	char		*p, *end, *realval, *tmpbuf;
+	int		i, j, rc, size=0;
+	char		*p, *end, *realval, *tmpbuf, *bigpat = NULL;
 	size_t		tmpbufsize;
 	char		pat[BUFSIZ];
 	char		buf[BUFSIZ];
@@ -198,7 +198,6 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
 
 	LDAPDebug( LDAP_DEBUG_FILTER, "=> string_filter_sub\n",
 	    0, 0, 0 );
-
 	/*
 	 * construct a regular expression corresponding to the
 	 * filter and let regex do the work for each value
@@ -207,16 +206,33 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
 	pat[0] = '\0';
 	p = pat;
 	end = pat + sizeof(pat) - 2;	/* leave room for null */
+
 	if ( initial != NULL ) {
-		value_normalize( initial, syntax, 1 /* trim leading blanks */ );
-		strcpy( p, "^" );
-		p = strchr( p, '\0' );
-		/* 2 * in case every char is special */
-		if ( p + 2 * strlen( initial ) > end ) {
-			LDAPDebug( LDAP_DEBUG_ANY, "not enough pattern space\n",
-			    0, 0, 0 );
-			return( -1 );
+		size = strlen( initial ) + 1; /* add 1 for "^" */
+	}
+
+	if ( any != NULL ) {
+		i = 0;
+		while ( any[i] ) {
+			size += strlen(any[i++]) + 2; /* add 2 for ".*" */
 		}
+	}
+
+	if ( final != NULL ) {
+		 size += strlen( final ) + 3; /* add 3 for ".*" and "$" */
+	}
+
+	size *= 2; /* doubled in case all filter chars need escaping */
+	size++; /* add 1 for null */
+
+	if ( p + size > end ) {
+		bigpat = slapi_ch_malloc( size );
+		p = bigpat;
+	}
+
+	if ( initial != NULL ) {
+		value_normalize( initial, syntax, 1 /* trim leading blanks */ );
+		*p++ = '^';
 		filter_strcpy_special( p, initial );
 		p = strchr( p, '\0' );
 	}
@@ -224,13 +240,8 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
 		for ( i = 0; any[i] != NULL; i++ ) {
 			value_normalize( any[i], syntax, 0 /* DO NOT trim leading blanks */ );
 			/* ".*" + value */
-			if ( p + 2 * strlen( any[i] ) + 2 > end ) {
-				LDAPDebug( LDAP_DEBUG_ANY,
-				    "not enough pattern space\n", 0, 0, 0 );
-				return( -1 );
-			}
-			strcpy( p, ".*" );
-			p = strchr( p, '\0' );
+			*p++ = '.';
+			*p++ = '*';
 			filter_strcpy_special( p, any[i] );
 			p = strchr( p, '\0' );
 		}
@@ -238,28 +249,26 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
 	if ( final != NULL ) {
 		value_normalize( final, syntax, 0 /* DO NOT trim leading blanks */ );
 		/* ".*" + value */
-		if ( p + 2 * strlen( final ) + 2 > end ) {
-			LDAPDebug( LDAP_DEBUG_ANY, "not enough pattern space\n",
-			    0, 0, 0 );
-			return( -1 );
-		}
-		strcpy( p, ".*" );
-		p = strchr( p, '\0' );
+		*p++ = '.';
+		*p++ = '*';
 		filter_strcpy_special( p, final );
-		p = strchr( p, '\0' );
-		strcpy( p, "$" );
+		strcat( p, "$" );
 	}
 
 	/* compile the regex */
+	p = (bigpat) ? bigpat : pat;
 	slapd_re_lock();
-	if ( (p = slapd_re_comp( pat )) != 0 ) {
+	if ( (tmpbuf = slapd_re_comp( p )) != 0 ) {
 		LDAPDebug( LDAP_DEBUG_ANY, "re_comp (%s) failed (%s)\n",
 		    pat, p, 0 );
 		slapd_re_unlock();
-		return( -1 );
+		if( bigpat != NULL ) {
+			slapi_ch_free((void**)&bigpat );
+		}
+		return( LDAP_OPERATIONS_ERROR );
 	} else {
-		LDAPDebug( LDAP_DEBUG_TRACE, "re_comp (%s)\n",
-				   escape_string( pat, ebuf ), 0, 0 );
+ 		LDAPDebug( LDAP_DEBUG_TRACE, "re_comp (%s)\n",
+				   escape_string( p, ebuf ), 0, 0 );
 	}
 
 	/*
@@ -300,6 +309,9 @@ string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
 	if ( tmpbuf != NULL ) {
 		slapi_ch_free((void**)&tmpbuf );
 	}
+	if( bigpat != NULL ) {
+		slapi_ch_free((void**)&bigpat );
+	} 
 
 	LDAPDebug( LDAP_DEBUG_FILTER, "<= string_filter_sub %d\n",
 	    rc, 0, 0 );

+ 63 - 29
ldap/servers/slapd/regex.c

@@ -43,31 +43,6 @@
 #include "slap.h"	/* must come before regex.h */
 #include "portable.h"
 
-static PRLock	*regex_mutex = NULL;
-
-int
-slapd_re_init( void )
-{
-	if ( NULL == regex_mutex ) {
-		regex_mutex = PR_NewLock();
-	}
-	return( NULL == regex_mutex ? -1 : 0 );
-}
-
-void
-slapd_re_lock( void )
-{
-	PR_ASSERT( NULL != regex_mutex );
-	PR_Lock( regex_mutex );
-}
-
-int
-slapd_re_unlock( void )
-{
-	PR_ASSERT( NULL != regex_mutex );
-	return( PR_Unlock( regex_mutex ) );
-}
-
 #if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
 #include "regex.h"
 
@@ -91,6 +66,13 @@ slapd_re_unlock( void )
  * Modification history:
  *
  * $Log: regex.c,v $
+ * Revision 1.6  2008/04/29 00:38:36  nhosoi
+ * Resolves: #182621 (#443955)
+ * Summary: Allow larger regex buffer to enable long substring filters
+ * Description: Applying the patches provided by [email protected].
+ * regex.c: use dynamically allocated regex buffer, use ptrdiff_t to store the offsets to be restored after the realloc, and use a constant for the value of "how much the NFA buffer can grow in one iteration on the pattern".
+ * string.c: use dynamically allocated buffer if the prepared buffer is not large enough, used wrong pointer (pat instead of p) in a debug message, and performed an unneeded strcat of ".*"
+ *
  * Revision 1.5  2006/11/10 23:45:40  nhosoi
  * Resolves: #214533
  * Summary: configure needs to support --with-fhs (Comment #6)
@@ -416,6 +398,12 @@ slapd_re_unlock( void )
  *	matches:	foo-foo fo-fo fob-fob foobar-foobar ...
  */
 
+/* This is the maximum the NFA buffer might grow for every op code processed.
+   The max seems to be the + after a character class, like "[a-z]+".  It
+   needs 1 byte for the CCL code, 16 for the CCL bit map, and 2 for END codes
+   and 1 for a CLO code. */
+#define MAXOPSPACE 20
+
 #define MAXNFA  1024
 #define MAXTAG  10
 
@@ -454,11 +442,12 @@ typedef unsigned char UCHAR;
  */
 
 static int  tagstk[MAXTAG];             /* subpat tag stack..*/
-static UCHAR nfa[MAXNFA];		/* automaton..       */
-static int  sta = NOP;               	/* status of lastpat */
+static UCHAR *nfa = NULL;               /* automaton..       */
+static int  nfasize = MAXNFA;           /* tracks size of nfa buffer */
+static int  sta = NOP;                  /* status of lastpat */
 
-static UCHAR bittab[BITBLK];		/* bit table for CCL */
-					/* pre-set bits...   */
+static UCHAR bittab[BITBLK];            /* bit table for CCL */
+                                        /* pre-set bits...   */
 static UCHAR bitarr[] = {1,2,4,8,16,32,64,128};
 
 #ifdef DEBUG
@@ -498,6 +487,21 @@ slapd_re_comp( char *pat )
 	sta = NOP;
 
 	for (p = (UCHAR*)pat; *p; p++) {
+		/* Check if we are approaching end of nfa buffer. MAXOPSPACE is
+		   the max we might add to the nfa per loop. */
+		if (mp - (UCHAR*)nfa + MAXOPSPACE >= nfasize) {
+			/* Save offsets */
+			ptrdiff_t mppos = mp - nfa;
+			ptrdiff_t sppos = sp - nfa;
+
+			/* Double the nfa buffer size */
+			nfasize *= 2;
+			nfa = (UCHAR*)slapi_ch_realloc((char*)nfa, nfasize);
+
+			/* Restore pointers into realloced space */
+			mp = nfa + mppos;
+			sp = nfa + sppos;
+		}
 		lp = mp;
 		switch(*p) {
 
@@ -1099,3 +1103,33 @@ nfadump( UCHAR *ap)
 }
 #endif
 #endif /* MACOS or DOS or NEED_BSDREGEX */
+
+static PRLock	*regex_mutex = NULL;
+
+int
+slapd_re_init( void )
+{
+	if ( NULL == regex_mutex ) {
+		regex_mutex = PR_NewLock();
+	}
+
+	if ( NULL == nfa ) {
+		nfa = (UCHAR*)slapi_ch_malloc( MAXNFA );
+	}
+
+	return( NULL == regex_mutex ? -1 : 0 );
+}
+
+void
+slapd_re_lock( void )
+{
+	PR_ASSERT( NULL != regex_mutex );
+	PR_Lock( regex_mutex );
+}
+
+int
+slapd_re_unlock( void )
+{
+	PR_ASSERT( NULL != regex_mutex );
+	return( PR_Unlock( regex_mutex ) );
+}