aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-01-13 13:07:20 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2014-01-13 13:07:20 -0500
commitfc27b406817f303e38fbc86d857cead2a5116668 (patch)
tree5393ec692f5c8c23f377c5646709825254ee9080
parent5143dfd5713299048c556d69f93bf17108693db9 (diff)
downloadpostgresql-fc27b406817f303e38fbc86d857cead2a5116668.tar.gz
postgresql-fc27b406817f303e38fbc86d857cead2a5116668.zip
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.
-rw-r--r--contrib/pg_trgm/trgm_op.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/contrib/pg_trgm/trgm_op.c b/contrib/pg_trgm/trgm_op.c
index 8cd28c55e3e..73895f60d15 100644
--- a/contrib/pg_trgm/trgm_op.c
+++ b/contrib/pg_trgm/trgm_op.c
@@ -9,6 +9,7 @@
#include "catalog/pg_type.h"
#include "tsearch/ts_locale.h"
+#include "utils/memutils.h"
#include "utils/array.h"
@@ -192,6 +193,18 @@ generate_trgm(char *str, int slen)
char *bword,
*eword;
+ /*
+ * Guard against possible overflow in the palloc requests below. (We
+ * don't worry about the additive constants, since palloc can detect
+ * requests that are a little above MaxAllocSize --- we just need to
+ * prevent integer overflow in the multiplications.)
+ */
+ if ((Size) (slen / 2) >= (MaxAllocSize / (sizeof(trgm) * 3)) ||
+ (Size) slen >= (MaxAllocSize / pg_database_encoding_max_length()))
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("out of memory")));
+
trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
trg->flag = ARRKEY;
SET_VARSIZE(trg, TRGMHDRSIZE);
@@ -201,7 +214,8 @@ generate_trgm(char *str, int slen)
tptr = GETARR(trg);
- buf = palloc(sizeof(char) * (slen + 4));
+ /* Allocate a buffer for case-folded, blank-padded words */
+ buf = (char *) palloc(slen * pg_database_encoding_max_length() + 4);
if (LPADDING > 0)
{
@@ -225,6 +239,7 @@ generate_trgm(char *str, int slen)
#ifdef IGNORECASE
pfree(bword);
#endif
+
buf[LPADDING + bytelen] = ' ';
buf[LPADDING + bytelen + 1] = ' ';
@@ -240,7 +255,10 @@ generate_trgm(char *str, int slen)
if ((len = tptr - GETARR(trg)) == 0)
return trg;
- if (len > 0)
+ /*
+ * Make trigrams unique.
+ */
+ if (len > 1)
{
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
len = unique_array(GETARR(trg), len);
@@ -423,6 +441,18 @@ generate_wildcard_trgm(const char *str, int slen)
bytelen;
const char *eword;
+ /*
+ * Guard against possible overflow in the palloc requests below. (We
+ * don't worry about the additive constants, since palloc can detect
+ * requests that are a little above MaxAllocSize --- we just need to
+ * prevent integer overflow in the multiplications.)
+ */
+ if ((Size) (slen / 2) >= (MaxAllocSize / (sizeof(trgm) * 3)) ||
+ (Size) slen >= (MaxAllocSize / pg_database_encoding_max_length()))
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("out of memory")));
+
trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) *3);
trg->flag = ARRKEY;
SET_VARSIZE(trg, TRGMHDRSIZE);
@@ -432,6 +462,7 @@ generate_wildcard_trgm(const char *str, int slen)
tptr = GETARR(trg);
+ /* Allocate a buffer for blank-padded, but not yet case-folded, words */
buf = palloc(sizeof(char) * (slen + 4));
/*
@@ -452,6 +483,7 @@ generate_wildcard_trgm(const char *str, int slen)
* count trigrams
*/
tptr = make_trigrams(tptr, buf2, bytelen, charlen);
+
#ifdef IGNORECASE
pfree(buf2);
#endif
@@ -465,7 +497,7 @@ generate_wildcard_trgm(const char *str, int slen)
/*
* Make trigrams unique.
*/
- if (len > 0)
+ if (len > 1)
{
qsort((void *) GETARR(trg), len, sizeof(trgm), comp_trgm);
len = unique_array(GETARR(trg), len);