gboolean rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache, const char *path, gboolean silent, gboolean try_load) { g_assert (cache != NULL); g_assert (path != NULL); #ifndef WITH_HYPERSCAN return FALSE; #else gint fd, n, ret; guchar magicbuf[RSPAMD_HS_MAGIC_LEN]; const guchar *mb; GHashTableIter it; gpointer k, v; struct rspamd_re_class *re_class; 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); if (len < sizeof (rspamd_cryptobox_HASHBYTES + 3)) { return FALSE; } if (memcmp (path + len - 3, ".hs", 3) != 0) { return FALSE; } hash_pos = path + len - 3 - (sizeof (re_class->hash) - 1); g_hash_table_iter_init (&it, cache->re_classes); while (g_hash_table_iter_next (&it, &k, &v)) { re_class = v; if (memcmp (hash_pos, re_class->hash, sizeof (re_class->hash) - 1) == 0) { /* Open file and check magic */ fd = open (path, O_RDONLY); if (fd == -1) { if (!silent) { msg_err_re_cache ("cannot open hyperscan cache file %s: %s", path, strerror (errno)); } return FALSE; } if (read (fd, magicbuf, sizeof (magicbuf)) != sizeof (magicbuf)) { msg_err_re_cache ("cannot read hyperscan cache file %s: %s", path, strerror (errno)); close (fd); return FALSE; } if (cache->vectorized_hyperscan) { mb = rspamd_hs_magic_vector; } else { mb = rspamd_hs_magic; } if (memcmp (magicbuf, mb, sizeof (magicbuf)) != 0) { msg_err_re_cache ("cannot open hyperscan cache file %s: " "bad magic ('%*xs', '%*xs' expected)", path, (int) RSPAMD_HS_MAGIC_LEN, magicbuf, (int) RSPAMD_HS_MAGIC_LEN, mb); close (fd); return FALSE; } if (read (fd, &test_plt, sizeof (test_plt)) != sizeof (test_plt)) { msg_err_re_cache ("cannot read hyperscan cache file %s: %s", path, strerror (errno)); close (fd); return FALSE; } if (memcmp (&test_plt, &cache->plt, sizeof (test_plt)) != 0) { msg_err_re_cache ("cannot open hyperscan cache file %s: " "compiled for a different platform", path); close (fd); return FALSE; } 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; } } if (!silent) { msg_warn_re_cache ("unknown hyperscan cache file %s", path); } return FALSE; #endif }
gboolean rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache, const char *path, gboolean silent) { g_assert (cache != NULL); g_assert (path != NULL); #ifndef WITH_HYPERSCAN return FALSE; #else gint fd; guchar magicbuf[RSPAMD_HS_MAGIC_LEN]; GHashTableIter it; gpointer k, v; struct rspamd_re_class *re_class; gsize len; const gchar *hash_pos; hs_platform_info_t test_plt; len = strlen (path); if (len < sizeof (rspamd_cryptobox_HASHBYTES + 3)) { return FALSE; } if (memcmp (path + len - 3, ".hs", 3) != 0) { return FALSE; } hash_pos = path + len - 3 - (sizeof (re_class->hash) - 1); g_hash_table_iter_init (&it, cache->re_classes); while (g_hash_table_iter_next (&it, &k, &v)) { re_class = v; if (memcmp (hash_pos, re_class->hash, sizeof (re_class->hash) - 1) == 0) { /* Open file and check magic */ fd = open (path, O_RDONLY); if (fd == -1) { if (!silent) { msg_err_re_cache ("cannot open hyperscan cache file %s: %s", path, strerror (errno)); } return FALSE; } if (read (fd, magicbuf, sizeof (magicbuf)) != sizeof (magicbuf)) { msg_err_re_cache ("cannot read hyperscan cache file %s: %s", path, strerror (errno)); close (fd); return FALSE; } if (memcmp (magicbuf, rspamd_hs_magic, sizeof (magicbuf)) != 0) { msg_err_re_cache ("cannot open hyperscan cache file %s: " "bad magic ('%*xs', '%*xs' expected)", path, (int) RSPAMD_HS_MAGIC_LEN, magicbuf, (int) RSPAMD_HS_MAGIC_LEN, rspamd_hs_magic); close (fd); return FALSE; } if (read (fd, &test_plt, sizeof (test_plt)) != sizeof (test_plt)) { msg_err_re_cache ("cannot read hyperscan cache file %s: %s", path, strerror (errno)); close (fd); return FALSE; } if (memcmp (&test_plt, &cache->plt, sizeof (test_plt)) != 0) { msg_err_re_cache ("cannot open hyperscan cache file %s: " "compiled for a different platform", path); close (fd); return FALSE; } /* XXX: add crc check */ close (fd); return TRUE; } } if (!silent) { msg_warn_re_cache ("unknown hyperscan cache file %s", path); } return FALSE; #endif }