git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 0/3] Fix a segfault caused by regexec() being called on mmap()ed data

From
Jeff King <peff@peff.net>
Date
Sep 6, 2016, 18:29 UTC
Message-ID
<20160906182942.s2mlge2vg65f5sy4@sigill.intra.peff.net>
In-Reply-To
<alpine.DEB.2.20.1609061521410.129229@virtualbox>
On Tue, Sep 06, 2016 at 04:06:32PM +0200, Johannes Schindelin wrote:
Show 6 quoted lines
> > I think re_search() the correct replacement function but it's been a
> > while since I've looked into it.
> 
> The segfault I investigated happened in a call to strlen(). I see many
> calls to strlen() in compat/regex/... The one that triggers the segfault
> is in regexec(), compat/regex/regexec.c:241.

Yes, that is the important one, I think. The others are for patterns, error msgs, etc. Of course strlen() is not the only function that cares about NUL delimiters (and there might even be a "while (*p)" somewhere in the code).

I always assumed the _point_ of re_search taking a ptr/len pair was exactly to handle this case. The documentation[1] says:

   `string` is the string you want to match; it can contain newline and
   null characters. `size` is the length of that string.

Which seems pretty definitive to me (that's for re_match(), but re_search() is defined in the docs in terms of re_match()).

[1] http://www.delorie.com/gnu/docs/regex/regex_47.html
> As to re_search(): I have not been able to reason about its callees in a
> reasonable amount of time. I agree that they *should* not run over the
> buffer, but I cannot easily verify it.

Between the documentation above, and the fact that your new test passes when we switch to it (see below), I feel pretty good about it.

Show 5 quoted lines
> The bigger problem is that re_search() is defined in the __USE_GNU section
> of regex.h, and I do not think it is appropriate to universally #define
> said constant before #include'ing regex.h. So it would appear that major
> surgery would be required if we wanted to use regular expressions on
> strings that are not NUL-terminated.

We can contain this to the existing compat/regexec/regexec.c, and just provide a wrapper that is similar to regexec but takes a ptr/len pair.

Like:
diff --git a/compat/regex/regex.h b/compat/regex/regex.h
index 61c9683..b2dd0b7 100644
--- a/compat/regex/regex.h
+++ b/compat/regex/regex.h
@@ -569,6 +569,11 @@ extern int regexec (const regex_t *__restrict __preg,
 		    regmatch_t __pmatch[__restrict_arr],
 		    int __eflags);
 
+extern int regexecn (const regex_t *__restrict __preg,
+		     const char *__restrict __cstring, size_t __length,
+		     size_t __nmatch, regmatch_t __pmatch[__restrict_arr],
+		     int __eflags);
+
 extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
 			char *__restrict __errbuf, size_t __errbuf_size);
 
diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c
index eb5e1d4..8afe26b 100644
--- a/compat/regex/regexec.c
+++ b/compat/regex/regexec.c
@@ -217,15 +217,16 @@ static reg_errcode_t extend_buffers (re_match_context_t *mctx)
    We return 0 if we find a match and REG_NOMATCH if not.  */
 
 int
