]> granicus.if.org Git - postgresql/commitdiff
Improve ispell dictionary's defenses against bad affix files.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 23 Oct 2014 17:11:28 +0000 (13:11 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 23 Oct 2014 17:12:00 +0000 (13:12 -0400)
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.

src/backend/tsearch/spell.c

index 530c6eddb8cacf09fc9a57ab9dea698201cf647f..b32dc471aa3a5e0c5f36ac9e551d7c4c1b8c269f 100644 (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")));
-
-                       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)