summary refs log tree commit diff
path: root/posix
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2015-03-23 16:12:38 +0100
committerFlorian Weimer <fweimer@redhat.com>2015-03-23 16:12:38 +0100
commit2b028564f14d20cdda0c00d8ba100695b40501f5 (patch)
tree46699eeec32449e0894c69d8d39c30c39e6d1c63 /posix
parent59261ad3eb345e0d7b9f5c73e1a09d046991cea5 (diff)
downloadglibc-2b028564f14d20cdda0c00d8ba100695b40501f5.tar.gz
glibc-2b028564f14d20cdda0c00d8ba100695b40501f5.tar.xz
glibc-2b028564f14d20cdda0c00d8ba100695b40501f5.zip
Avoid SIGFPE in wordexp [BZ #18100]
Check for a zero divisor and integer overflow before performing
division in arithmetic expansion.
Diffstat (limited to 'posix')
-rw-r--r--posix/wordexp-test.c40
-rw-r--r--posix/wordexp.c4
2 files changed, 44 insertions, 0 deletions
diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c
index 0a353a45c3..73f1b7d3ca 100644
--- a/posix/wordexp-test.c
+++ b/posix/wordexp-test.c
@@ -237,6 +237,7 @@ struct test_case_struct
     { WRDE_SYNTAX, NULL, "`\\", 0, 0, { NULL, }, IFS },     /* BZ 18042  */
     { WRDE_SYNTAX, NULL, "${", 0, 0, { NULL, }, IFS },      /* BZ 18043  */
     { WRDE_SYNTAX, NULL, "L${a:", 0, 0, { NULL, }, IFS },   /* BZ 18043#c4  */
+    { WRDE_SYNTAX, NULL, "$[1/0]", WRDE_NOCMD, 0, {NULL, }, IFS }, /* BZ 18100 */
 
     { -1, NULL, NULL, 0, 0, { NULL, }, IFS },
   };
@@ -362,6 +363,45 @@ main (int argc, char *argv[])
 	++fail;
     }
 
+  /* Integer overflow in division.  */
+  {
+    static const char *const numbers[] = {
+      "0",
+      "1",
+      "65536",
+      "2147483648",
+      "4294967296"
+      "9223372036854775808",
+      "18446744073709551616",
+      "170141183460469231731687303715884105728",
+      "340282366920938463463374607431768211456",
+      NULL
+    };
+
+    for (const char *const *num = numbers; *num; ++num)
+      {
+	wordexp_t p;
+	char pattern[256];
+	snprintf (pattern, sizeof (pattern), "$[(-%s)/(-1)]", *num);
+	int ret = wordexp (pattern, &p, WRDE_NOCMD);
+	if (ret == 0)
+	  {
+	    if (p.we_wordc != 1 || strcmp (p.we_wordv[0], *num) != 0)
+	      {
+		printf ("Integer overflow for \"%s\" failed", pattern);
+		++fail;
+	      }
+	    wordfree (&p);
+	  }
+	else if (ret != WRDE_SYNTAX)
+	  {
+	    printf ("Integer overflow for \"%s\" failed with %d",
+		    pattern, ret);
+	    ++fail;
+	  }
+      }
+  }
+
   puts ("tests completed, now cleaning up");
 
   /* Clean up */
diff --git a/posix/wordexp.c b/posix/wordexp.c
index f6062d58c8..e711d43355 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -617,6 +617,10 @@ eval_expr_multdiv (char **expr, long int *result)
 	  if (eval_expr_val (expr, &arg) != 0)
 	    return WRDE_SYNTAX;
 
+	  /* Division by zero or integer overflow.  */
+	  if (arg == 0 || (arg == -1 && *result == LONG_MIN))
+	    return WRDE_SYNTAX;
+
 	  *result /= arg;
 	}
       else break;