[patch] Fix for BZ #18043 buffer-overflow (read past the end) in wordexp/parse_dollars/parse_param

Paul Pluzhnikov ppluzhnikov@gmail.com
Fri Mar 6 04:33:00 GMT 2015


On Thu, Mar 5, 2015 at 11:48 AM, Carlos O'Donell <carlos@redhat.com> wrote:

> OK to commit as long as you verified that test case fails before
> and passes afterwards on at least x86_64.

It doesn't. To make it fail I would have to mmap two pages, mprotect
the second, and place the string at the end of the first page... which
is quite a bit of code.

Must I do that? I guess if we hope to catch any regression here, I must...

Attached patch is verified to fail posix/wordexp-test with expected
SIGSEGV due to overflow before the fix, and pass after.


2015-03-05  Paul Pluzhnikov  <ppluzhnikov@google.com>

        [BZ #18043]
        * posix/wordexp.c (parse_param): Fix buffer overflow.
        * posix/wordexp-test.c (do_bz18043): Add test case.



-- 
Paul Pluzhnikov
-------------- next part --------------
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index 8a312e0..c928438 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -17,6 +17,7 @@
 
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/mman.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <pwd.h>
@@ -249,6 +250,31 @@ command_line_test (const char *words)
     printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
 }
 
+static int
+do_bz18043 (void)
+{
+  const int pagesize = getpagesize ();
+  char *start = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE,
+		      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+
+  if (start == MAP_FAILED)
+    return 1;
+
+  if (mprotect (start + pagesize, pagesize, PROT_NONE))
+    return 2;
+
+  const char word[] = "${";
+  char *word_start = start + pagesize - sizeof (word);
+  memcpy (word_start, word, sizeof (word));
+
+  wordexp_t w;
+  wordexp (word_start, &w, 0);
+
+  munmap (start, 2 * pagesize);
+
+  return 0;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -370,6 +396,9 @@ main (int argc, char *argv[])
 
   printf ("tests failed: %d\n", fail);
 
+  if (do_bz18043 ())
+    ++fail;
+
   return fail != 0;
 }
 
diff --git a/posix/wordexp.c b/posix/wordexp.c
index e3d8d6b..1c14401 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -1299,7 +1299,7 @@ parse_param (char **word, size_t *word_length, size_t *max_length,
 	}
       while (isdigit(words[++*offset]));
     }
-  else if (strchr ("*@$", words[*offset]) != NULL)
+  else if (words[*offset] != '\0' && strchr ("*@$", words[*offset]) != NULL)
     {
       /* Special parameter. */
       special = 1;


More information about the Libc-alpha mailing list