postgres.git / summary / log / commit / refs

commit    7df2aa8efeba44189dc8d763da34ce171422307e
Author:   Masahiko Sawada <msawada@postgresql.org>
Commit:   Noah Misch <noah@leadboat.com>
Date:     Mon Aug 10 13:38:04 2026 +0000

    Fix potential buffer overrun in regexp match/split functions.
    
    setup_regexp_matches() sizes the buffer used to convert matched
    substrings back from pg_wchar form at the smaller of maxlen*eml and
    the original string's byte length, on the assumption that such a
    conversion cannot produce more bytes than the string it came
    from. That assumption holds only for validly encoded input. But
    pg_mb2wchar_with_len() silently accepts bytes that are invalid in the
    database encoding, turning each such byte into one pg_wchar, and
    converting that back can take more bytes than the input did. A string
    made of such bytes therefore overruns the conversion buffer by up to
    its own length, corrupting the following memory. regexp_match(),
    regexp_matches(), regexp_split_to_table() and regexp_split_to_array()
    are all affected.
    
    Fix by dropping the tighter bound and always allocating maxlen*eml + 1
    bytes.
    
    Reported-by: Francesco Verardi <frevadiscor89@gmail.com>
    Author: Masahiko Sawada <sawada.mshk@gmail.com>
    Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
    Backpatch-through: 14
    Security: CVE-2026-14664


src/backend/utils/adt/regexp.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c index 311b9877bbb..0768b5c7389 100644 --- a/src/backend/utils/adt/regexp.c +++ b/src/backend/utils/adt/regexp.c @@ -1648,23 +1648,24 @@ setup_regexp_matches(text *orig_str, text *pattern, pg_re_flags *re_flags, if (eml > 1) { - int64 maxsiz = eml * (int64) maxlen; int conv_bufsiz; /* * Make the conversion buffer large enough for any substring of - * interest. + * interest. We can't use the original string's byte length as a + * tighter bound, because that assumes the input is validly encoded; + * but pg_mb2wchar_with_len() can accept strings that are invalid in + * the database encoding, and converting such a character back to + * multibyte form can take more bytes than it did in the input. * - * Worst case: assume we need the maximum size (maxlen*eml), but take - * advantage of the fact that the original string length in bytes is - * an upper bound on the byte length of any fetched substring (and we - * know that len+1 is safe to allocate because the varlena header is - * longer than 1 byte). + * This can't overflow, nor exceed what palloc will accept: maxlen is + * at most wide_len, which is at most orig_len, and we have already + * successfully allocated (orig_len + 1) * sizeof(pg_wchar) bytes for + * wide_str. That relies on eml being no more than sizeof(pg_wchar), + * which is true of all supported encodings. */ - if (maxsiz > orig_len) - conv_bufsiz = orig_len + 1; - else - conv_bufsiz = maxsiz + 1; /* safe since maxsiz < 2^30 */ + Assert(eml <= sizeof(pg_wchar)); + conv_bufsiz = maxlen * eml + 1; matchctx->conv_buf = palloc(conv_bufsiz); matchctx->conv_bufsiz = conv_bufsiz; [parent: 3b2238fbe9b9]