Skip to content

Commit 299498d

Browse files
committed
Fix possible buffer overrun in contrib/pg_trgm.
Allow for the possibility that folding a string to lower case makes it longer (due to replacing a character with a longer multibyte character). This doesn't change the number of trigrams that will be extracted, but it does affect the required size of an intermediate buffer in generate_trgm(). Per bug #8821 from Ufuk Kayserilioglu. Also install some checks that the input string length is not so large as to cause overflow in the calculations of palloc request sizes. Back-patch to all supported versions.
1 parent f6d6b42 commit 299498d

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

contrib/pg_trgm/trgm_op.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "catalog/pg_type.h"
1111
#include "tsearch/ts_locale.h"
12+
#include "utils/memutils.h"
1213

1314

1415
PG_MODULE_MAGIC;
@@ -191,6 +192,18 @@ generate_trgm(char *str, int slen)
191192
char *bword,
192193
*eword;
193194

195+
/*
196+
* Guard against possible overflow in the palloc requests below. (We
197+
* don't worry about the additive constants, since palloc can detect
198+
* requests that are a little above MaxAllocSize --- we just need to
199+
* prevent integer overflow in the multiplications.)
200+
*/
201+
if ((Size) (slen / 2) >= (MaxAllocSize / (sizeof(trgm) * 3)) ||
202+
(Size) slen >= (MaxAllocSize / pg_database_encoding_max_length()))
203+
ereport(ERROR,
204+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
205+
errmsg("out of memory")));
206+
194207
trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
195208
trg->flag = ARRKEY;
196209
SET_VARSIZE(trg, TRGMHDRSIZE);
@@ -200,7 +213,8 @@ generate_trgm(char *str, int slen)
200213

201214
tptr = GETARR(trg);
202215

203-
buf = palloc(sizeof(char) * (slen + 4));
216+
/* Allocate a buffer for case-folded, blank-padded words */
217+
buf = (char *) palloc(slen * pg_database_encoding_max_length() + 4);
204218

205219
if (LPADDING > 0)
206220
{
@@ -224,6 +238,7 @@ generate_trgm(char *str, int slen)
224238
#ifdef IGNORECASE
225239
pfree(bword);
226240
#endif
241+
227242
buf[LPADDING + bytelen] = ' ';
228243
buf[LPADDING + bytelen + 1] = ' ';
229244

@@ -239,7 +254,10 @@ generate_trgm(char *str, int slen)
239254
if ((len = tptr - GETARR(trg)) == 0)
240255
return trg;
241256

242-
if (len > 0)
257+
/*
258+
* Make trigrams unique.
259+
*/
260+
if (len > 1)
243261
{
244262
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
245263
len = unique_array(GETARR(trg), len);
@@ -422,6 +440,18 @@ generate_wildcard_trgm(const char *str, int slen)
422440
bytelen;
423441
const char *eword;
424442

443+
/*
444+
* Guard against possible overflow in the palloc requests below. (We
445+
* don't worry about the additive constants, since palloc can detect
446+
* requests that are a little above MaxAllocSize --- we just need to
447+
* prevent integer overflow in the multiplications.)
448+
*/
449+
if ((Size) (slen / 2) >= (MaxAllocSize / (sizeof(trgm) * 3)) ||
450+
(Size) slen >= (MaxAllocSize / pg_database_encoding_max_length()))
451+
ereport(ERROR,
452+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
453+
errmsg("out of memory")));
454+
425455
trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
426456
trg->flag = ARRKEY;
427457
SET_VARSIZE(trg, TRGMHDRSIZE);
@@ -431,6 +461,7 @@ generate_wildcard_trgm(const char *str, int slen)
431461

432462
tptr = GETARR(trg);
433463

464+
/* Allocate a buffer for blank-padded, but not yet case-folded, words */
434465
buf = palloc(sizeof(char) * (slen + 4));
435466

436467
/*
@@ -451,6 +482,7 @@ generate_wildcard_trgm(const char *str, int slen)
451482
* count trigrams
452483
*/
453484
tptr = make_trigrams(tptr, buf2, bytelen, charlen);
485+
454486
#ifdef IGNORECASE
455487
pfree(buf2);
456488
#endif
@@ -464,7 +496,7 @@ generate_wildcard_trgm(const char *str, int slen)
464496
/*
465497
* Make trigrams unique.
466498
*/
467-
if (len > 0)
499+
if (len > 1)
468500
{
469501
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
470502
len = unique_array(GETARR(trg), len);

0 commit comments

Comments
 (0)