Skip to content

Commit fc27b40

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 5143dfd commit fc27b40

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
#include "utils/array.h"
1314

1415

@@ -192,6 +193,18 @@ generate_trgm(char *str, int slen)
192193
char *bword,
193194
*eword;
194195

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

202215
tptr = GETARR(trg);
203216

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

206220
if (LPADDING > 0)
207221
{
@@ -225,6 +239,7 @@ generate_trgm(char *str, int slen)
225239
#ifdef IGNORECASE
226240
pfree(bword);
227241
#endif
242+
228243
buf[LPADDING + bytelen] = ' ';
229244
buf[LPADDING + bytelen + 1] = ' ';
230245

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

243-
if (len > 0)
258+
/*
259+
* Make trigrams unique.
260+
*/
261+
if (len > 1)
244262
{
245263
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
246264
len = unique_array(GETARR(trg), len);
@@ -423,6 +441,18 @@ generate_wildcard_trgm(const char *str, int slen)
423441
bytelen;
424442
const char *eword;
425443

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

433463
tptr = GETARR(trg);
434464

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

437468
/*
@@ -452,6 +483,7 @@ generate_wildcard_trgm(const char *str, int slen)
452483
* count trigrams
453484
*/
454485
tptr = make_trigrams(tptr, buf2, bytelen, charlen);
486+
455487
#ifdef IGNORECASE
456488
pfree(buf2);
457489
#endif
@@ -465,7 +497,7 @@ generate_wildcard_trgm(const char *str, int slen)
465497
/*
466498
* Make trigrams unique.
467499
*/
468-
if (len > 0)
500+
if (len > 1)
469501
{
470502
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
471503
len = unique_array(GETARR(trg), len);

0 commit comments

Comments
 (0)