-regexec (
+regexecn (
 	const regex_t *__restrict preg,
 	const char *__restrict string,
+	size_t length,
 	size_t nmatch,
 	regmatch_t pmatch[],
 	int eflags)
 {
   reg_errcode_t err;
-  int start, length;
+  int start;
 
   if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
     return REG_BADPAT;
@@ -238,7 +239,7 @@ regexec (
   else
     {
       start = 0;
-      length = strlen (string);
+      /* length already passed in */
     }
 
   __libc_lock_lock (dfa->lock);
@@ -252,6 +253,17 @@ regexec (
   return err != REG_NOERROR;
 }
 
+int
+regexec (
+	const regex_t *__restrict preg,
+	const char *__restrict string,
+	size_t nmatch,
+	regmatch_t pmatch[],
+	int eflags)
+{
+  return regexecn(preg, string, strlen(string), nmatch, pmatch, eflags);
+}
+
 #ifdef _LIBC
 # include <shlib-compat.h>
 versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 55067ca..fdd08dd 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -50,9 +50,9 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
 	xdemitconf_t xecfg;
 
 	if (!one)
-		return !regexec(regexp, two->ptr, 1, &regmatch, 0);
+		return !regexecn(regexp, two->ptr, two->size, 1, &regmatch, 0);
 	if (!two)
-		return !regexec(regexp, one->ptr, 1, &regmatch, 0);
+		return !regexecn(regexp, one->ptr, one->size, 1, &regmatch, 0);
 
 	/*
 	 * We have both sides; need to run textual diff and see if
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 22 of 66 in “Fix a segfault caused by regexec() being called on mmap()ed data”
  1. 0/3 Fix a segfault caused by regexec() being called on mmap()ed dataJohannes Schindelin, Sep 5, 2016
  2. 2/3 diff_populate_filespec: NUL-terminate buffersJohannes Schindelin, Sep 5, 2016
  3. Jeff KingSep 6, 2016
  4. Johannes SchindelinSep 6, 2016
  5. Jeff KingSep 6, 2016
  6. Junio C HamanoSep 7, 2016
  7. Johannes SchindelinSep 8, 2016
  8. Johannes SchindelinSep 8, 2016
  9. Jeff KingSep 8, 2016
  10. Junio C HamanoSep 8, 2016
  11. Johannes SchindelinSep 8, 2016
  12. Jeff KingSep 8, 2016
  13. 3/3 diff_grep: add assertions verifying that the buffers are NUL-terminatedJohannes Schindelin, Sep 5, 2016
  14. Jeff KingSep 6, 2016
  15. Johannes SchindelinSep 6, 2016
  16. 1/3 Demonstrate a problem: our pickaxe code assumes NUL-terminated buffersJohannes Schindelin, Sep 5, 2016
  17. Jeff KingSep 6, 2016
  18. Johannes SchindelinSep 8, 2016
  19. Junio C HamanoSep 5, 2016
  20. Jeff KingSep 6, 2016
  21. Johannes SchindelinSep 6, 2016
  22. Jeff KingSep 6, 2016
  23. Johannes SchindelinSep 8, 2016
  24. Jeff KingSep 8, 2016
  25. Johannes SchindelinSep 9, 2016
  26. Junio C HamanoSep 9, 2016
  27. Johannes SchindelinSep 6, 2016
  28. Jeff KingSep 6, 2016
  29. Johannes SchindelinSep 6, 2016
  30. 0/3 Fix a segfault caused by regexec() being called on mmap()ed dataJohannes Schindelin, Sep 8, 2016
  31. 1/3 Demonstrate a problem: our pickaxe code assumes NUL-terminated buffersJohannes Schindelin, Sep 8, 2016
  32. 2/3 Introduce a function to run regexec() on non-NUL-terminated buffersJohannes Schindelin, Sep 8, 2016
  33. Jeff KingSep 8, 2016
  34. Johannes SchindelinSep 9, 2016
  35. Jeff KingSep 9, 2016
  36. 3/3 Use the newly-introduced regexec_buf() functionJohannes Schindelin, Sep 8, 2016
  37. Johannes SchindelinSep 8, 2016
  38. Jeff KingSep 8, 2016
  39. Jeff KingSep 8, 2016
  40. Jeff KingSep 8, 2016
  41. Ramsay JonesSep 8, 2016
  42. Jeff KingSep 8, 2016
  43. Junio C HamanoSep 8, 2016
  44. Johannes SchindelinSep 8, 2016
  45. Jeff KingSep 8, 2016
  46. 0/3 Fix a segfault caused by regexec() being called on mmap()ed dataJohannes Schindelin, Sep 8, 2016
  47. 1/3 Demonstrate a problem: our pickaxe code assumes NUL-terminated buffersJohannes Schindelin, Sep 8, 2016
  48. 2/3 Introduce a function to run regexec() on non-NUL-terminated buffersJohannes Schindelin, Sep 8, 2016
  49. Junio C HamanoSep 8, 2016
  50. 3/3 Use the newly-introduced regexec_buf() functionJohannes Schindelin, Sep 8, 2016
  51. Junio C HamanoSep 8, 2016
  52. Johannes SchindelinSep 9, 2016
  53. Jeff KingSep 9, 2016
  54. Johannes SchindelinSep 9, 2016
  55. Junio C HamanoSep 9, 2016
  56. 0/3 Fix a segfault caused by regexec() being called on mmap()ed dataJohannes Schindelin, Sep 21, 2016
  57. 1/3 regex: -G<pattern> feeds a non NUL-terminated string to regexec() and failsJohannes Schindelin, Sep 21, 2016
  58. 2/3 regex: add regexec_buf() that can work on a non NUL-terminated stringJohannes Schindelin, Sep 21, 2016
  59. Junio C HamanoSep 21, 2016
  60. Johannes SchindelinSep 22, 2016
  61. 3/3 regex: use regexec_buf()Johannes Schindelin, Sep 21, 2016
  62. Junio C HamanoSep 21, 2016
  63. Junio C HamanoSep 21, 2016
  64. Jeff KingSep 21, 2016
  65. Johannes SchindelinSep 25, 2016
  66. Jeff KingSep 21, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.