Validate ispell dictionaries more carefully.

Using incorrect, or just mismatched, dictionary and affix files
could result in a crash, due to failure to cross-check offsets
obtained from the file.  Add necessary validation, as well as
some Asserts for future-proofing.

Per bug #16050 from Alexander Lakhin.  Back-patch to 9.6 where the
problem was introduced.

Arthur Zakirov, per initial investigation by Tomas Vondra

Discussion: https://postgr.es/m/16050-024ae722464ab604@postgresql.org
Discussion: https://postgr.es/m/20191013012610.2p2fp3zzpoav7jzf@development
This commit is contained in:
Tom Lane 2019-11-02 16:45:32 -04:00
parent dc816e5815
commit 8af1624e3f
3 changed files with 93 additions and 3 deletions

View File

@ -458,6 +458,8 @@ IsAffixFlagInUse(IspellDict *Conf, int affix, const char *affixflag)
if (*affixflag == 0) if (*affixflag == 0)
return true; return true;
Assert(affix < Conf->nAffixData);
flagcur = Conf->AffixData[affix]; flagcur = Conf->AffixData[affix];
while (*flagcur) while (*flagcur)
@ -1160,13 +1162,17 @@ getAffixFlagSet(IspellDict *Conf, char *s)
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid affix alias \"%s\"", s))); errmsg("invalid affix alias \"%s\"", s)));
if (curaffix > 0 && curaffix <= Conf->nAffixData) if (curaffix > 0 && curaffix < Conf->nAffixData)
/* /*
* Do not subtract 1 from curaffix because empty string was added * Do not subtract 1 from curaffix because empty string was added
* in NIImportOOAffixes * in NIImportOOAffixes
*/ */
return Conf->AffixData[curaffix]; return Conf->AffixData[curaffix];
else if (curaffix > Conf->nAffixData)
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid affix alias \"%s\"", s)));
else else
return VoidString; return VoidString;
} }
@ -1561,6 +1567,8 @@ MergeAffix(IspellDict *Conf, int a1, int a2)
{ {
char **ptr; char **ptr;
Assert(a1 < Conf->nAffixData && a2 < Conf->nAffixData);
/* Do not merge affix flags if one of affix flags is empty */ /* Do not merge affix flags if one of affix flags is empty */
if (*Conf->AffixData[a1] == '\0') if (*Conf->AffixData[a1] == '\0')
return a2; return a2;
@ -1603,9 +1611,10 @@ MergeAffix(IspellDict *Conf, int a1, int a2)
static uint32 static uint32
makeCompoundFlags(IspellDict *Conf, int affix) makeCompoundFlags(IspellDict *Conf, int affix)
{ {
char *str = Conf->AffixData[affix]; Assert(affix < Conf->nAffixData);
return (getCompoundAffixFlagValue(Conf, str) & FF_COMPOUNDFLAGMASK); return (getCompoundAffixFlagValue(Conf, Conf->AffixData[affix]) &
FF_COMPOUNDFLAGMASK);
} }
/* /*
@ -1725,6 +1734,16 @@ NISortDictionary(IspellDict *Conf)
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid affix alias \"%s\"", errmsg("invalid affix alias \"%s\"",
Conf->Spell[i]->p.flag))); Conf->Spell[i]->p.flag)));
if (curaffix < 0 || curaffix >= Conf->nAffixData)
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid affix alias \"%s\"",
Conf->Spell[i]->p.flag)));
if (*end != '\0' && !t_isdigit(end) && !t_isspace(end))
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid affix alias \"%s\"",
Conf->Spell[i]->p.flag)));
} }
else else
{ {

View File

@ -413,6 +413,40 @@ SELECT ts_lexize('hunspell_num', 'footballyklubber');
{foot,ball,klubber} {foot,ball,klubber}
(1 row) (1 row)
-- Test suitability of affix and dict files
CREATE TEXT SEARCH DICTIONARY hunspell_err (
Template=ispell,
DictFile=ispell_sample,
AffFile=hunspell_sample_long
);
ERROR: invalid affix alias "GJUS"
CREATE TEXT SEARCH DICTIONARY hunspell_err (
Template=ispell,
DictFile=ispell_sample,
AffFile=hunspell_sample_num
);
ERROR: invalid affix flag "SZ\"
CREATE TEXT SEARCH DICTIONARY hunspell_invalid_1 (
Template=ispell,
DictFile=hunspell_sample_long,
AffFile=ispell_sample
);
CREATE TEXT SEARCH DICTIONARY hunspell_invalid_2 (
Template=ispell,
DictFile=hunspell_sample_long,
AffFile=hunspell_sample_num
);
CREATE TEXT SEARCH DICTIONARY hunspell_invalid_3 (
Template=ispell,
DictFile=hunspell_sample_num,
AffFile=ispell_sample
);
CREATE TEXT SEARCH DICTIONARY hunspell_err (
Template=ispell,
DictFile=hunspell_sample_num,
AffFile=hunspell_sample_long
);
ERROR: invalid affix alias "302,301,202,303"
-- Synonym dictionary -- Synonym dictionary
CREATE TEXT SEARCH DICTIONARY synonym ( CREATE TEXT SEARCH DICTIONARY synonym (
Template=synonym, Template=synonym,

View File

@ -101,6 +101,43 @@ SELECT ts_lexize('hunspell_num', 'footballklubber');
SELECT ts_lexize('hunspell_num', 'ballyklubber'); SELECT ts_lexize('hunspell_num', 'ballyklubber');
SELECT ts_lexize('hunspell_num', 'footballyklubber'); SELECT ts_lexize('hunspell_num', 'footballyklubber');
-- Test suitability of affix and dict files
CREATE TEXT SEARCH DICTIONARY hunspell_err (
Template=ispell,
DictFile=ispell_sample,
AffFile=hunspell_sample_long
);
CREATE TEXT SEARCH DICTIONARY hunspell_err (
Template=ispell,
DictFile=ispell_sample,
AffFile=hunspell_sample_num
);
CREATE TEXT SEARCH DICTIONARY hunspell_invalid_1 (
Template=ispell,
DictFile=hunspell_sample_long,
AffFile=ispell_sample
);
CREATE TEXT SEARCH DICTIONARY hunspell_invalid_2 (
Template=ispell,
DictFile=hunspell_sample_long,
AffFile=hunspell_sample_num
);
CREATE TEXT SEARCH DICTIONARY hunspell_invalid_3 (
Template=ispell,
DictFile=hunspell_sample_num,
AffFile=ispell_sample
);
CREATE TEXT SEARCH DICTIONARY hunspell_err (
Template=ispell,
DictFile=hunspell_sample_num,
AffFile=hunspell_sample_long
);
-- Synonym dictionary -- Synonym dictionary
CREATE TEXT SEARCH DICTIONARY synonym ( CREATE TEXT SEARCH DICTIONARY synonym (
Template=synonym, Template=synonym,