From 0122b8ef489a7488b469bbb80a04b843c307765c Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Fri, 20 Mar 2015 15:13:13 +0100
Subject: [PATCH] Avoid SIGFPE in wordexp [BZ #18100]
Check for a zero divisor and integer overflow before performing
division in arithmetic expansion.
2015-03-20 Florian Weimer <fweimer@redhat.com>
[BZ #18100]
* posix/wordexp.c (eval_expr_multdiv): Check for division by zero
and integer overflow.
* posix/wordexp-test.c (test_case): Add divide-by-zero test.
(main): Add integer overflow tests.
* manual/pattern.texi (Calling Wordexp): Document additional use
for WRDE_SYNTAX.
@@ -14,8 +14,8 @@ Version 2.22
17621, 17628, 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, 18042, 18043, 18046, 18047, 18068, 18080, 18093, 18104, 18110,
- 18111, 18128, 18138.
+ 18039, 18042, 18043, 18046, 18047, 18068, 18080, 18093, 18100, 18104,
+ 18110, 18111, 18128, 18138.
* Character encoding and ctype tables were updated to Unicode 7.0.0, using
new generator scripts contributed by Pravin Satpute and Mike FABIAN (Red
@@ -2006,7 +2006,8 @@ allocate room for.
@comment POSIX.2
@item WRDE_SYNTAX
There was a syntax error in the input string. For example, an unmatched
-quoting character is a syntax error.
+quoting character is a syntax error. This error code is also used to
+signal division by zero and overflow in arithmetic expansion.
@end table
@end deftypefun
@@ -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 */
@@ -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;
--
2.1.0