List:Commits« Previous MessageNext Message »
From:Dmitry Shulga Date:November 24 2010 9:07am
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	2010-11-24
      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 was not take care of available memory,
      which may lead to stack overflow crashes.
     @ client/mysqltest.cc
        Passed NULL pointer to function as last actual argument in call
        to my_regcomp. In this case check for enough memory in stack
        doesn't occur. Such checking doesn't need in mysql clients.
     @ regex/main.c
        Passed NULL pointer to function as last actual argument in call
        to my_regcomp. In this case check for enough memory
        in stack doesn't occur. Such checking doesn't need in regex's 
        regression tests.
     @ regex/my_regex.h
        added pointer to function as last argument of my_regcomp() for check
        enough memory in stack.
     @ regex/regcomp.c
        Added pointer to function as last argument of p_ere()/p_ere_exp()
        that called in order to check that there are enough memory in stack
        for next recursion call.
     @ regex/regcomp.ih
        added pointer to function as last argument of my_regcomp() for check
        enough memory in stack.
     @ sql/item_cmpfunc.cc
        Passed pointer to function check_enough_stack_size() in call to
        my_regcomp(). The function check_enough_stack_size() will be
        called in during recursive descendant for regular expression parsing.

    modified:
      client/mysqltest.cc
      regex/main.c
      regex/my_regex.h
      regex/regcomp.c
      regex/regcomp.ih
      sql/item_cmpfunc.cc
