Improve ispell dictionary's defenses against bad affix files.

Don't crash if an ispell dictionary definition contains flags but not
any compound affixes.  (This isn't a security issue since only superusers
can install affix files, but still it's a bad thing.)

Also, be more careful about detecting whether an affix-file FLAG command
is old-format (ispell) or new-format (myspell/hunspell).  And change the
error message about mixed old-format and new-format commands into something
intelligible.

Per bug #11770 from Emre Hasegeli.  Back-patch to all supported branches.
This commit is contained in:
Tom Lane 2014-10-23 13:11:28 -04:00
parent 2781b4bea7
commit b34d6f03db
1 changed files with 44 additions and 26 deletions

View File

@ -599,6 +599,9 @@ addFlagValue(IspellDict *Conf, char *s, uint32 val)
Conf->usecompound = true;
}
/*
* Import an affix file that follows MySpell or Hunspell format
*/
static void
NIImportOOAffixes(IspellDict *Conf, const char *filename)
{
@ -757,6 +760,10 @@ nextline:
* import affixes
*
* Note caller must already have applied get_tsearch_config_filename
*
* This function is responsible for parsing ispell ("old format") affix files.
* If we realize that the file contains new-format commands, we pass off the
* work to NIImportOOAffixes(), which will re-read the whole file.
*/
void
NIImportAffixes(IspellDict *Conf, const char *filename)
@ -833,13 +840,6 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
while (*s && t_isspace(s))
s += pg_mblen(s);
oldformat = true;
/* allow only single-encoded flags */
if (pg_mblen(s) != 1)
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multibyte flag character is not allowed")));
if (*s == '*')
{
@ -855,26 +855,30 @@ NIImportAffixes(IspellDict *Conf, const char *filename)
if (*s == '\\')
s++;
/* allow only single-encoded flags */
if (pg_mblen(s) != 1)
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multibyte flag character is not allowed")));
/*
* An old-format flag is a single ASCII character; we expect it to
* be followed by EOL, whitespace, or ':'. Otherwise this is a
* new-format flag command.
*/
if (*s && pg_mblen(s) == 1)
{
flag = *(unsigned char *) s;
s++;
if (*s == '\0' || *s == '#' || *s == '\n' || *s == ':' ||
t_isspace(s))
{
oldformat = true;
goto nextline;
}
}
goto isnewformat;
}
if (STRNCMP(recoded, "COMPOUNDFLAG") == 0 ||
STRNCMP(recoded, "COMPOUNDMIN") == 0 ||
STRNCMP(recoded, "PFX") == 0 ||
STRNCMP(recoded, "SFX") == 0)
goto isnewformat;
flag = *(unsigned char *) s;
goto nextline;
}
if (STRNCMP(recoded, "COMPOUNDFLAG") == 0 || STRNCMP(recoded, "COMPOUNDMIN") == 0 ||
STRNCMP(recoded, "PFX") == 0 || STRNCMP(recoded, "SFX") == 0)
{
if (oldformat)
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("wrong affix file format for flag")));
tsearch_readline_end(&trst);
NIImportOOAffixes(Conf, filename);
return;
}
if ((!suffixes) && (!prefixes))
goto nextline;
@ -888,6 +892,16 @@ nextline:
pfree(pstr);
}
tsearch_readline_end(&trst);
return;
isnewformat:
if (oldformat)
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("affix file contains both old-style and new-style commands")));
tsearch_readline_end(&trst);
NIImportOOAffixes(Conf, filename);
}
static int
@ -1501,6 +1515,10 @@ CheckCompoundAffixes(CMPDAffix **ptr, char *word, int len, bool CheckInPlace)
{
bool issuffix;
/* in case CompoundAffix is null: */
if (*ptr == NULL)
return -1;
if (CheckInPlace)
{
while ((*ptr)->affix)