Fix buffer overflows in pg_trgm due to lower-casing

The code made a subtle assumption that the lower-cased version of a
string never has more characters than the original. That is not always
true. For example, in a database with the latin9 encoding:

    latin9db=# select lower(U&'\00CC' COLLATE "lt-x-icu");
       lower
    -----------
     i\x1A\x1A
    (1 row)

In this example, lower-casing expands the single input character into
three characters.

The generate_trgm_only() function relied on that assumption in two
ways:

- It used "slen * pg_database_encoding_max_length() + 4" to allocate
  the buffer to hold the lowercased and blank-padded string. That
  formula accounts for expansion if the lower-case characters are
  longer (in bytes) than the originals, but it's still not enough if
  the lower-cased string contains more *characters* than the original.

- Its callers sized the output array to hold the trigrams extracted
  from the input string with the formula "(slen / 2 + 1) * 3", where
  'slen' is the input string length in bytes. (The formula was
  generous to account for the possibility that RPADDING was set to 2.)
  That's also not enough if one input byte can turn into multiple
  characters.

To fix, introduce a growable trigram array and give up on trying to
choose the correct max buffer sizes ahead of time.

Backpatch to v18, but no further. In previous versions lower-casing was
done character by character, and thus the assumption that lower-casing
doesn't change the character length was valid. That was changed in v18,
commit fb1a18810f.

Security: CVE-2026-2007
Reviewed-by: Noah Misch <[email protected]>
Reviewed-by: Jeff Davis <[email protected]>

Branch
------
REL_18_STABLE

Details
-------
https://git.postgresql.org/pg/commitdiff/e0965fb1a8550716db08e2183560be3546851647
Author: Heikki Linnakangas <[email protected]>

Modified Files
--------------
contrib/pg_trgm/trgm_op.c        | 275 ++++++++++++++++++++++++++-------------
src/tools/pgindent/typedefs.list |   1 +
2 files changed, 185 insertions(+), 91 deletions(-)

Reply via email to