Browse Source

Add more sanity checks when loading hyperscan cache

tags/1.2.0
Vsevolod Stakhov 8 years ago
parent
commit
de42879925
3 changed files with 52 additions and 10 deletions
  1. 1
    1
      src/hs_helper.c
  2. 50
    8
      src/libserver/re_cache.c
  3. 1
    1
      src/libserver/re_cache.h

+ 1
- 1
src/hs_helper.c View File

for (i = 0; i < globbuf.gl_pathc; i++) { for (i = 0; i < globbuf.gl_pathc; i++) {
if (forced || if (forced ||
!rspamd_re_cache_is_valid_hyperscan_file (ctx->cfg->re_cache, !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) { if (unlink (globbuf.gl_pathv[i]) == -1) {
msg_err ("cannot unlink %s: %s", globbuf.gl_pathv[i], msg_err ("cannot unlink %s: %s", globbuf.gl_pathv[i],
strerror (errno)); strerror (errno));

+ 50
- 8
src/libserver/re_cache.c View File

rspamd_snprintf (path, sizeof (path), "%s%c%s.hs", cache_dir, rspamd_snprintf (path, sizeof (path), "%s%c%s.hs", cache_dir,
G_DIR_SEPARATOR, re_class->hash); 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); fd = open (path, O_RDONLY, 00600);




gboolean gboolean
rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache, 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 (cache != NULL);
g_assert (path != NULL); g_assert (path != NULL);
#ifndef WITH_HYPERSCAN #ifndef WITH_HYPERSCAN
return FALSE; return FALSE;
#else #else
gint fd;
gint fd, n, ret;
guchar magicbuf[RSPAMD_HS_MAGIC_LEN]; guchar magicbuf[RSPAMD_HS_MAGIC_LEN];
GHashTableIter it; GHashTableIter it;
gpointer k, v; gpointer k, v;
gsize len; gsize len;
const gchar *hash_pos; const gchar *hash_pos;
hs_platform_info_t test_plt; hs_platform_info_t test_plt;
hs_database_t *test_db = NULL;
guchar *map, *p, *end;


len = strlen (path); len = strlen (path);


return FALSE; return FALSE;
} }


/* XXX: add crc check */
close (fd); 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; return TRUE;
} }
} }
return FALSE; return FALSE;
#else #else
gchar path[PATH_MAX]; 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; GHashTableIter it;
gpointer k, v; gpointer k, v;
guint8 *map, *p, *end; guint8 *map, *p, *end;
rspamd_snprintf (path, sizeof (path), "%s%c%s.hs", cache_dir, rspamd_snprintf (path, sizeof (path), "%s%c%s.hs", cache_dir,
G_DIR_SEPARATOR, re_class->hash); 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'", msg_debug_re_cache ("load hyperscan database from '%s'",
re_class->hash); re_class->hash);


re_class->hs_scratch = NULL; re_class->hs_scratch = NULL;
re_class->hs_db = 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) { != 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); munmap (map, st.st_size);
g_free (hs_ids); g_free (hs_ids);
g_free (hs_flags); g_free (hs_flags);

+ 1
- 1
src/libserver/re_cache.h View File

* Returns TRUE if the specified file is valid hyperscan cache * Returns TRUE if the specified file is valid hyperscan cache
*/ */
gboolean rspamd_re_cache_is_valid_hyperscan_file (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);


/** /**
* Loads all hyperscan regexps precompiled * Loads all hyperscan regexps precompiled

Loading…
Cancel
Save