diff options
author | Florian Weimer <fweimer@redhat.com> | 2015-03-23 16:12:38 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2015-03-23 16:12:38 +0100 |
commit | 2b028564f14d20cdda0c00d8ba100695b40501f5 (patch) | |
tree | 46699eeec32449e0894c69d8d39c30c39e6d1c63 /posix | |
parent | 59261ad3eb345e0d7b9f5c73e1a09d046991cea5 (diff) | |
download | glibc-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.c | 40 | ||||
-rw-r--r-- | posix/wordexp.c | 4 |
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; |