commit 29d138d26f3a4c65d0916892371ca1af26102b79 Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 12:41:12 2010 -0800 regexec.c: avoid overflow in realloc buffer length computation (cherry picked from commit aef699dce14a56ff0f212f533e5ea485d3cec96a) commit a8e15c34fcef7eac14b431f0d0aa79162180b423 Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 12:33:58 2010 -0800 regexec.c: avoid leaks on out-of-memory failure paths (cherry picked from commit 74bc9f14db655d2fdc9018d396af326e9b9bdf3f) commit f13891f2e60093d435a14f09a3ed60090d156e25 Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 12:22:18 2010 -0800 regexec.c: avoid overflow in computing sum of lengths (cherry picked from commit 42a2c9b5c3c92f7e2f556d7bc9dc80e557484574) commit ce4929787c15c85a000e432b82d02dd0f45a21fa Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 12:15:53 2010 -0800 re_search_internal: Avoid overflow in computing re_malloc buffer size (cherry picked from commit eadc09f22cd81dd0153fba0fd8514261ea9b4196) commit 815460ad9b99f6e7cb65b0d8285973abd23de3b1 Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 12:03:56 2010 -0800 prune_impossible_nodes: Avoid overflow in computing re_malloc buffer size (cherry picked from commit 4cd028677b55c8be454bb06f0b28a8b41beffe9b) commit 6b6e4661ec78d763dcad0b059e29b03b0abd2cb4 Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 10:52:38 2010 -0800 regexec.c: avoid arithmetic overflow in buffer size calculation (cherry picked from commit daa8454919de6c4e8b914c5d45276abd20baab08) commit 9a395a890e199fa29cb7a9f9d5cb62caa3e20332 Author: Paul Eggert <eggert@cs.ucla.edu> Date: Fri Jan 22 10:39:59 2010 -0800 regexec.c: simplify re_search_2_stub (cherry picked from commit d044d844dd011bb26317ac36da2d22ebe19621b1) commit fcadae915dc0bb6b8071857c510c7356ce8fc0ca Author: Ulrich Drepper <drepper@redhat.com> Date: Fri Jan 22 10:22:53 2010 -0800 Simplify test in re_string_skip_chars. (cherry picked from commit 5ddf954cf19d43f54ba44f487427d210952e1236) commit 78e4576784342c9c5d16dbf55789f5c332fa0379 Author: Ulrich Drepper <drepper@redhat.com> Date: Fri Jan 22 10:17:45 2010 -0800 regex_internal.c: don't assume WEOF fits in wchar_t (cherry picked from commit 4f08104cbf07d87a42c389f2af17f87c445e59d5) commit 6537ebd97f63c3aeebd954137e799d53a43bb69c Author: Ulrich Drepper <drepper@redhat.com> Date: Fri Jan 22 09:57:30 2010 -0800 regex_internal.c: remove useless variable and the code to set it. (cherry picked from commit 0dae5d4ec1740b511af97c600df1ceea37ada73d) commit b1b5d0f7786d02f49ff4569f80573b48a0240a2e Author: Ulrich Drepper <drepper@redhat.com> Date: Fri Jan 22 09:48:35 2010 -0800 Extend overflow detection in re_dfa_add_node. (cherry picked from commit 22364644882b6cf426ed13be5b6480c3a9210eb1) commit 791a72bc4bae0c29f725694d629872dba81c50e2 Author: Ulrich Drepper <drepper@redhat.com> Date: Fri Jan 22 09:33:01 2010 -0800 regex: avoid internal re_realloc overflow (adjusted cherry-pick from 54dd0ab31fe2b2168ba1a6180a0c05941fb54b3c) --- ChangeLog | 53 ++++++++++++++++++++++++++++++++++++++++++++++ posix/regex_internal.c | 34 +++++++++++++++++++---------- posix/regexec.c | 55 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 118 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 30480e2..2223015 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +2010-01-22 Jim Meyering <jim@meyering.net> + + [BZ #11193] + * posix/regexec.c (extend_buffers): Avoid overflow in realloc + buffer length computation. + + [BZ #11192] + * posix/regexec.c (re_copy_regs): Don't leak when allocation + of the start buffer succeeds but allocation of the "end" one fails. + + [BZ #11191] + * posix/regexec.c (re_search_2_stub): Check for overflow + when adding the sizes of the two strings. + + [BZ #11190] + * posix/regexec.c (re_search_internal): Avoid overflow + in computing re_malloc buffer size. + + [BZ #11189] + * posix/regexec.c (prune_impossible_nodes): Avoid overflow + in computing re_malloc buffer size. + + [BZ #11188] + * posix/regexec.c (build_trtable): Avoid arithmetic overflow + in size calculation. + + [BZ #11187] + * posix/regexec.c (re_search_2_stub): Use simpler method than + boolean for freeing internal storage. + +2010-01-22 Ulrich Drepper <drepper@redhat.com> + + * posix/regex_internal.c (re_string_skip_chars): Simplify test for + failed mbrtowc call. + +2010-01-22 Jim Meyering <jim@meyering.net> + + [BZ #11186] + * posix/regex_internal.c (re_string_skip_chars): Don't assume WEOF + fits in wchar_t. Problem reported by Eric Blake. + + [BZ #11185] + * posix/regex_internal.c (re_string_reconstruct): Remove declaration + and stores into set-but-not-used local, "q". + + [BZ #11184] + * posix/regex_internal.c (re_dfa_add_node): Extend the overflow + detection test. Patch by Paul Eggert. + + [BZ #11183] + * posix/regex_internal.c (re_string_realloc_buffers): + Detect and handle internal overflow. Patch by Paul Eggert + 2010-01-19 Ulrich Drepper <drepper@redhat.com> [BZ #11194] diff --git a/posix/regex_internal.c b/posix/regex_internal.c index ff28e5f..8183a29 100644 --- a/posix/regex_internal.c +++ b/posix/regex_internal.c @@ -133,7 +133,14 @@ re_string_realloc_buffers (re_string_t *pstr, int new_buf_len) #ifdef RE_ENABLE_I18N if (pstr->mb_cur_max > 1) { - wint_t *new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); + wint_t *new_wcs; + + /* Avoid overflow in realloc. */ + const size_t max_object_size = MAX (sizeof (wint_t), sizeof (int)); + if (BE (SIZE_MAX / max_object_size < new_buf_len, 0)) + return REG_ESPACE; + + new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len); if (BE (new_wcs == NULL, 0)) return REG_ESPACE; pstr->wcs = new_wcs; @@ -482,18 +489,18 @@ re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc) mbstate_t prev_st; int rawbuf_idx; size_t mbclen; - wchar_t wc = WEOF; + wint_t wc = WEOF; /* Skip the characters which are not necessary to check. */ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len; rawbuf_idx < new_raw_idx;) { - int remain_len; - remain_len = pstr->len - rawbuf_idx; + wchar_t wc2; + int remain_len = pstr->len - rawbuf_idx; prev_st = pstr->cur_state; - mbclen = __mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx, + mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx, remain_len, &pstr->cur_state); - if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) + if (BE ((ssize_t) mbclen <= 0, 0)) { /* We treat these cases as a single byte character. */ if (mbclen == 0 || remain_len == 0) @@ -503,10 +510,12 @@ re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc) mbclen = 1; pstr->cur_state = prev_st; } + else + wc = (wint_t) wc2; /* Then proceed the next character. */ rawbuf_idx += mbclen; } - *last_wc = (wint_t) wc; + *last_wc = wc; return rawbuf_idx; } #endif /* RE_ENABLE_I18N */ @@ -694,7 +703,7 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) if (pstr->is_utf8) { - const unsigned char *raw, *p, *q, *end; + const unsigned char *raw, *p, *end; /* Special case UTF-8. Multi-byte chars start with any byte other than 0x80 - 0xbf. */ @@ -723,13 +732,11 @@ re_string_reconstruct (re_string_t *pstr, int idx, int eflags) unsigned char buf[6]; size_t mbclen; - q = p; if (BE (pstr->trans != NULL, 0)) { int i = mlen < 6 ? mlen : 6; while (--i >= 0) buf[i] = pstr->trans[p[i]]; - q = buf; } /* XXX Don't use mbrtowc, we know which conversion to use (UTF-8 -> UCS4). */ @@ -1404,8 +1411,11 @@ re_dfa_add_node (re_dfa_t *dfa, re_token_t token) re_node_set *new_edests, *new_eclosures; re_token_t *new_nodes; - /* Avoid overflows. */ - if (BE (new_nodes_alloc < dfa->nodes_alloc, 0)) + /* Avoid overflows in realloc. */ + const size_t max_object_size = MAX (sizeof (re_token_t), + MAX (sizeof (re_node_set), + sizeof (int))); + if (BE (SIZE_MAX / max_object_size < new_nodes_alloc, 0)) return -1; new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc); diff --git a/posix/regexec.c b/posix/regexec.c index b8db740..f877016 100644 --- a/posix/regexec.c +++ b/posix/regexec.c @@ -368,16 +368,16 @@ re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, const char *str; int rval; int len = length1 + length2; - int free_str = 0; + char *s = NULL; - if (BE (length1 < 0 || length2 < 0 || stop < 0, 0)) + if (BE (length1 < 0 || length2 < 0 || stop < 0 || len < length1, 0)) return -2; /* Concatenate the strings. */ if (length2 > 0) if (length1 > 0) { - char *s = re_malloc (char, len); + s = re_malloc (char, len); if (BE (s == NULL, 0)) return -2; @@ -388,17 +388,14 @@ re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, memcpy (s + length1, string2, length2); #endif str = s; - free_str = 1; } else str = string2; else str = string1; - rval = re_search_stub (bufp, str, len, start, range, stop, regs, - ret_len); - if (free_str) - re_free ((char *) str); + rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len); + re_free (s); return rval; } @@ -512,9 +509,14 @@ re_copy_regs (regs, pmatch, nregs, regs_allocated) if (regs_allocated == REGS_UNALLOCATED) { /* No. So allocate them with malloc. */ regs->start = re_malloc (regoff_t, need_regs); - regs->end = re_malloc (regoff_t, need_regs); - if (BE (regs->start == NULL, 0) || BE (regs->end == NULL, 0)) + if (BE (regs->start == NULL, 0)) return REGS_UNALLOCATED; + regs->end = re_malloc (regoff_t, need_regs); + if (BE (regs->end == NULL, 0)) + { + re_free (regs->start); + return REGS_UNALLOCATED; + } regs->num_regs = need_regs; } else if (regs_allocated == REGS_REALLOCATE) @@ -524,9 +526,15 @@ re_copy_regs (regs, pmatch, nregs, regs_allocated) if (BE (need_regs > regs->num_regs, 0)) { regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs); - regoff_t *new_end = re_realloc (regs->end, regoff_t, need_regs); - if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0)) + regoff_t *new_end; + if (BE (new_start == NULL, 0)) return REGS_UNALLOCATED; + new_end = re_realloc (regs->end, regoff_t, need_regs); + if (BE (new_end == NULL, 0)) + { + re_free (new_start); + return REGS_UNALLOCATED; + } regs->start = new_start; regs->end = new_end; regs->num_regs = need_regs; @@ -694,6 +702,13 @@ re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, multi character collating element. */ if (nmatch > 1 || dfa->has_mb_node) { + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0)) + { + err = REG_ESPACE; + goto free_return; + } + mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1); if (BE (mctx.state_log == NULL, 0)) { @@ -952,6 +967,11 @@ prune_impossible_nodes (mctx) #endif match_last = mctx->match_last; halt_node = mctx->last_node; + + /* Avoid overflow. */ + if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0)) + return REG_ESPACE; + sifted_states = re_malloc (re_dfastate_t *, match_last + 1); if (BE (sifted_states == NULL, 0)) { @@ -3362,6 +3382,13 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) if (BE (err != REG_NOERROR, 0)) goto out_free; + /* Avoid arithmetic overflow in size calculation. */ + if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) + / (3 * sizeof (re_dfastate_t *))) + < ndests), + 0)) + goto out_free; + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX + ndests * 3 * sizeof (re_dfastate_t *))) dest_states = (re_dfastate_t **) @@ -4077,6 +4104,10 @@ extend_buffers (re_match_context_t *mctx) reg_errcode_t ret; re_string_t *pstr = &mctx->input; + /* Avoid overflow. */ + if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0)) + return REG_ESPACE; + /* Double the lengthes of the buffers. */ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); if (BE (ret != REG_NOERROR, 0))