List:Commits« Previous MessageNext Message »
From:Dmitry Shulga Date:January 19 2011 5:10pm
Subject:bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514) Bug#58026
View as plain text  
#At file:///Users/shulga/projects/mysql/5.1-bugteam-bug58026/ based on revid:davi.arnaut@stripped

 3514 Dmitry Shulga	2011-01-19
      Fixed bug#58026 - massive recursion and crash in regular expression
      handling.
      
      The problem was that parsing of nested regular expression involved
      recursive calls. Such recursion didn't take into account the amount of
      available stack space, which ended up leading to stack overflow crashes.
     @ mysql-test/t/not_embedded_server.test
        Added test for bug#58026
     @ regex/my_regex.h
        added pointer to function as last argument of my_regex_init() for check
        enough memory in stack.
     @ regex/regcomp.c
        p_ere() was modified: added call to function for check enough memory
        in stack. Function for check available stack space specified by
        global variable my_regex_enough_mem_in_stack. This variable set to
        NULL for embedded mysqld and to a pointer to function
        check_enough_stack_size otherwise.
     @ regex/reginit.c
        my_regex_init was modified: pass a pointer to a function for check
        enough memory in stack space. Reset this pointer to NULL in my_regex_end.
     @ sql/mysqld.cc
        Added function check_enough_stack_size() for check enough memory in stack.
        Passed this function as second argument to my_regex_init. For embedded 
        mysqld passed NULL as second argument.

    modified:
      mysql-test/r/not_embedded_server.result
      mysql-test/t/not_embedded_server.test
      regex/my_regex.h
      regex/regcomp.c
      regex/reginit.c
      sql/mysqld.cc
=== modified file 'mysql-test/r/not_embedded_server.result'
--- a/mysql-test/r/not_embedded_server.result	2009-04-30 10:29:19 +0000
+++ b/mysql-test/r/not_embedded_server.result	2011-01-19 17:10:47 +0000
@@ -4,3 +4,7 @@ select 1;
 SHOW VARIABLES like 'slave_skip_errors';
 Variable_name	Value
 slave_skip_errors	OFF
+#
+# Bug#58026: massive recursion and crash in regular expression handling
+#
+SELECT '1' RLIKE RPAD('1', 10000, '(');

=== modified file 'mysql-test/t/not_embedded_server.test'
--- a/mysql-test/t/not_embedded_server.test	2009-04-30 10:29:19 +0000
+++ b/mysql-test/t/not_embedded_server.test	2011-01-19 17:10:47 +0000
@@ -42,4 +42,14 @@ select 1;
 
 SHOW VARIABLES like 'slave_skip_errors';
 
+--echo #
+--echo # Bug#58026: massive recursion and crash in regular expression handling
+--echo #
+
+--disable_result_log
+--error ER_STACK_OVERRUN_NEED_MORE
+SELECT '1' RLIKE RPAD('1', 10000, '(');
+--enable_result_log
+
+
 # End of 5.1 tests

=== modified file 'regex/my_regex.h'
--- a/regex/my_regex.h	2005-09-29 00:08:24 +0000
+++ b/regex/my_regex.h	2011-01-19 17:10:47 +0000
@@ -28,6 +28,7 @@ typedef struct {
 
 
 /* === regcomp.c === */
+typedef int (*my_regex_stack_check_t)();
 extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset);
 #define	REG_BASIC	0000
 #define	REG_EXTENDED	0001
@@ -76,7 +77,8 @@ extern void my_regfree(my_regex_t *);
 
 /* === reginit.c === */
 
-extern void my_regex_init(CHARSET_INFO *cs);	/* Should be called for multithread progs */
+/* Should be called for multithread progs */
+extern void my_regex_init(CHARSET_INFO *cs,  my_regex_stack_check_t func);
 extern void my_regex_end(void);	/* If one wants a clean end */
 
 #ifdef __cplusplus

=== modified file 'regex/regcomp.c'
--- a/regex/regcomp.c	2010-07-09 19:37:52 +0000
+++ b/regex/regcomp.c	2011-01-19 17:10:47 +0000
@@ -31,6 +31,9 @@ struct parse {
 	CHARSET_INFO *charset;	/* for ctype things  */
 };
 
