about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Pluzhnikov <ppluzhnikov@google.com>2015-03-06 09:13:16 -0800
committerPaul Pluzhnikov <ppluzhnikov@google.com>2015-03-06 09:13:16 -0800
commit895c30cb003857b52c1675f9078e6a799b231bcb (patch)
tree5efa6be9373ca6e1d8dafe195aa639c19060e494
parent5df56c7e3a236b39b3395e042015b541172f652b (diff)
downloadglibc-895c30cb003857b52c1675f9078e6a799b231bcb.tar.gz
glibc-895c30cb003857b52c1675f9078e6a799b231bcb.tar.xz
glibc-895c30cb003857b52c1675f9078e6a799b231bcb.zip
Fix BZ #18043: buffer-overflow (read past the end) in wordexp/parse_dollars/parse_param
-rw-r--r--ChangeLog6
-rw-r--r--NEWS2
-rw-r--r--posix/wordexp-test.c31
-rw-r--r--posix/wordexp.c2
4 files changed, 39 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 0eb779d91f..da0b76943a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-03-06  Paul Pluzhnikov  <ppluzhnikov@google.com>
+
+	[BZ #18043]
+	* posix/wordexp.c (parse_param): Fix buffer overflow.
+	* posix/wordexp-test.c (do_bz18043): Add test case.
+
 2015-03-06  Vincent Bernat  <vincent@bernat.im>
 
 	* time/tst-strptime2.c (do_test): Ensure failing tests are
diff --git a/NEWS b/NEWS
index 1f98e58da2..b4df84900f 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,7 @@ Version 2.22
   16560, 16783, 17269, 17523, 17569, 17588, 17631, 17711, 17776, 17779,
   17792, 17836, 17912, 17916, 17932, 17944, 17949, 17964, 17965, 17967,
   17969, 17978, 17987, 17991, 17996, 17998, 17999, 18019, 18020, 18029,
-  18030, 18032, 18036, 18038, 18039, 18046, 18047.
+  18030, 18032, 18036, 18038, 18039, 18043, 18046, 18047.
 
 * Character encoding and ctype tables were updated to Unicode 7.0.0, using
   new generator scripts contributed by Pravin Satpute and Mike FABIAN (Red
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index 8a312e0bcd..137044e95f 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,33 @@ 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;
+  if (wordexp (word_start, &w, 0) != WRDE_SYNTAX)
+    return 3;
+
+  if (munmap (start, 2 * pagesize) != 0)
+    return 4;
+
+  return 0;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -370,6 +398,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 e3d8d6bd0d..1c144014b3 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;