=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc	2010-11-19 09:29:08 +0000
+++ b/client/mysqltest.cc	2010-11-24 09:07:00 +0000
@@ -7593,7 +7593,7 @@ char *re_eprint(int err)
 void init_re_comp(my_regex_t *re, const char* str)
 {
   int err= my_regcomp(re, str, (REG_EXTENDED | REG_ICASE | REG_NOSUB),
-                      &my_charset_latin1);
+                      &my_charset_latin1, NULL);
   if (err)
   {
     char erbuf[100];
@@ -9032,7 +9032,7 @@ int reg_replace(char** buf_p, int* buf_l
   if (icase)
     cflags|= REG_ICASE;
 
-  if ((err_code= my_regcomp(&r,pattern,cflags,&my_charset_latin1)))
+  if ((err_code= my_regcomp(&r,pattern,cflags,&my_charset_latin1, NULL)))
   {
     check_regerr(&r,err_code);
     return 1;

=== modified file 'regex/main.c'
--- a/regex/main.c	2010-10-19 22:36:59 +0000
+++ b/regex/main.c	2010-11-24 09:07:00 +0000
@@ -74,7 +74,8 @@ char *argv[];
 		exit(status);
 	}
 
-	err = my_regcomp(&re, argv[optind++], copts, &my_charset_latin1);
+	err = my_regcomp(&re, argv[optind++], copts, &my_charset_latin1,
+	                 NULL);
 	if (err) {
 		len = my_regerror(err, &re, erbuf, sizeof(erbuf));
 		fprintf(stderr, "error %s, %d/%d `%s'\n",
@@ -226,7 +227,7 @@ int opts;			/* may not match f1 */
 	strcpy(f0copy, f0);
 	re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
 	fixstr(f0copy);
-	err = my_regcomp(&re, f0copy, opts, &my_charset_latin1);
+	err = my_regcomp(&re, f0copy, opts, &my_charset_latin1, NULL);
 	if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
 		/* unexpected error or wrong error */
 		len = my_regerror(err, &re, erbuf, sizeof(erbuf));

=== modified file 'regex/my_regex.h'
--- a/regex/my_regex.h	2005-09-29 00:08:24 +0000
+++ b/regex/my_regex.h	2010-11-24 09:07:00 +0000
@@ -28,7 +28,8 @@ typedef struct {
 
 
 /* === regcomp.c === */
-extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset);
+extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset,
+                      int (*check_enough_mem_in_stack)());
 #define	REG_BASIC	0000
 #define	REG_EXTENDED	0001
 #define	REG_ICASE	0002

=== modified file 'regex/regcomp.c'
--- a/regex/regcomp.c	2010-07-09 19:37:52 +0000
+++ b/regex/regcomp.c	2010-11-24 09:07:00 +0000
@@ -100,11 +100,12 @@ static int never = 0;		/* for use in ass
  = #define	REG_DUMP	0200
  */
 int				/* 0 success, otherwise REG_something */
-my_regcomp(preg, pattern, cflags, charset)
+my_regcomp(preg, pattern, cflags, charset, check_enough_mem_in_stack)
 my_regex_t *preg;
 const char *pattern;
 int cflags;
 CHARSET_INFO *charset;
+int (*check_enough_mem_in_stack)();
 {
 	struct parse pa;
 	register struct re_guts *g;
@@ -174,7 +175,7 @@ CHARSET_INFO *charset;
 	EMIT(OEND, 0);
 	g->firststate = THERE();
 	if (cflags&REG_EXTENDED)
-		p_ere(p, OUT);
+		p_ere(p, OUT, check_enough_mem_in_stack);
 	else if (cflags&REG_NOSPEC)
 		p_str(p);
 	else
@@ -205,12 +206,13 @@ CHARSET_INFO *charset;
 
 /*
  - p_ere - ERE parser top level, concatenation and alternation
- == static void p_ere(register struct parse *p, int stop);
+ == static void p_ere(register struct parse *p, int stop, (int*)(check_stack_overun)());
  */
 static void
-p_ere(p, stop)
+p_ere(p, stop, check_enough_mem_in_stack)
 register struct parse *p;
 int stop;			/* character this ERE should end at */
+int (*check_enough_mem_in_stack)();
 {
 	register char c;
 	register sopno UNINIT_VAR(prevback);
@@ -221,8 +223,14 @@ 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 (check_enough_mem_in_stack &&
+		      check_enough_mem_in_stack()) {
+		    SETERROR(REG_ESPACE);
+		    return;
+		  }
+		  p_ere_exp(p, check_enough_mem_in_stack);
+		}
 		if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */
 
 		if (!EAT('|'))
@@ -254,8 +262,9 @@ int stop;			/* character this ERE should
  == static void p_ere_exp(register struct parse *p);
  */
 static void
-p_ere_exp(p)
+p_ere_exp(p,check_enough_mem_in_stack)
 register struct parse *p;
+int (*check_enough_mem_in_stack)();
 {
 	register char c;
 	register sopno pos;
@@ -277,7 +286,7 @@ register struct parse *p;
 		        p->pbegin[subno] = HERE();
 		EMIT(OLPAREN, subno);
 		if (!SEE(')'))
-			p_ere(p, ')');
+			p_ere(p, ')', check_enough_mem_in_stack);
 		if (subno < NPAREN) {
 			p->pend[subno] = HERE();
 			assert(p->pend[subno] != 0);

=== modified file 'regex/regcomp.ih'
--- a/regex/regcomp.ih	2004-10-19 22:28:42 +0000
+++ b/regex/regcomp.ih	2010-11-24 09:07:00 +0000
@@ -4,8 +4,8 @@ extern "C" {
 #endif
 
 /* === regcomp.c === */
-static void p_ere(register struct parse *p, int stop);
-static void p_ere_exp(register struct parse *p);
+static void p_ere(register struct parse *p, int stop, int (*check_enough_mem_in_stack)());
+static void p_ere_exp(register struct parse *p, int (*check_enough_mem_in_stack)());
 static void p_str(register struct parse *p);
 static void p_bre(register struct parse *p, register int end1, register int end2);
 static int p_simp_re(register struct parse *p, int starordinary);

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2010-09-09 12:48:06 +0000
+++ b/sql/item_cmpfunc.cc	2010-11-24 09:07:00 +0000
@@ -4791,6 +4791,18 @@ void Item_func_like::cleanup()
 
 #ifdef USE_REGEX
 
+extern "C"
+int
+check_enough_stack_size()
+{
+#ifndef EMBEDDED_LIBRARY    // Avoid compiler warning
+  uchar stack_top;
+#endif
+  return check_stack_overrun(current_thd, STACK_MIN_SIZE,
+                             &stack_top);
+}
+
+
 /**
   @brief Compile regular expression.
 
@@ -4834,7 +4846,8 @@ int Item_func_regex::regcomp(bool send_e
   }
 
   if ((error= my_regcomp(&preg, res->c_ptr_safe(),
-                         regex_lib_flags, regex_lib_charset)))
+                         regex_lib_flags, regex_lib_charset,
+                         check_enough_stack_size)))
   {
     if (send_error)
     {


Attachment: [text/bzr-bundle] bzr/dmitry.shulga@oracle.com-20101124090700-w1hfdjmntgzv5tuh.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514) Bug#58026Dmitry Shulga24 Nov
  • Re: bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514)Bug#58026Davi Arnaut17 Jan
    • Re: bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514) Bug#58026Dmitry Shulga18 Jan
      • Re: bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3514)Bug#58026Davi Arnaut18 Jan
        • Re: 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 Arnaut19 Jan