+/* Check if there is enough stack space for recursion. */
+my_regex_stack_check_t my_regex_enough_mem_in_stack= NULL;
+
 #include "regcomp.ih"
 
 static char nuls[10];		/* place to point scanner in event of error */
@@ -117,7 +120,7 @@ CHARSET_INFO *charset;
 #	define	GOODFLAGS(f)	((f)&~REG_DUMP)
 #endif
 
-	my_regex_init(charset);	/* Init cclass if neaded */
+	my_regex_init(charset, NULL);	/* Init class if needed */
 	preg->charset=charset;
 	cflags = GOODFLAGS(cflags);
 	if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
@@ -221,8 +224,15 @@ int stop;			/* character this ERE should
 	for (;;) {
 		/* do a bunch of concatenated expressions */
 		conc = HERE();
-		while (MORE() && (c = PEEK()) != '|' && c != stop)
-			p_ere_exp(p);
+		while (MORE() && (c = PEEK()) != '|' && c != stop) {
+		  if (my_regex_enough_mem_in_stack &&
+		      my_regex_enough_mem_in_stack())
+		  {
+		    SETERROR(REG_ESPACE);
+		    return;
+		  }
+		  p_ere_exp(p);
+		}
 		if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */
 
 		if (!EAT('|'))

=== modified file 'regex/reginit.c'
--- a/regex/reginit.c	2008-02-18 22:29:39 +0000
+++ b/regex/reginit.c	2011-01-19 17:10:47 +0000
@@ -4,10 +4,12 @@
 #include <m_ctype.h>
 #include <m_string.h>
 #include "cclass.h"
+#include "my_regex.h"
 
 static my_bool regex_inited=0;
+extern my_regex_stack_check_t my_regex_enough_mem_in_stack;
 
-void my_regex_init(CHARSET_INFO *cs)
+void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func)
 {
   char buff[CCLASS_LAST][256];
   int  count[CCLASS_LAST];
@@ -16,6 +18,7 @@ void my_regex_init(CHARSET_INFO *cs)
   if (!regex_inited)
   {
     regex_inited=1;
+    my_regex_enough_mem_in_stack= func;
     bzero((uchar*) &count,sizeof(count));
 
     for (i=1 ; i<= 255; i++)
@@ -74,6 +77,7 @@ void my_regex_end()
     int i;
     for (i=0; i < CCLASS_LAST ; i++)
       free((char*) cclasses[i].chars);
+    my_regex_enough_mem_in_stack= NULL;
     regex_inited=0;
   }
 }

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2010-11-09 14:45:13 +0000
+++ b/sql/mysqld.cc	2011-01-19 17:10:47 +0000
@@ -3032,6 +3032,20 @@ sizeof(load_default_groups)/sizeof(load_
 #endif
 
 
+#ifndef EMBEDDED_LIBRARY
+extern "C"
+int
+check_enough_stack_size()
+{
+  uchar stack_top;
+
+  return check_stack_overrun(current_thd, STACK_MIN_SIZE,
+                             &stack_top);
+  return 0;
+}
+#endif
+
+
 /**
   Initialize one of the global date/time format variables.
 
@@ -3412,7 +3426,11 @@ static int init_common_variables(const c
 #endif
   mysys_uses_curses=0;
 #ifdef USE_REGEX
-  my_regex_init(&my_charset_latin1);
+#ifndef EMBEDDED_LIBRARY
+  my_regex_init(&my_charset_latin1, check_enough_stack_size);
+#else
+  my_regex_init(&my_charset_latin1, NULL);
+#endif
 #endif
   /*
     Process a comma-separated character set list and choose


Attachment: [text/bzr-bundle] bzr/dmitry.shulga@oracle.com-20110119171047-j2fdszywuoyw7i1b.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514) Bug#58026Dmitry Shulga19 Jan
  • Re: bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514)Bug#58026Davi Arnaut20 Jan