]> source.dussan.org Git - rspamd.git/commitdiff
Add more sanity checks when loading hyperscan cache
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 18 Feb 2016 09:57:48 +0000 (09:57 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 18 Feb 2016 09:57:48 +0000 (09:57 +0000)
src/hs_helper.c
src/libserver/re_cache.c
src/libserver/re_cache.h

index a34d1d8859a81cec3aab38da31e432c8ab7726a0..7e8f7f1c5aac9967e5d679f959fe13bb2c856511 100644 (file)
@@ -135,7 +135,7 @@ rspamd_hs_helper_cleanup_dir (struct hs_helper_ctx *ctx, gboolean forced)
                for (i = 0; i < globbuf.gl_pathc; i++) {
                        if (forced ||
                                        !rspamd_re_cache_is_valid_hyperscan_file (ctx->cfg->re_cache,
-                                               globbuf.gl_pathv[i], TRUE)) {
+                                               globbuf.gl_pathv[i], TRUE, TRUE)) {
                                if (unlink (globbuf.gl_pathv[i]) == -1) {
                                        msg_err ("cannot unlink %s: %s", globbuf.gl_pathv[i],
                                                        strerror (errno));
index a25f0d1e52a60cd14665fc87a9089e71778d8185..8ab0cd0316e2ffd6e259f9288f07845489f28f73 100644 (file)
@@ -1071,7 +1071,7 @@ rspamd_re_cache_compile_hyperscan (struct rspamd_re_cache *cache,
                rspamd_snprintf (path, sizeof (path), "%s%c%s.hs", cache_dir,
                                G_DIR_SEPARATOR, re_class->hash);
 
-               if (rspamd_re_cache_is_valid_hyperscan_file (cache, path, TRUE)) {
+               if (rspamd_re_cache_is_valid_hyperscan_file (cache, path, TRUE, TRUE)) {
 
                        fd = open (path, O_RDONLY, 00600);
 
@@ -1302,7 +1302,7 @@ rspamd_re_cache_compile_hyperscan (struct rspamd_re_cache *cache,
 
 gboolean
 rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache,
-               const char *path, gboolean silent)
+               const char *path, gboolean silent, gboolean try_load)
 {
        g_assert (cache != NULL);
        g_assert (path != NULL);
@@ -1310,7 +1310,7 @@ rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache,
 #ifndef WITH_HYPERSCAN
        return FALSE;
 #else
-       gint fd;
+       gint fd, n, ret;
        guchar magicbuf[RSPAMD_HS_MAGIC_LEN];
        GHashTableIter it;
        gpointer k, v;
@@ -1318,6 +1318,8 @@ rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache,
        gsize len;
        const gchar *hash_pos;
        hs_platform_info_t test_plt;
+       hs_database_t *test_db = NULL;
+       guchar *map, *p, *end;
 
        len = strlen (path);
 
@@ -1380,9 +1382,49 @@ rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache,
                                return FALSE;
                        }
 
-                       /* XXX: add crc check */
                        close (fd);
 
+                       if (try_load) {
+                               map = rspamd_file_xmap (path, PROT_READ, &len);
+
+                               if (map == NULL) {
+                                       msg_err_re_cache ("cannot mmap hyperscan cache file %s: "
+                                                       "%s",
+                                                       path, strerror (errno));
+                                       return FALSE;
+                               }
+
+                               p = map + RSPAMD_HS_MAGIC_LEN + sizeof (test_plt);
+                               end = map + len;
+                               n = *(gint *)p;
+                               p += sizeof (gint);
+
+                               if (n <= 0 || 2 * n * sizeof (gint) + /* IDs + flags */
+                                               sizeof (guint64) + /* crc */
+                                               RSPAMD_HS_MAGIC_LEN + /* header */
+                                               sizeof (cache->plt) > len) {
+                                       /* Some wrong amount of regexps */
+                                       msg_err_re_cache ("bad number of expressions in %s: %d",
+                                                       path, n);
+                                       munmap (map, len);
+                                       return FALSE;
+                               }
+
+                               p += n * sizeof (gint) * 2 + sizeof (guint64);
+
+                               if ((ret = hs_deserialize_database (p, end - p, &test_db))
+                                               != HS_SUCCESS) {
+                                       msg_err_re_cache ("bad hs database in %s: %d", path, ret);
+                                       munmap (map, len);
+
+                                       return FALSE;
+                               }
+
+                               hs_free_database (test_db);
+                               munmap (map, len);
+                       }
+                       /* XXX: add crc check */
+
                        return TRUE;
                }
        }
@@ -1407,7 +1449,7 @@ rspamd_re_cache_load_hyperscan (struct rspamd_re_cache *cache,
        return FALSE;
 #else
        gchar path[PATH_MAX];
-       gint fd, i, n, *hs_ids = NULL, *hs_flags = NULL, total = 0;
+       gint fd, i, n, *hs_ids = NULL, *hs_flags = NULL, total = 0, ret;
        GHashTableIter it;
        gpointer k, v;
        guint8 *map, *p, *end;
@@ -1422,7 +1464,7 @@ rspamd_re_cache_load_hyperscan (struct rspamd_re_cache *cache,
                rspamd_snprintf (path, sizeof (path), "%s%c%s.hs", cache_dir,
                                G_DIR_SEPARATOR, re_class->hash);
 
-               if (rspamd_re_cache_is_valid_hyperscan_file (cache, path, FALSE)) {
+               if (rspamd_re_cache_is_valid_hyperscan_file (cache, path, FALSE, FALSE)) {
                        msg_debug_re_cache ("load hyperscan database from '%s'",
                                        re_class->hash);
 
@@ -1484,9 +1526,9 @@ rspamd_re_cache_load_hyperscan (struct rspamd_re_cache *cache,
                        re_class->hs_scratch = NULL;
                        re_class->hs_db = NULL;
 
-                       if (hs_deserialize_database (p, end - p, &re_class->hs_db)
+                       if ((ret = hs_deserialize_database (p, end - p, &re_class->hs_db))
                                        != HS_SUCCESS) {
-                               msg_err_re_cache ("bad hs database in %s", path);
+                               msg_err_re_cache ("bad hs database in %s: %d", path, ret);
                                munmap (map, st.st_size);
                                g_free (hs_ids);
                                g_free (hs_flags);
index 5cb10ea63c249a83afe1eea2bc4e446e0388aa4b..6c7999ba1762079f65791cef8f57bd1bd4fc44bd 100644 (file)
@@ -152,7 +152,7 @@ gint rspamd_re_cache_compile_hyperscan (struct rspamd_re_cache *cache,
  * Returns TRUE if the specified file is valid hyperscan cache
  */
 gboolean rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache,
-               const char *path, gboolean silent);
+               const char *path, gboolean silent, gboolean try_load);
 
 /**
  * Loads all hyperscan regexps precompiled