hs: validate cached database against current HS installation

After deserializing a cached Hyperscan database, verify that its
version, CPU features, and mode match the current Hyperscan
installation by comparing hs_database_info output against a
reference database. Reject loading incompatible caches.

Ticket: 8325
pull/14908/head
Lukas Sismis 6 months ago committed by Victor Julien
parent 0cdc77b707
commit 2e7b12dda4

@ -40,6 +40,9 @@
#define HS_CACHE_FILE_VERSION "2"
#define HS_CACHE_FILE_SUFFIX "_v" HS_CACHE_FILE_VERSION ".hs"
static SCMutex g_hs_ref_info_mutex = SCMUTEX_INITIALIZER;
static char *g_hs_ref_info = NULL;
static int16_t HSCacheConstructFPath(
const char *dir_path, const char *db_hash, char *out_path, uint16_t out_path_size)
{
@ -120,6 +123,43 @@ static void SCHSCachePatternHash(const SCHSPattern *p, SCSha256 *sha256)
SCSha256Update(sha256, (const uint8_t *)p->sids, p->sids_size * sizeof(SigIntId));
}
/**
* \brief Get the hs_database_info string for a reference BLOCK-mode database
* compiled with the current Hyperscan installation.
*
* Compiled lazily on the first call and cached. Thread-safe.
*
* \retval Pointer to info string, or NULL on failure. Do not free the ptr.
*/
static const char *HSGetReferenceDbInfo(void)
{
SCMutexLock(&g_hs_ref_info_mutex);
if (g_hs_ref_info != NULL) {
SCMutexUnlock(&g_hs_ref_info_mutex);
return g_hs_ref_info;
}
hs_database_t *ref_db = NULL;
hs_compile_error_t *compile_err = NULL;
hs_error_t err = hs_compile("Suricata suricatta is the scientific name for the meerkat",
HS_FLAG_SINGLEMATCH, HS_MODE_BLOCK, NULL, &ref_db, &compile_err);
if (err == HS_SUCCESS && ref_db != NULL) {
if (hs_database_info(ref_db, &g_hs_ref_info) != HS_SUCCESS) {
if (g_hs_ref_info)
SCFree(g_hs_ref_info);
g_hs_ref_info = NULL;
}
hs_free_database(ref_db);
}
if (compile_err != NULL) {
SCLogInfo("Failed to compile reference Hyperscan database: %s", compile_err->message);
hs_free_compile_error(compile_err);
}
SCMutexUnlock(&g_hs_ref_info_mutex);
return g_hs_ref_info;
}
int HSLoadCache(hs_database_t **hs_db, const char *hs_db_hash, const char *dirpath)
{
char hash_file_static[PATH_MAX];
@ -133,6 +173,7 @@ int HSLoadCache(hs_database_t **hs_db, const char *hs_db_hash, const char *dirpa
if (!SCPathExists(hash_file_static))
return -1;
char *db_info = NULL;
char *buffer = NULL;
size_t buffer_size;
buffer = HSReadStream(hash_file_static, &buffer_size);
@ -149,6 +190,25 @@ int HSLoadCache(hs_database_t **hs_db, const char *hs_db_hash, const char *dirpa
goto freeup;
}
// Verify the loaded database is compatible with the current Hyperscan
// If both the loaded DB and the reference DB fail to load, consider the cache.
const char *ref_info = HSGetReferenceDbInfo();
if (ref_info != NULL) {
if (hs_database_info(*hs_db, &db_info) != HS_SUCCESS || db_info == NULL) {
SCLogDebug("Failed to query info for loaded Hyperscan database %s: %s",
hash_file_static, HSErrorToStr(error));
ret = -1;
goto freeup;
}
if (strcmp(db_info, ref_info) != 0) {
SCLogDebug("Loaded Hyperscan database %s is incompatible with the current "
"Hyperscan installation and will be ignored",
hash_file_static);
ret = -1;
goto freeup;
}
}
ret = 0;
/* Touch file to update modification time so active caches are retained. */
if (SCTouchFile(hash_file_static) != 0) {
@ -156,6 +216,12 @@ int HSLoadCache(hs_database_t **hs_db, const char *hs_db_hash, const char *dirpa
}
freeup:
if (ret != 0 && *hs_db != NULL) {
hs_free_database(*hs_db);
*hs_db = NULL;
}
if (db_info)
SCFree(db_info);
SCFree(buffer);
return ret;
}
@ -470,4 +536,14 @@ void SCHSCacheStatsDeinit(void *data)
SCFree(pd_cache_stats);
}
void SCHSCacheDeinit(void)
{
SCMutexLock(&g_hs_ref_info_mutex);
if (g_hs_ref_info != NULL) {
SCFree(g_hs_ref_info);
g_hs_ref_info = NULL;
}
SCMutexUnlock(&g_hs_ref_info_mutex);
}
#endif /* BUILD_HYPERSCAN */

@ -53,6 +53,7 @@ int SCHSCachePruneEvaluate(MpmConfig *mpm_conf, HashTable *inuse_caches);
void *SCHSCacheStatsInit(void);
void SCHSCacheStatsPrint(void *data);
void SCHSCacheStatsDeinit(void *data);
void SCHSCacheDeinit(void);
#endif /* BUILD_HYPERSCAN */
#endif /* SURICATA_UTIL_MPM_HS_CACHE__H */

@ -1251,6 +1251,8 @@ void MpmHSGlobalCleanup(void)
g_db_table = NULL;
}
SCMutexUnlock(&g_db_table_mutex);
SCHSCacheDeinit();
}
/*************************************Unittests********************************/

Loading…
Cancel
Save