From 9e6eb057ed468ebec1432ee8e818388e2e56e60e Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 9 Aug 2016 17:35:45 +0100 Subject: [PATCH] [CritFix] Check hyperscan cache sanity before loading When regexp database is changed it is possible that hyperscan cache will contain some invalid or shifted regexps IDs. In this situation, Rspamd could not correctly detect that such an event occurred and loaded an incorrect database. This commit adds strict crc checking that includes: 1. HS ids 2. HS flags 3. HS serialized blob If this crc fails to match then Rspamd recompiles the corrupted cache file. --- src/libserver/re_cache.c | 42 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/libserver/re_cache.c b/src/libserver/re_cache.c index b9b1b5e8c..07c637224 100644 --- a/src/libserver/re_cache.c +++ b/src/libserver/re_cache.c @@ -1321,6 +1321,7 @@ rspamd_re_cache_compile_hyperscan (struct rspamd_re_cache *cache, gchar path[PATH_MAX], npath[PATH_MAX]; hs_database_t *test_db; gint fd, i, n, *hs_ids = NULL, pcre_flags, re_flags; + rspamd_cryptobox_fast_hash_state_t crc_st; guint64 crc; rspamd_regexp_t *re; hs_compile_error_t *hs_errors; @@ -1509,8 +1510,15 @@ rspamd_re_cache_compile_hyperscan (struct rspamd_re_cache *cache, * crc - 8 bytes checksum * */ - crc = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, - hs_serialized, serialized_len, 0xdeadbabe); + rspamd_cryptobox_fast_hash_init (&crc_st, 0xdeadbabe); + /* IDs -> Flags -> Hs blob */ + rspamd_cryptobox_fast_hash_update (&crc_st, + hs_ids, sizeof (*hs_ids) * n); + rspamd_cryptobox_fast_hash_update (&crc_st, + hs_flags, sizeof (*hs_flags) * n); + rspamd_cryptobox_fast_hash_update (&crc_st, + hs_serialized, serialized_len); + crc = rspamd_cryptobox_fast_hash_final (&crc_st); if (cache->vectorized_hyperscan) { iov[0].iov_base = (void *) rspamd_hs_magic_vector; @@ -1618,6 +1626,8 @@ rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache, hs_platform_info_t test_plt; hs_database_t *test_db = NULL; guchar *map, *p, *end; + rspamd_cryptobox_fast_hash_state_t crc_st; + guint64 crc, valid_crc; len = strlen (path); @@ -1715,7 +1725,35 @@ rspamd_re_cache_is_valid_hyperscan_file (struct rspamd_re_cache *cache, return FALSE; } + /* + * Magic - 8 bytes + * Platform - sizeof (platform) + * n - number of regexps + * n * + * n * + * crc - 8 bytes checksum + * + */ + + memcpy (&crc, p + n * 2 * sizeof (gint), sizeof (crc)); + rspamd_cryptobox_fast_hash_init (&crc_st, 0xdeadbabe); + /* IDs */ + rspamd_cryptobox_fast_hash_update (&crc_st, p, n * sizeof (gint)); + /* Flags */ + rspamd_cryptobox_fast_hash_update (&crc_st, p + n * sizeof (gint), + n * sizeof (gint)); + /* HS database */ p += n * sizeof (gint) * 2 + sizeof (guint64); + rspamd_cryptobox_fast_hash_update (&crc_st, p, end - p); + valid_crc = rspamd_cryptobox_fast_hash_final (&crc_st); + + if (crc != valid_crc) { + msg_warn_re_cache ("outdated or invalid hs database in %s: " + "crc read %xL, crc expected %xL", path, crc, valid_crc); + munmap (map, len); + + return FALSE; + } if ((ret = hs_deserialize_database (p, end - p, &test_db)) != HS_SUCCESS) { -- 2.39.5