diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-08-09 17:35:45 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-08-09 17:39:41 +0100 |
commit | 9e6eb057ed468ebec1432ee8e818388e2e56e60e (patch) | |
tree | ef3ee2acf09e2a436bb8e7c25a246da672a53698 | |
parent | 36fead2e11779262c4d99efcbfde28925fbb74bf (diff) | |
download | rspamd-9e6eb057ed468ebec1432ee8e818388e2e56e60e.tar.gz rspamd-9e6eb057ed468ebec1432ee8e818388e2e56e60e.zip |
[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.
-rw-r--r-- | src/libserver/re_cache.c | 42 |
1 files 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 * <hyperscan blob> */ - 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 * <regexp ids> + * n * <regexp flags> + * crc - 8 bytes checksum + * <hyperscan blob> + */ + + 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) { |