diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2014-10-23 13:11:28 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2014-10-23 13:12:00 -0400 |
commit | b34d6f03dbb34027ee0ee6f1c1887ae30ec7b07d (patch) | |
tree | cd0674724debeb40b876c6c8265badb2566c70ef /src | |
parent | 2781b4bea7db357be59f9a5fd73ca1eb12ff5a79 (diff) | |
download | postgresql-b34d6f03dbb34027ee0ee6f1c1887ae30ec7b07d.tar.gz postgresql-b34d6f03dbb34027ee0ee6f1c1887ae30ec7b07d.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/tsearch/spell.c | 70 |
1 files changed, 44 insertions, 26 deletions
diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c index 530c6eddb8c..b32dc471aa3 100644 --- a/src/backend/tsearch/spell.c +++ b/src/backend/tsearch/spell.c @@ -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"))); - - 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; + /* + * 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; + 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) |