diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 48c86c9b7680..6fd9ed501831 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -517,7 +517,7 @@ jobs: matrix: container: - almalinux:9 - - fedora:42 + - fedora:44 env: skip: true steps: @@ -568,11 +568,11 @@ jobs: # We need a step for each RPM upload as we can't use the # container name directly in an artifact, as artifacts can't # have ':' in the name. - - if: ${{ matrix.container == 'fedora:42' && env.skip != 'true' }} + - if: ${{ matrix.container == 'fedora:44' && env.skip != 'true' }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 name: Uploading RPMs with: - name: rpms-fedora-40 + name: rpms-fedora-44 path: suricata-rpms/devel/rpms - if: ${{ matrix.container == 'almalinux:9' && env.skip != 'true' }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 @@ -769,10 +769,10 @@ jobs: - run: make clean - run: make -j ${{ env.CPUS }} - fedora-42-sv-codecov: - name: Fedora 42 (Suricata Verify codecov) + fedora-44-sv-codecov: + name: Fedora 44 (Suricata Verify codecov) runs-on: ubuntu-latest - container: fedora:42 + container: fedora:44 needs: [prepare-deps, prepare-cbindgen] steps: @@ -865,10 +865,10 @@ jobs: flags: suricata-verify # Fedora build using Clang. - fedora-42-clang: - name: Fedora 42 (clang, debug, asan, wshadow, rust-strict, systemd) + fedora-44-clang: + name: Fedora 44 (clang, debug, asan, wshadow, rust-strict, systemd) runs-on: ubuntu-latest - container: fedora:42 + container: fedora:44 needs: [prepare-deps, prepare-cbindgen] steps: @@ -966,10 +966,10 @@ jobs: - run: src/suricata --build-info | grep -E "Systemd support:\s+yes" &> /dev/null # Fedora build using GCC. - fedora-42-gcc: - name: Fedora 42 (gcc, debug, flto, asan, wshadow, rust-strict) + fedora-44-gcc: + name: Fedora 44 (gcc, debug, flto, asan, wshadow, rust-strict) runs-on: ubuntu-latest - container: fedora:42 + container: fedora:44 needs: [prepare-deps, prepare-cbindgen] steps: @@ -1066,7 +1066,7 @@ jobs: fedora-non-root: name: Fedora (non-root, debug, clang, asan, wshadow, rust-strict, no-ja) runs-on: ubuntu-latest - container: fedora:42 + container: fedora:44 needs: [prepare-deps, prepare-cbindgen] steps: - name: Determine number of CPUs diff --git a/doc/userguide/firewall/firewall-design.rst b/doc/userguide/firewall/firewall-design.rst index 8ac8e757d3e0..6d04b18eb7c0 100644 --- a/doc/userguide/firewall/firewall-design.rst +++ b/doc/userguide/firewall/firewall-design.rst @@ -327,35 +327,47 @@ of :ref:`engine analysis`. Default policies ================ -Each hook has a default policy. By default ``packet.filter`` enforces a ``drop:packet`` policy and the -``app`` hooks apply ``drop:flow``. +Each hook has a default policy applied to traffic that no firewall rule handled. +By default ``packet.filter`` enforces ``drop:packet``, ``packet.pre-flow`` and +``packet.pre-stream`` enforce ``accept:hook``, and every ``app`` hook enforces +``drop:flow``. -The policies can be configured in ``firewall`` block in the config. Packet hooks -live under ``packet`` and app-layer hooks under ``app``, keyed by protocol. - -Example for ``packet.filter``, to use reject instead of drop:: +Defaults are configured in the ``firewall.policies`` block. A ``default-policy`` +for any hook may be given at several levels and the most specific present +setting wins:: firewall: policies: + default-policy: ["accept:hook"] # global fallback (all hooks) packet: - filter: [ "reject:packet" ] - - -Example for DNS:: - - firewall: - policies: + default-policy: ["drop:packet"] # fallback for packet hooks + filter: ["reject:packet"] + pre-flow: ["accept:hook"] + pre-stream: ["accept:hook"] app: + default-policy: ["drop:flow"] # fallback for all app hooks dns: + default-policy: ["drop:flow"] # fallback for dns hooks request-started: ["accept:hook"] - # Drop and alert on all DNS requests that are not allowed in # firewall.rules. request-complete: ["drop:flow", "alert"] - # Accept all responses. response-started: ["accept:tx"] +Precedence: + +* packet hook: ``packet.`` > ``packet.default-policy`` > + ``policies.default-policy`` > built-in (``drop:packet`` or ``accept:hook``) +* app hook: ``app..`` > ``app..default-policy`` > + ``app.default-policy`` > ``policies.default-policy`` > built-in (``drop:flow``) + +An action scope must be valid for the hook it is applied to. For example, +defining ``accept:tx`` as a global default policy will fail to start Suricata, +because ``packet`` policies do not accept ``tx``. +Cover such hooks with a more specific setting so the incompatible default never +reaches them. + ARP handling in bridge mode --------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index 2fd06cb2b79b..b2ab7a274611 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1059,6 +1059,7 @@ libsuricata_c_a_SOURCES = \ thread-callbacks.c \ thread-storage.c \ threads.c \ + threadvars.c \ tm-modules.c \ tm-queuehandlers.c \ tm-queues.c \ diff --git a/src/detect-engine-analyzer.c b/src/detect-engine-analyzer.c index 742e34f02696..3746afd6d7ac 100644 --- a/src/detect-engine-analyzer.c +++ b/src/detect-engine-analyzer.c @@ -2110,11 +2110,8 @@ int FirewallAnalyzer(const DetectEngineCtx *de_ctx) const char *name = AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOSERVER); if (name == NULL) { - if (state == 0) - name = "request-started"; - else if (state == complete_state_ts) - name = "request-complete"; - else + name = DetectFirewallAppGenericHookName(state, complete_state_ts, STREAM_TOSERVER); + if (name == NULL) name = "unknown"; } @@ -2136,11 +2133,8 @@ int FirewallAnalyzer(const DetectEngineCtx *de_ctx) const char *name = AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOCLIENT); if (name == NULL) { - if (state == 0) - name = "response-started"; - else if (state == complete_state_tc) - name = "response-complete"; - else + name = DetectFirewallAppGenericHookName(state, complete_state_tc, STREAM_TOCLIENT); + if (name == NULL) name = "unknown"; } char table_name[128]; diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index d2049b4744b7..82271f19368c 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -55,6 +55,12 @@ #include "util-hash.h" #include "util-thash.h" #include "util-hash-lookup3.h" +#include "counters.h" +#include "util-random.h" + +#include "thread-storage.h" + +static void ThresholdCacheInit(void); struct Thresholds { THashTableContext *thash; @@ -66,6 +72,7 @@ static void ThresholdsDestroy(struct Thresholds *t); void ThresholdInit(void) { ThresholdsInit(&ctx); + ThresholdCacheInit(); } void ThresholdDestroy(void) @@ -114,14 +121,14 @@ static void ThresholdEntryFree(void *ptr) // nothing to free, base data is part of hash } -static inline uint32_t HashAddress(const Address *a) +static inline uint32_t HashAddress(const Address *a, const uint32_t seed) { uint32_t key; if (a->family == AF_INET) { - key = a->addr_data32[0]; + key = hashword(a->addr_data32, 1, seed); } else if (a->family == AF_INET6) { - key = hashword(a->addr_data32, 4, 0); + key = hashword(a->addr_data32, 4, seed); } else key = 0; @@ -141,17 +148,17 @@ static inline int CompareAddress(const Address *a, const Address *b) return 0; } -static uint32_t ThresholdEntryHash(uint32_t seed, void *ptr) +static uint32_t ThresholdEntryHash(const uint32_t seed, void *ptr) { const ThresholdEntry *e = ptr; uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), seed); switch (e->key[TRACK]) { case TRACK_BOTH: - hash += HashAddress(&e->addr2); + hash += HashAddress(&e->addr2, seed); /* fallthrough */ case TRACK_SRC: case TRACK_DST: - hash += HashAddress(&e->addr); + hash += HashAddress(&e->addr, seed); break; } return hash; @@ -250,27 +257,6 @@ typedef struct ThresholdCacheItem { RB_ENTRY(ThresholdCacheItem) rb; } ThresholdCacheItem; -static thread_local HashTable *threshold_cache_ht = NULL; - -thread_local uint64_t cache_lookup_cnt = 0; -thread_local uint64_t cache_lookup_notinit = 0; -thread_local uint64_t cache_lookup_nosupport = 0; -thread_local uint64_t cache_lookup_miss_expired = 0; -thread_local uint64_t cache_lookup_miss = 0; -thread_local uint64_t cache_lookup_hit = 0; -thread_local uint64_t cache_housekeeping_check = 0; -thread_local uint64_t cache_housekeeping_expired = 0; - -static void DumpCacheStats(void) -{ - SCLogPerf("threshold thread cache stats: cnt:%" PRIu64 " notinit:%" PRIu64 " nosupport:%" PRIu64 - " miss_expired:%" PRIu64 " miss:%" PRIu64 " hit:%" PRIu64 - ", housekeeping: checks:%" PRIu64 ", expired:%" PRIu64, - cache_lookup_cnt, cache_lookup_notinit, cache_lookup_nosupport, - cache_lookup_miss_expired, cache_lookup_miss, cache_lookup_hit, - cache_housekeeping_check, cache_housekeeping_expired); -} - /* rbtree for expiry handling */ static int ThresholdCacheTreeCompareFunc(ThresholdCacheItem *a, ThresholdCacheItem *b) @@ -285,23 +271,57 @@ static int ThresholdCacheTreeCompareFunc(ThresholdCacheItem *a, ThresholdCacheIt RB_HEAD(THRESHOLD_CACHE, ThresholdCacheItem); RB_PROTOTYPE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc); RB_GENERATE(THRESHOLD_CACHE, ThresholdCacheItem, rb, ThresholdCacheTreeCompareFunc); -thread_local struct THRESHOLD_CACHE threshold_cache_tree; -thread_local uint64_t threshold_cache_housekeeping_ts = 0; -static void ThresholdCacheExpire(SCTime_t now) +struct ThresholdCacheThreadCtx { + HashTable *ht; + struct THRESHOLD_CACHE tree; + uint64_t housekeeping_ts; + + uint64_t lookup_cnt; + uint64_t lookup_nosupport; + uint64_t lookup_miss_expired; + uint64_t lookup_miss; + uint64_t lookup_hit; + uint64_t housekeeping_check; + uint64_t housekeeping_expired; +}; + +static ThreadStorageId thread_storage_id = { .id = -1 }; + +static void DumpCacheStats(struct ThresholdCacheThreadCtx *tctx) +{ + SCLogPerf("threshold thread cache stats: cnt:%" PRIu64 " nosupport:%" PRIu64 + " miss_expired:%" PRIu64 " miss:%" PRIu64 " hit:%" PRIu64 + ", housekeeping: checks:%" PRIu64 ", expired:%" PRIu64, + tctx->lookup_cnt, tctx->lookup_nosupport, tctx->lookup_miss_expired, tctx->lookup_miss, + tctx->lookup_hit, tctx->housekeeping_check, tctx->housekeeping_expired); +} + +static inline struct ThresholdCacheThreadCtx *GetThreadCtx(DetectEngineThreadCtx *det_ctx) +{ + if (unlikely(det_ctx->tv == NULL || thread_storage_id.id < 0)) { + return NULL; + } + return ThreadGetStorageById(det_ctx->tv, thread_storage_id); +} + +static void ThresholdCacheExpire(DetectEngineThreadCtx *det_ctx, SCTime_t now) { + struct ThresholdCacheThreadCtx *tctx = GetThreadCtx(det_ctx); + if (tctx == NULL) + return; + tctx->housekeeping_ts = SCTIME_SECS(now); + ThresholdCacheItem *iter, *safe = NULL; int cnt = 0; - threshold_cache_housekeeping_ts = SCTIME_SECS(now); - - RB_FOREACH_SAFE (iter, THRESHOLD_CACHE, &threshold_cache_tree, safe) { - cache_housekeeping_check++; + RB_FOREACH_SAFE (iter, THRESHOLD_CACHE, &tctx->tree, safe) { + tctx->housekeeping_check++; if (SCTIME_CMP_LT(iter->expires_at, now)) { - THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, iter); - HashTableRemove(threshold_cache_ht, iter, 0); + THRESHOLD_CACHE_RB_REMOVE(&tctx->tree, iter); + HashTableRemove(tctx->ht, iter, 0); SCLogDebug("iter %p expired", iter); - cache_housekeeping_expired++; + tctx->housekeeping_expired++; } if (++cnt > 1) @@ -314,7 +334,8 @@ static void ThresholdCacheExpire(SCTime_t now) static uint32_t ThresholdCacheHashFunc(HashTable *ht, void *data, uint16_t datalen) { ThresholdCacheItem *e = data; - uint32_t hash = hashword(e->key, sizeof(e->key) / sizeof(uint32_t), 0) * (e->ipv + e->track); + uint32_t hash = + hashword(e->key, sizeof(e->key) / sizeof(uint32_t), ht->seed) * (e->ipv + e->track); hash = hash % ht->array_size; return hash; } @@ -334,12 +355,13 @@ static void ThresholdCacheHashFreeFunc(void *data) } /// \brief Thread local cache -static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, const uint32_t sid, - const uint32_t gid, const uint32_t rev, SCTime_t expires) +static int SetupCache(DetectEngineThreadCtx *det_ctx, const Packet *p, const int8_t track, + const int8_t retval, const uint32_t sid, const uint32_t gid, const uint32_t rev, + SCTime_t expires) { - if (!threshold_cache_ht) { - threshold_cache_ht = HashTableInit(256, ThresholdCacheHashFunc, - ThresholdCacheHashCompareFunc, ThresholdCacheHashFreeFunc); + struct ThresholdCacheThreadCtx *tctx = GetThreadCtx(det_ctx); + if (!tctx) { + return -1; } uint32_t addr; @@ -362,7 +384,7 @@ static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, .key[TC_TENANT] = p->tenant_id, .expires_at = expires, }; - ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0); + ThresholdCacheItem *found = HashTableLookup(tctx->ht, &lookup, 0); if (!found) { ThresholdCacheItem *n = SCCalloc(1, sizeof(*n)); if (n) { @@ -376,8 +398,8 @@ static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, n->key[TC_TENANT] = p->tenant_id; n->expires_at = expires; - if (HashTableAdd(threshold_cache_ht, n, 0) == 0) { - ThresholdCacheItem *r = THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, n); + if (HashTableAdd(tctx->ht, n, 0) == 0) { + ThresholdCacheItem *r = THRESHOLD_CACHE_RB_INSERT(&tctx->tree, n); DEBUG_VALIDATE_BUG_ON(r != NULL); // duplicate; should be impossible (void)r; // only used by DEBUG_VALIDATE_BUG_ON return 1; @@ -389,8 +411,8 @@ static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, found->expires_at = expires; found->retval = retval; - THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found); - THRESHOLD_CACHE_RB_INSERT(&threshold_cache_tree, found); + THRESHOLD_CACHE_RB_REMOVE(&tctx->tree, found); + THRESHOLD_CACHE_RB_INSERT(&tctx->tree, found); return 1; } } @@ -403,28 +425,28 @@ static int SetupCache(const Packet *p, const int8_t track, const int8_t retval, * \retval -4 error - unsupported tracker * \retval ret cached return code */ -static int CheckCache(const Packet *p, const int8_t track, const uint32_t sid, const uint32_t gid, - const uint32_t rev) +static int CheckCache(DetectEngineThreadCtx *det_ctx, const Packet *p, const int8_t track, + const uint32_t sid, const uint32_t gid, const uint32_t rev) { - cache_lookup_cnt++; - - if (!threshold_cache_ht) { - cache_lookup_notinit++; - return -3; // error cache initialized + struct ThresholdCacheThreadCtx *tctx = GetThreadCtx(det_ctx); + if (!tctx) { + return -3; } + tctx->lookup_cnt++; + uint32_t addr; if (track == TRACK_SRC) { addr = p->src.addr_data32[0]; } else if (track == TRACK_DST) { addr = p->dst.addr_data32[0]; } else { - cache_lookup_nosupport++; + tctx->lookup_nosupport++; return -4; // error tracker not unsupported } - if (SCTIME_SECS(p->ts) > threshold_cache_housekeeping_ts) { - ThresholdCacheExpire(p->ts); + if (SCTIME_SECS(p->ts) > tctx->housekeeping_ts) { + ThresholdCacheExpire(det_ctx, p->ts); } ThresholdCacheItem lookup = { @@ -436,29 +458,72 @@ static int CheckCache(const Packet *p, const int8_t track, const uint32_t sid, c .key[TC_REV] = rev, .key[TC_TENANT] = p->tenant_id, }; - ThresholdCacheItem *found = HashTableLookup(threshold_cache_ht, &lookup, 0); + ThresholdCacheItem *found = HashTableLookup(tctx->ht, &lookup, 0); if (found) { if (SCTIME_CMP_GT(p->ts, found->expires_at)) { - THRESHOLD_CACHE_RB_REMOVE(&threshold_cache_tree, found); - HashTableRemove(threshold_cache_ht, found, 0); - cache_lookup_miss_expired++; + THRESHOLD_CACHE_RB_REMOVE(&tctx->tree, found); + HashTableRemove(tctx->ht, found, 0); + tctx->lookup_miss_expired++; return -2; // cache miss - found but expired } - cache_lookup_hit++; + tctx->lookup_hit++; return found->retval; } - cache_lookup_miss++; + tctx->lookup_miss++; return -1; // cache miss - not found } -void ThresholdCacheThreadFree(void) +static void ThresholdCacheThreadFree(void *ptr) { - if (threshold_cache_ht) { - HashTableFree(threshold_cache_ht); - threshold_cache_ht = NULL; + if (ptr != NULL) { + struct ThresholdCacheThreadCtx *tctx = ptr; + DumpCacheStats(tctx); + HashTableFree(tctx->ht); + SCFree(tctx); + } +} + +static void ThresholdCacheInit(void) +{ +#ifdef UNITTESTS + /* many tests don't manage the thread storage correctly, so skip the cache in unittests */ + if (!(RunmodeIsUnittests())) { +#endif + /* Register thread storage. */ + thread_storage_id = ThreadStorageRegister( + "threshold_cache", sizeof(void *), NULL, ThresholdCacheThreadFree); + if (thread_storage_id.id < 0) { + FatalError("Failed to register threshold_cache thread storage"); + } +#ifdef UNITTESTS } - RB_INIT(&threshold_cache_tree); - DumpCacheStats(); +#endif +} + +int ThresholdCacheThreadInit(DetectEngineThreadCtx *det_ctx) +{ + if (thread_storage_id.id < 0) + return 0; + /* we can get called more than once per thread for MT */ + if (ThreadGetStorageById(det_ctx->tv, thread_storage_id) != NULL) + return 0; + + struct ThresholdCacheThreadCtx *tctx = SCCalloc(1, sizeof(*tctx)); + if (tctx == NULL) + return -1; + + uint32_t seed = (uint32_t)RandomGet(); + + tctx->ht = HashTableInitWithSeed(256, ThresholdCacheHashFunc, ThresholdCacheHashCompareFunc, + ThresholdCacheHashFreeFunc, seed); + if (tctx->ht == NULL) { + SCFree(tctx); + return -1; + } + + RB_INIT(&tctx->tree); + ThreadSetStorageById(det_ctx->tv, thread_storage_id, tctx); + return 0; } /** @@ -709,8 +774,8 @@ static int ThresholdSetup(const DetectThresholdData *td, ThresholdEntry *te, return 0; } -static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, const DetectThresholdData *td, - ThresholdEntry *te, +static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + const DetectThresholdData *td, ThresholdEntry *te, const Packet *p, // ts only? - cache too const uint32_t sid, const uint32_t gid, const uint32_t rev, PacketAlert *pa) { @@ -730,7 +795,7 @@ static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, const DetectThres ret = 2; if (PacketIsIPv4(p)) { - SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry); + SetupCache(det_ctx, p, td->track, (int8_t)ret, sid, gid, rev, entry); } } } else { @@ -765,7 +830,7 @@ static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, const DetectThres ret = 2; if (PacketIsIPv4(p)) { - SetupCache(p, td->track, (int8_t)ret, sid, gid, rev, entry); + SetupCache(det_ctx, p, td->track, (int8_t)ret, sid, gid, rev, entry); } } } else { @@ -855,8 +920,9 @@ static int ThresholdCheckUpdate(const DetectEngineCtx *de_ctx, const DetectThres return ret; } -static int ThresholdGetFromHash(const DetectEngineCtx *de_ctx, struct Thresholds *tctx, - const Packet *p, const Signature *s, const DetectThresholdData *td, PacketAlert *pa) +static int ThresholdGetFromHash(const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + struct Thresholds *tctx, const Packet *p, const Signature *s, const DetectThresholdData *td, + PacketAlert *pa) { /* fast track for count 1 threshold */ if (td->count == 1 && td->type == TYPE_THRESHOLD) { @@ -905,7 +971,7 @@ static int ThresholdGetFromHash(const DetectEngineCtx *de_ctx, struct Thresholds r = ThresholdSetup(td, te, p->ts, s->id, s->gid, s->rev, p->tenant_id); } else { // existing, check/update - r = ThresholdCheckUpdate(de_ctx, td, te, p, s->id, s->gid, s->rev, pa); + r = ThresholdCheckUpdate(de_ctx, det_ctx, td, te, p, s->id, s->gid, s->rev, pa); } (void)THashDecrUsecnt(res.data); @@ -920,8 +986,9 @@ static int ThresholdGetFromHash(const DetectEngineCtx *de_ctx, struct Thresholds * \retval 1 normal match * \retval 0 no match */ -static int ThresholdHandlePacketFlow(const DetectEngineCtx *de_ctx, Flow *f, Packet *p, - const DetectThresholdData *td, uint32_t sid, uint32_t gid, uint32_t rev, PacketAlert *pa) +static int ThresholdHandlePacketFlow(const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, + Flow *f, Packet *p, const DetectThresholdData *td, uint32_t sid, uint32_t gid, uint32_t rev, + PacketAlert *pa) { int ret = 0; ThresholdEntry *found = ThresholdFlowLookupEntry(f, sid, gid, rev, p->tenant_id); @@ -941,7 +1008,7 @@ static int ThresholdHandlePacketFlow(const DetectEngineCtx *de_ctx, Flow *f, Pac } } else { // existing, check/update - ret = ThresholdCheckUpdate(de_ctx, td, found, p, sid, gid, rev, pa); + ret = ThresholdCheckUpdate(de_ctx, det_ctx, td, found, p, sid, gid, rev, pa); } return ret; } @@ -972,29 +1039,30 @@ int PacketAlertThreshold(const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *d ret = ThresholdHandlePacketSuppress(p,td,s->id,s->gid); } else if (td->track == TRACK_SRC) { if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) { - int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev); + int cache_ret = CheckCache(det_ctx, p, td->track, s->id, s->gid, s->rev); if (cache_ret >= 0) { SCReturnInt(cache_ret); } } - ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa); + ret = ThresholdGetFromHash(de_ctx, det_ctx, &ctx, p, s, td, pa); } else if (td->track == TRACK_DST) { if (PacketIsIPv4(p) && (td->type == TYPE_LIMIT || td->type == TYPE_BOTH)) { - int cache_ret = CheckCache(p, td->track, s->id, s->gid, s->rev); + int cache_ret = CheckCache(det_ctx, p, td->track, s->id, s->gid, s->rev); if (cache_ret >= 0) { SCReturnInt(cache_ret); } } - ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa); + ret = ThresholdGetFromHash(de_ctx, det_ctx, &ctx, p, s, td, pa); } else if (td->track == TRACK_BOTH) { - ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa); + ret = ThresholdGetFromHash(de_ctx, det_ctx, &ctx, p, s, td, pa); } else if (td->track == TRACK_RULE) { - ret = ThresholdGetFromHash(de_ctx, &ctx, p, s, td, pa); + ret = ThresholdGetFromHash(de_ctx, det_ctx, &ctx, p, s, td, pa); } else if (td->track == TRACK_FLOW) { if (p->flow) { - ret = ThresholdHandlePacketFlow(de_ctx, p->flow, p, td, s->id, s->gid, s->rev, pa); + ret = ThresholdHandlePacketFlow( + de_ctx, det_ctx, p->flow, p, td, s->id, s->gid, s->rev, pa); } } diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index cb1b09fbbb3c..c65e8d53271f 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -39,7 +39,8 @@ int PacketAlertThreshold(const DetectEngineCtx *, DetectEngineThreadCtx *, const DetectThresholdData *, Packet *, const Signature *, PacketAlert *); void ThresholdListFree(void *ptr); -void ThresholdCacheThreadFree(void); + +int ThresholdCacheThreadInit(DetectEngineThreadCtx *); void FlowThresholdVarFree(void *ptr); diff --git a/src/detect-engine.c b/src/detect-engine.c index e9d0339a4ab0..278d697dd145 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -3478,6 +3478,8 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx * #endif SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect); + if (ThresholdCacheThreadInit(det_ctx) != 0) + return TM_ECODE_FAILED; return TM_ECODE_OK; } @@ -3734,8 +3736,6 @@ static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx) AppLayerDecoderEventsFreeEvents(&det_ctx->decoder_events); PrefilterPktNonPFStatsDump(); SCFree(det_ctx); - - ThresholdCacheThreadFree(); } TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) diff --git a/src/detect-parse.c b/src/detect-parse.c index ed399e7c5021..88af468d6206 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -109,6 +109,39 @@ typedef struct SignatureParser_ { char opts[DETECT_MAX_RULE_SIZE]; } SignatureParser; +/** Valid action scopes per firewall hook class. */ +enum DetectFirewallPolicyClass { + DETECT_FIREWALL_POLICY_CLASS_PACKET, + DETECT_FIREWALL_POLICY_CLASS_APP +}; + +static const uint8_t fw_packet_hook_scopes[] = { + ACTION_SCOPE_PACKET, + ACTION_SCOPE_HOOK, + ACTION_SCOPE_FLOW, +}; +static const uint8_t fw_app_hook_scopes[] = { + ACTION_SCOPE_FLOW, + ACTION_SCOPE_TX, + ACTION_SCOPE_HOOK, +}; + +/** \brief max length of a firewall.policies YAML config path */ +#define FW_POLICY_YAML_PATH_MAX 320 +/** \brief max length of a single YAML path leaf segment (a hook name) */ +#define FW_POLICY_YAML_PATH_NAME_MAX 64 +/** \brief max number of config paths consulted to resolve one policy */ +#define FW_POLICY_CHAIN_MAX 6 + +/** + * \brief Ordered, most-specific-first list of config paths a single policy can + * be configured at. + */ +typedef struct FirewallPolicyChain { + char path[FW_POLICY_CHAIN_MAX][FW_POLICY_YAML_PATH_MAX]; + uint8_t len; +} FirewallPolicyChain; + const char *DetectListToHumanString(int list) { #define CASE_CODE_STRING(E, S) case E: return S; break @@ -1141,6 +1174,20 @@ static bool IsBuiltIn(const char *n) return false; } +/** + * \brief Generic start/complete hook alias for an app progress state, in config + * form (hyphens), or NULL for intermediate states. + */ +const char *DetectFirewallAppGenericHookName( + const uint8_t state, const uint8_t complete_state, const int direction) +{ + if (state == 0) + return (direction == STREAM_TOSERVER) ? "request-started" : "response-started"; + if (state == complete_state) + return (direction == STREAM_TOSERVER) ? "request-complete" : "response-complete"; + return NULL; +} + /** \brief register app hooks as generic lists * * Register each hook in each app protocol as: @@ -3900,75 +3947,195 @@ static int DoParsePolicy(const char *policy_name, struct DetectFirewallPolicy *p return 1; } +static bool FirewallScopeValidForClass(uint8_t scope, enum DetectFirewallPolicyClass pol_class) +{ + const uint8_t *set = NULL; + size_t n = 0; + switch (pol_class) { + case DETECT_FIREWALL_POLICY_CLASS_PACKET: + set = fw_packet_hook_scopes; + n = ARRAY_SIZE(fw_packet_hook_scopes); + break; + case DETECT_FIREWALL_POLICY_CLASS_APP: + set = fw_app_hook_scopes; + n = ARRAY_SIZE(fw_app_hook_scopes); + break; + default: + FatalError("Invalid firewall policy class %u", (unsigned)pol_class); + } + for (size_t i = 0; i < n; i++) { + if (set[i] == scope) { + return true; + } + } + return false; +} + +/** + * \brief Render the valid scopes for a hook class to a string. + */ +static void FirewallScopeHintForClass( + enum DetectFirewallPolicyClass pol_class, char *out, size_t out_size) +{ + const uint8_t *set = NULL; + size_t n = 0; + switch (pol_class) { + case DETECT_FIREWALL_POLICY_CLASS_PACKET: + set = fw_packet_hook_scopes; + n = ARRAY_SIZE(fw_packet_hook_scopes); + break; + case DETECT_FIREWALL_POLICY_CLASS_APP: + set = fw_app_hook_scopes; + n = ARRAY_SIZE(fw_app_hook_scopes); + break; + default: + FatalError("Invalid firewall policy class %u", (unsigned)pol_class); + } + out[0] = '\0'; + for (size_t i = 0; i < n; i++) { + if ((i > 0 && strlcat(out, "/", out_size) >= out_size) || + strlcat(out, ActionScopeToString((enum ActionScope)set[i]), out_size) >= out_size) { + FatalError("firewall policy scope hint too long"); + } + } +} + +/** + * \brief Append a unique inheritance tier to the chain of firewall policies to query. + */ +static void ATTR_FMT_PRINTF(2, 3) + FirewallPolicyChainAdd(FirewallPolicyChain *chain, const char *fmt, ...) +{ + if (chain->len >= FW_POLICY_CHAIN_MAX) { + FatalError("too many firewall YAML config paths, max %u", FW_POLICY_CHAIN_MAX); + } + char *path = chain->path[chain->len]; + + va_list ap; + va_start(ap, fmt); + int r = vsnprintf(path, FW_POLICY_YAML_PATH_MAX, fmt, ap); + va_end(ap); + if (r < 0) { + FatalError("%s: firewall YAML config path formatting failed", fmt); + } + if ((size_t)r >= FW_POLICY_YAML_PATH_MAX) { + FatalError("%s: firewall YAML config path too long", path); + } + + for (uint8_t i = 0; i < chain->len; i++) { + if (strcmp(chain->path[i], path) == 0) + return; + } + chain->len++; +} + +/** + * \brief Resolve a firewall policy from its config path chain. + * + * The first path in the chain that has a policy configured wins, with its + * action scope validated against the target hook class. + * + * \retval 1 a config source was used and stored in \p out + * \retval 0 no source present, \p out is unmodified + * \retval -1 parse error, e.g. an empty policy, or invalid scope for the target class + */ + +static int ResolveFirewallPolicy(struct DetectFirewallPolicy *out, + enum DetectFirewallPolicyClass pol_class, const FirewallPolicyChain *chain) +{ + for (uint8_t i = 0; i < chain->len; i++) { + const char *path = chain->path[i]; + struct DetectFirewallPolicy tmp = { 0 }; + int r = DoParsePolicy(path, &tmp); + if (r < 0) { + return -1; + } + if (r == 1) { + if (tmp.action == 0) { + SCLogError("%s: policy is set but empty", path); + return -1; + } + if (!FirewallScopeValidForClass(tmp.action_scope, pol_class)) { + char hint[32]; // space to combine ActionScopeToString results + FirewallScopeHintForClass(pol_class, hint, sizeof(hint)); + SCLogError("%s: action scope (\"%s\") is not valid. Valid scopes: %s", path, + ActionScopeToString(tmp.action_scope), hint); + return -1; + } + *out = tmp; + return 1; + } + } + return 0; +} + +static void FirewallHookNameConvertUnderscoreToDash(const char *in, char *out, size_t out_size) +{ + if (strlcpy(out, in, out_size) >= out_size) { + FatalError("%s: firewall policy config name too long", in); + } + for (size_t i = 0; out[i] != '\0'; i++) { + if (out[i] == '_') + out[i] = '-'; + } +} + +/** + * \brief Resolve and store one app-layer hook default policy. + */ static int DoParseAppPolicy(const char *prefix, const AppProto app_proto, const char *hookname, const uint8_t state, const uint8_t complete_state, const int direction, struct DetectFirewallPolicies *fw_policies, struct DetectFirewallAppPolicy *app_fw_policies) { - char policy_name[256]; - const char *in_name = hookname; - if (hookname == NULL) { - if (state == 0) { - if (direction == STREAM_TOSERVER) - hookname = "request-started"; - else - hookname = "response-started"; - } else if (state == complete_state) { - if (direction == STREAM_TOSERVER) - hookname = "request-complete"; - else - hookname = "response-complete"; - } - if (hookname == NULL) - return 0; - } - char *nname = SCStrdup(hookname); - if (nname == NULL) + const char *app_proto_str = AppProtoToStringRaw(app_proto); + if (app_proto_str == NULL) { + SCLogError("Unknown app proto %u", (unsigned)app_proto); return -1; - for (int i = 0; nname[i] != '\0'; i++) { - if (nname[i] == '_') - nname[i] = '-'; } - const char *app_name = AppProtoToStringRaw(app_proto); - int r = snprintf(policy_name, sizeof(policy_name), "%s.app.%s.%s", prefix, app_name, nname); - SCFree(nname); - if (r < 0 || (size_t)r >= sizeof(policy_name)) { - FatalError("internal error: failed to assemble firewall policy config string"); + const char *generic_hook = DetectFirewallAppGenericHookName(state, complete_state, direction); + char hook[FW_POLICY_YAML_PATH_NAME_MAX] = ""; + if (hookname != NULL) { + FirewallHookNameConvertUnderscoreToDash(hookname, hook, sizeof(hook)); + } + + FirewallPolicyChain chain = { .len = 0 }; + if (hookname != NULL) { + /* .app.. */ + FirewallPolicyChainAdd(&chain, "%s.app.%s.%s", prefix, app_proto_str, hook); + } + if (generic_hook != NULL) { + /* .app.. */ + FirewallPolicyChainAdd(&chain, "%s.app.%s.%s", prefix, app_proto_str, generic_hook); } + /* .app..default-policy */ + FirewallPolicyChainAdd(&chain, "%s.app.%s.default-policy", prefix, app_proto_str); + /* .app.default-policy */ + FirewallPolicyChainAdd(&chain, "%s.app.default-policy", prefix); + /* .default-policy */ + FirewallPolicyChainAdd(&chain, "%s.default-policy", prefix); - struct DetectFirewallPolicy *pol; + struct DetectFirewallPolicy *app_pol; if (direction == STREAM_TOSERVER) - pol = &app_fw_policies[app_proto].ts[state]; + app_pol = &app_fw_policies[app_proto].ts[state]; else - pol = &app_fw_policies[app_proto].tc[state]; - r = DoParsePolicy(policy_name, pol); - if (r == 0 && in_name != NULL) { - if (state == 0) { - if (direction == STREAM_TOSERVER) - hookname = "request-started"; - else - hookname = "response-started"; - } else if (state == complete_state) { - if (direction == STREAM_TOSERVER) - hookname = "request-complete"; - else - hookname = "response-complete"; - } - if (hookname == NULL) - return 0; - r = snprintf(policy_name, sizeof(policy_name), "%s.app.%s.%s", prefix, app_name, hookname); - if (r < 0 || (size_t)r >= sizeof(policy_name)) { - FatalError("internal error: failed to assemble firewall policy config string"); - } + app_pol = &app_fw_policies[app_proto].tc[state]; - r = DoParsePolicy(policy_name, pol); + /* init to drop:flow by default, will be overwritten by ResolveFirewallPolicy if there + * is a config for this hook. */ + app_pol->action = ACTION_DROP; + app_pol->action_scope = ACTION_SCOPE_FLOW; + + int r = ResolveFirewallPolicy(app_pol, DETECT_FIREWALL_POLICY_CLASS_APP, &chain); + if (r < 0) { + return -1; } /* for policies with an alert action, create a policy sig */ - if (r == 1 && pol->action & ACTION_ALERT) { + if (r == 1 && app_pol->action & ACTION_ALERT) { SCLogDebug("adding policy signature"); - return AddAppPolicySignature(fw_policies->policy_signatures, direction, app_proto, app_name, - state, hookname, pol); + return AddAppPolicySignature(fw_policies->policy_signatures, direction, app_proto, + app_proto_str, state, hookname, app_pol); } return r; } @@ -4013,10 +4180,52 @@ int DetectFirewallInitDefaultPolicies(DetectEngineCtx *de_ctx) return -1; } +/** + * \brief Resolve and store one packet-hook default policy. + */ +static int DetectFirewallLoadPacketPolicy(struct DetectFirewallPolicies *fw_policies, + const char *prefix, enum DetectFirewallPacketPolicies id, const char *leaf) +{ + /* inheritance tiers, most specific first */ + FirewallPolicyChain chain = { .len = 0 }; + /* .packet. */ + FirewallPolicyChainAdd(&chain, "%s.packet.%s", prefix, leaf); + /* .packet.default-policy */ + FirewallPolicyChainAdd(&chain, "%s.packet.default-policy", prefix); + /* .default-policy */ + FirewallPolicyChainAdd(&chain, "%s.default-policy", prefix); + + struct DetectFirewallPolicy *pol = &fw_policies->pkt[id]; // built-in default + int r = ResolveFirewallPolicy(pol, DETECT_FIREWALL_POLICY_CLASS_PACKET, &chain); + if (r < 0) { + return -1; + } + if (r == 1 && (pol->action & ACTION_ALERT)) { + return AddPktPolicySignature(fw_policies, pol, id); + } + return 0; +} + +/** + * \brief Load the packet-hook default policies. + */ +static int DetectFirewallLoadPacketPolicies( + struct DetectFirewallPolicies *fw_policies, const char *prefix) +{ + if (DetectFirewallLoadPacketPolicy( + fw_policies, prefix, DETECT_FIREWALL_POLICY_PACKET_FILTER, "filter") < 0) + return -1; + if (DetectFirewallLoadPacketPolicy( + fw_policies, prefix, DETECT_FIREWALL_POLICY_PRE_FLOW, "pre-flow") < 0) + return -1; + if (DetectFirewallLoadPacketPolicy( + fw_policies, prefix, DETECT_FIREWALL_POLICY_PRE_STREAM, "pre-stream") < 0) + return -1; + return 0; +} + int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx) { - int r; - char policy_name[256]; char prefix[96] = "firewall.policies"; if (strlen(de_ctx->config_prefix) > 0) { snprintf(prefix, sizeof(prefix), "%s.firewall.policies", de_ctx->config_prefix); @@ -4029,42 +4238,8 @@ int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx) if (app_fw_policies == NULL) return -1; - r = snprintf(policy_name, sizeof(policy_name), "%s.packet.filter", prefix); - if (r < 0 || (size_t)r >= sizeof(policy_name)) { - FatalError("internal error: failed to assemble firewall policy config string"); - } - r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER]); - if (r < 0) - return -1; - if (fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER].action & ACTION_ALERT) - if (AddPktPolicySignature(fw_policies, - &fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER], - DETECT_FIREWALL_POLICY_PACKET_FILTER) < 0) - return -1; - - r = snprintf(policy_name, sizeof(policy_name), "%s.packet.pre-flow", prefix); - if (r < 0 || (size_t)r >= sizeof(policy_name)) { - FatalError("internal error: failed to assemble firewall policy config string"); - } - r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW]); - if (r < 0) + if (DetectFirewallLoadPacketPolicies(fw_policies, prefix) < 0) return -1; - if (fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW].action & ACTION_ALERT) - if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW], - DETECT_FIREWALL_POLICY_PRE_FLOW) < 0) - return -1; - - r = snprintf(policy_name, sizeof(policy_name), "%s.packet.pre-stream", prefix); - if (r < 0 || (size_t)r >= sizeof(policy_name)) { - FatalError("internal error: failed to assemble firewall policy config string"); - } - r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM]); - if (r < 0) - return -1; - if (fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM].action & ACTION_ALERT) - if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM], - DETECT_FIREWALL_POLICY_PRE_STREAM) < 0) - return -1; for (AppProto a = 0; a < g_alproto_max; a++) { if (!AppProtoIsValid(a)) @@ -4079,7 +4254,6 @@ int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx) fw_policies, app_fw_policies) < 0) return -1; } - const uint8_t complete_state_tc = (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOCLIENT); for (uint8_t state = 0; state <= complete_state_tc; state++) { diff --git a/src/detect-parse.h b/src/detect-parse.h index 53aff021d2d1..44568741f31e 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -118,6 +118,9 @@ void DetectRegisterAppLayerHookLists(void); const char *ActionScopeToString(enum ActionScope s); +const char *DetectFirewallAppGenericHookName( + const uint8_t state, const uint8_t complete_state, const int direction); + struct DetectFirewallPolicy; void DetectFirewallPolicyToString(const struct DetectFirewallPolicy *p, char *out, size_t out_size); int DetectFirewallInitDefaultPolicies(DetectEngineCtx *); diff --git a/src/detect-threshold.c b/src/detect-threshold.c index f4b381bf2ae5..f24ba4bb8b11 100644 --- a/src/detect-threshold.c +++ b/src/detect-threshold.c @@ -393,6 +393,7 @@ DetectThresholdData *DetectThresholdDataCopy(DetectThresholdData *de) #include "util-hashlist.h" #include "packet.h" #include "action-globals.h" +#include "thread-storage.h" /** * \test ThresholdTestParse01 is a test for a valid threshold options @@ -564,96 +565,87 @@ static int ThresholdTestParse08(void) static int DetectThresholdTestSig1(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit\"; content:\"A\"; " - "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); - if (s == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit\"; content:\"A\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - FAIL_IF(s->type == SIG_TYPE_IPONLY); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); if (alerts != 1) { printf("alerts %" PRIi32 ", expected 1: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 2) { printf("alerts %" PRIi32 ", expected 2: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 3) { printf("alerts %" PRIi32 ", expected 3: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 4) { printf("alerts %" PRIi32 ", expected 4: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %" PRIi32 ", expected 5: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %" PRIi32 ", expected 5: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %" PRIi32 ", expected 5: ", alerts); } - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); if (alerts != 5) { printf("alerts %" PRIi32 ", expected 5: ", alerts); } - if (alerts == 5) - result = 1; - else - printf("alerts %" PRIi32 ", expected 5: ", alerts); - - SigGroupCleanup(de_ctx); - SigCleanSignatures(de_ctx); + FAIL_IF_NOT(alerts == 5); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); -end: + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -667,70 +659,63 @@ static int DetectThresholdTestSig1(void) static int DetectThresholdTestSig2(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold\"; threshold: type " - "threshold, track by_dst, count 5, seconds 60; sid:1;)"); - if (s == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold\"; threshold: type " + "threshold, track by_dst, count 5, seconds 60; sid:1;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - if (alerts == 2) - result = 1; - else - goto cleanup; + FAIL_IF_NOT(alerts == 2); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -744,11 +729,16 @@ static int DetectThresholdTestSig2(void) static int DetectThresholdTestSig3(void) { - ThreadVars th_v; - memset(&th_v, 0, sizeof(th_v)); - + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); + + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); @@ -761,30 +751,33 @@ static int DetectThresholdTestSig3(void) SigGroupBuild(de_ctx); DetectEngineThreadCtx *det_ctx; - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1); TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 10) == 1); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + ThreadVarsFree(tv); + StorageCleanup(); ThresholdDestroy(); PASS; } @@ -800,66 +793,61 @@ static int DetectThresholdTestSig3(void) static int DetectThresholdTestSig4(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold both\"; threshold: type " - "both, track by_dst, count 2, seconds 60; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold both\"; threshold: type " + "both, track by_dst, count 2, seconds 60; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); - if (alerts == 2) - result = 1; - else - goto cleanup; + FAIL_IF_NOT(alerts == 2); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: + UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -873,166 +861,148 @@ static int DetectThresholdTestSig4(void) static int DetectThresholdTestSig5(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " - "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); - if (s == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); + FAIL_IF_NULL(s); - s = s->next = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; " - "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); - if (s == NULL) { - goto end; - } + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - if (alerts == 10) - result = 1; - else { - printf("alerts %d != 10: ", alerts); - goto cleanup; - } + FAIL_IF_NOT(alerts == 10); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); - -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } static int DetectThresholdTestSig6Ticks(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " - "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); - if (s == NULL) { - goto end; - } + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1;)"); + FAIL_IF_NULL(s); - s = s->next = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; " - "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); - if (s == NULL) { - goto end; - } + s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1000\"; " + "threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); uint64_t ticks_start = 0; uint64_t ticks_end = 0; ticks_start = UtilCpuGetTicks(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); alerts += PacketAlertCheck(p, 1000); ticks_end = UtilCpuGetTicks(); printf("test run %" PRIu64 "\n", (ticks_end - ticks_start)); - if (alerts == 10) - result = 1; - else - goto cleanup; + FAIL_IF_NOT(alerts == 10); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1040,48 +1010,45 @@ static int DetectThresholdTestSig6Ticks(void) */ static int DetectThresholdTestSig7(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; int drops = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, " - "track by_src, count 1, seconds 300; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, " + "track by_src, count 1, seconds 300; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; @@ -1089,38 +1056,31 @@ static int DetectThresholdTestSig7(void) TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - if (alerts == 1 && drops == 6) - result = 1; - else { - if (alerts != 1) - printf("alerts: %d != 1: ", alerts); - if (drops != 6) - printf("drops: %d != 6: ", drops); - goto cleanup; - } + FAIL_IF_NOT(alerts == 1 && drops == 6); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1128,48 +1088,45 @@ static int DetectThresholdTestSig7(void) */ static int DetectThresholdTestSig8(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; int drops = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, " - "track by_src, count 2, seconds 300; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (threshold: type limit, " + "track by_src, count 2, seconds 300; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; @@ -1177,38 +1134,31 @@ static int DetectThresholdTestSig8(void) TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - if (alerts == 2 && drops == 6) - result = 1; - else { - if (alerts != 1) - printf("alerts: %d != 1: ", alerts); - if (drops != 6) - printf("drops: %d != 6: ", drops); - goto cleanup; - } + FAIL_IF_NOT(alerts == 2 && drops == 6); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1216,48 +1166,45 @@ static int DetectThresholdTestSig8(void) */ static int DetectThresholdTestSig9(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; int drops = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, " - "track by_src, count 3, seconds 100; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, " + "track by_src, count 3, seconds 100; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; @@ -1265,38 +1212,31 @@ static int DetectThresholdTestSig9(void) TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - if (alerts == 2 && drops == 2) - result = 1; - else { - if (alerts != 2) - printf("alerts: %d != 2: ", alerts); - if (drops != 2) - printf("drops: %d != 2: ", drops); - goto cleanup; - } + FAIL_IF_NOT(alerts == 2 && drops == 2); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1304,48 +1244,45 @@ static int DetectThresholdTestSig9(void) */ static int DetectThresholdTestSig10(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; int drops = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, " - "track by_src, count 5, seconds 300; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (threshold: type threshold, " + "track by_src, count 5, seconds 300; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; @@ -1353,38 +1290,31 @@ static int DetectThresholdTestSig10(void) TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - if (alerts == 1 && drops == 1) - result = 1; - else { - if (alerts != 1) - printf("alerts: %d != 1: ", alerts); - if (drops != 1) - printf("drops: %d != 1: ", drops); - goto cleanup; - } + FAIL_IF_NOT(alerts == 1 && drops == 1); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1392,48 +1322,45 @@ static int DetectThresholdTestSig10(void) */ static int DetectThresholdTestSig11(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; int drops = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type both, " - "track by_src, count 3, seconds 300; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (threshold: type both, " + "track by_src, count 3, seconds 300; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; @@ -1441,38 +1368,31 @@ static int DetectThresholdTestSig11(void) TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - if (alerts == 1 && drops == 4) - result = 1; - else { - if (alerts != 1) - printf("alerts: %d != 1: ", alerts); - if (drops != 4) - printf("drops: %d != 4: ", drops); - goto cleanup; - } + FAIL_IF_NOT(alerts == 1 && drops == 4); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1480,48 +1400,45 @@ static int DetectThresholdTestSig11(void) */ static int DetectThresholdTestSig12(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; - int result = 0; int alerts = 0; int drops = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - if (de_ctx == NULL) { - goto end; - } - + FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 (threshold: type both, " - "track by_src, count 5, seconds 300; sid:10;)"); - if (s == NULL) { - goto end; - } + Signature *s = + DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (threshold: type both, " + "track by_src, count 5, seconds 300; sid:10;)"); + FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts = PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; @@ -1529,39 +1446,32 @@ static int DetectThresholdTestSig12(void) TimeSetIncrementTime(200); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 10); drops += ((PacketTestAction(p, ACTION_DROP)) ? 1 : 0); p->action = 0; - if (alerts == 1 && drops == 2) - result = 1; - else { - if (alerts != 1) - printf("alerts: %d != 1: ", alerts); - if (drops != 2) - printf("drops: %d != 2: ", drops); - goto cleanup; - } + FAIL_IF_NOT(alerts == 1 && drops == 2); -cleanup: - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); -end: UTHFreePackets(&p, 1); HostShutdown(); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); - return result; + ThreadVarsFree(tv); + PASS; } /** @@ -1575,39 +1485,40 @@ static int DetectThresholdTestSig12(void) static int DetectThresholdTestSig13(void) { - Packet *p = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int alerts = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); + + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); - memset(&th_v, 0, sizeof(th_v)); - p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + Packet *p = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " - "threshold: type limit, track by_rule, count 2, seconds 60; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_rule, count 2, seconds 60; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); /* should alert twice */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); FAIL_IF(alerts != 2); @@ -1615,21 +1526,24 @@ static int DetectThresholdTestSig13(void) TimeSetIncrementTime(70); p->ts = TimeGet(); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + SigMatchSignatures(tv, de_ctx, det_ctx, p); alerts += PacketAlertCheck(p, 1); FAIL_IF(alerts != 4); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); + ThreadVarsFree(tv); PASS; } @@ -1644,52 +1558,51 @@ static int DetectThresholdTestSig13(void) static int DetectThresholdTestSig14(void) { - Packet *p1 = NULL; - Packet *p2 = NULL; - Signature *s = NULL; - ThreadVars th_v; DetectEngineThreadCtx *det_ctx; int alerts1 = 0; int alerts2 = 0; + StorageCleanup(); + StorageInit(); ThresholdInit(); + StorageFinalize(); - memset(&th_v, 0, sizeof(th_v)); - p1 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); - p2 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "3.3.3.3", 1024, 80); + ThreadVars *tv = ThreadVarsAlloc(); + FAIL_IF_NULL(tv); + Packet *p1 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); FAIL_IF_NULL(p1); + Packet *p2 = UTHBuildPacketReal((uint8_t *)"A", 1, IPPROTO_TCP, "1.1.1.1", "3.3.3.3", 1024, 80); FAIL_IF_NULL(p2); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - de_ctx->flags |= DE_QUIET; - s = de_ctx->sig_list = - SigInit(de_ctx, "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " - "threshold: type limit, track by_both, count 2, seconds 60; sid:1;)"); + Signature *s = DetectEngineAppendSig(de_ctx, + "alert tcp any any -> any 80 (msg:\"Threshold limit sid 1\"; " + "threshold: type limit, track by_both, count 2, seconds 60; sid:1;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + DetectEngineThreadCtxInit(tv, (void *)de_ctx, (void *)&det_ctx); /* Both p1 and p2 should alert twice */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + SigMatchSignatures(tv, de_ctx, det_ctx, p1); alerts1 += PacketAlertCheck(p1, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + SigMatchSignatures(tv, de_ctx, det_ctx, p1); alerts1 += PacketAlertCheck(p1, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + SigMatchSignatures(tv, de_ctx, det_ctx, p1); alerts1 += PacketAlertCheck(p1, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + SigMatchSignatures(tv, de_ctx, det_ctx, p1); alerts1 += PacketAlertCheck(p1, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + SigMatchSignatures(tv, de_ctx, det_ctx, p2); alerts2 += PacketAlertCheck(p2, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + SigMatchSignatures(tv, de_ctx, det_ctx, p2); alerts2 += PacketAlertCheck(p2, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + SigMatchSignatures(tv, de_ctx, det_ctx, p2); alerts2 += PacketAlertCheck(p2, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + SigMatchSignatures(tv, de_ctx, det_ctx, p2); alerts2 += PacketAlertCheck(p2, 1); FAIL_IF(alerts1 != 2); @@ -1700,19 +1613,22 @@ static int DetectThresholdTestSig14(void) p2->ts = TimeGet(); /* Now they should both alert again after previous alerts expire */ - SigMatchSignatures(&th_v, de_ctx, det_ctx, p1); + SigMatchSignatures(tv, de_ctx, det_ctx, p1); alerts1 += PacketAlertCheck(p1, 1); - SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + SigMatchSignatures(tv, de_ctx, det_ctx, p2); alerts2 += PacketAlertCheck(p2, 1); FAIL_IF(alerts1 != 3); FAIL_IF(alerts2 != 3); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineThreadCtxDeinit(tv, (void *)det_ctx); DetectEngineCtxFree(de_ctx); UTHFreePackets(&p1, 1); UTHFreePackets(&p2, 1); + ThreadFreeStorage(tv); + StorageCleanup(); ThresholdDestroy(); + ThreadVarsFree(tv); PASS; } diff --git a/src/runmode-unittests.c b/src/runmode-unittests.c index ffa82ef5aa6c..4898f39a00ec 100644 --- a/src/runmode-unittests.c +++ b/src/runmode-unittests.c @@ -89,6 +89,7 @@ #include "util-hashlist.h" #include "util-pool.h" #include "util-byte.h" +#include "util-file.h" #include "util-proto-name.h" #include "util-macset.h" #include "util-flow-rate.h" @@ -217,6 +218,7 @@ static void RegisterUnittests(void) SourceWinDivertRegisterTests(); #endif SCProtoNameRegisterTests(); + FileRegisterTests(); UtilCIDRTests(); OutputJsonStatsRegisterTests(); CoredumpConfigRegisterTests(); diff --git a/src/tests/fuzz/fuzz_predefpcap_aware.c b/src/tests/fuzz/fuzz_predefpcap_aware.c index 74c7dab8d401..0351e22e0573 100644 --- a/src/tests/fuzz/fuzz_predefpcap_aware.c +++ b/src/tests/fuzz/fuzz_predefpcap_aware.c @@ -35,7 +35,7 @@ int LLVMFuzzerInitialize(const int *argc, char ***argv); int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); static int initialized = 0; -ThreadVars tv; +ThreadVars *tv = NULL; DecodeThreadVars *dtv; // FlowWorkerThreadData void *fwd; @@ -88,14 +88,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) PreRunPostPrivsDropInit(SCRunmodeGet()); PostConfLoadedDetectSetup(&surifuzz); - memset(&tv, 0, sizeof(tv)); - tv.flow_queue = FlowQueueNew(); - if (tv.flow_queue == NULL) + tv = ThreadVarsAlloc(); + tv->flow_queue = FlowQueueNew(); + if (tv->flow_queue == NULL) abort(); - dtv = DecodeThreadVarsAlloc(&tv); - DecodeRegisterPerfCounters(dtv, &tv); - tmm_modules[TMM_FLOWWORKER].ThreadInit(&tv, NULL, &fwd); - StatsSetupPrivate(&tv); + dtv = DecodeThreadVarsAlloc(tv); + DecodeRegisterPerfCounters(dtv, tv); + tmm_modules[TMM_FLOWWORKER].ThreadInit(tv, NULL, &fwd); + StatsSetupPrivate(tv); extern uint32_t max_pending_packets; max_pending_packets = 128; @@ -128,20 +128,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) while (r > 0) { if (PacketCopyData(p, pkt, header.caplen) == 0) { // DecodePcapFile - TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(&tv, p, dtv); + TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(tv, p, dtv); if (ecode == TM_ECODE_FAILED) { break; } - Packet *extra_p = PacketDequeueNoLock(&tv.decode_pq); + Packet *extra_p = PacketDequeueNoLock(&tv->decode_pq); while (extra_p != NULL) { PacketFreeOrRelease(extra_p); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + extra_p = PacketDequeueNoLock(&tv->decode_pq); } - tmm_modules[TMM_FLOWWORKER].Func(&tv, p, fwd); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + tmm_modules[TMM_FLOWWORKER].Func(tv, p, fwd); + extra_p = PacketDequeueNoLock(&tv->decode_pq); while (extra_p != NULL) { PacketFreeOrRelease(extra_p); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + extra_p = PacketDequeueNoLock(&tv->decode_pq); } } r = FPC_next(&pkts, &header, &pkt); diff --git a/src/tests/fuzz/fuzz_sigpcap.c b/src/tests/fuzz/fuzz_sigpcap.c index 6b2efae32736..37cd6950b9cf 100644 --- a/src/tests/fuzz/fuzz_sigpcap.c +++ b/src/tests/fuzz/fuzz_sigpcap.c @@ -35,7 +35,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); static int initialized = 0; -ThreadVars tv; +ThreadVars *tv = NULL; DecodeThreadVars *dtv; //FlowWorkerThreadData void *fwd; @@ -81,14 +81,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) PreRunPostPrivsDropInit(SCRunmodeGet()); PostConfLoadedDetectSetup(&surifuzz); - memset(&tv, 0, sizeof(tv)); - tv.flow_queue = FlowQueueNew(); - if (tv.flow_queue == NULL) + tv = ThreadVarsAlloc(); + tv->flow_queue = FlowQueueNew(); + if (tv->flow_queue == NULL) abort(); - dtv = DecodeThreadVarsAlloc(&tv); - DecodeRegisterPerfCounters(dtv, &tv); - tmm_modules[TMM_FLOWWORKER].ThreadInit(&tv, NULL, &fwd); - StatsSetupPrivate(&tv); + dtv = DecodeThreadVarsAlloc(tv); + DecodeRegisterPerfCounters(dtv, tv); + tmm_modules[TMM_FLOWWORKER].ThreadInit(tv, NULL, &fwd); + StatsSetupPrivate(tv); extern uint32_t max_pending_packets; max_pending_packets = 128; @@ -136,7 +136,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) DetectEngineCtx *de_ctx = DetectEngineGetCurrent(); de_ctx->ref_cnt--; - DetectEngineThreadCtx *new_det_ctx = DetectEngineThreadCtxInitForReload(&tv, de_ctx, 1); + DetectEngineThreadCtx *new_det_ctx = DetectEngineThreadCtxInitForReload(tv, de_ctx, 1); FlowWorkerReplaceDetectCtx(fwd, new_det_ctx); DetectEngineThreadCtxDeinit(NULL, old_det_ctx); @@ -171,20 +171,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) while (r > 0) { if (PacketCopyData(p, pkt, header->caplen) == 0) { // DecodePcapFile - TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(&tv, p, dtv); + TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(tv, p, dtv); if (ecode == TM_ECODE_FAILED) { break; } - Packet *extra_p = PacketDequeueNoLock(&tv.decode_pq); + Packet *extra_p = PacketDequeueNoLock(&tv->decode_pq); while (extra_p != NULL) { PacketFreeOrRelease(extra_p); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + extra_p = PacketDequeueNoLock(&tv->decode_pq); } - tmm_modules[TMM_FLOWWORKER].Func(&tv, p, fwd); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + tmm_modules[TMM_FLOWWORKER].Func(tv, p, fwd); + extra_p = PacketDequeueNoLock(&tv->decode_pq); while (extra_p != NULL) { PacketFreeOrRelease(extra_p); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + extra_p = PacketDequeueNoLock(&tv->decode_pq); } } r = pcap_next_ex(pkts, &header, &pkt); diff --git a/src/tests/fuzz/fuzz_sigpcap_aware.c b/src/tests/fuzz/fuzz_sigpcap_aware.c index 05be5813ab7f..4d55699f92aa 100644 --- a/src/tests/fuzz/fuzz_sigpcap_aware.c +++ b/src/tests/fuzz/fuzz_sigpcap_aware.c @@ -35,7 +35,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); static int initialized = 0; -ThreadVars tv; +ThreadVars *tv = NULL; DecodeThreadVars *dtv; // FlowWorkerThreadData void *fwd; @@ -106,14 +106,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) PreRunPostPrivsDropInit(SCRunmodeGet()); PostConfLoadedDetectSetup(&surifuzz); - memset(&tv, 0, sizeof(tv)); - tv.flow_queue = FlowQueueNew(); - if (tv.flow_queue == NULL) + tv = ThreadVarsAlloc(); + tv->flow_queue = FlowQueueNew(); + if (tv->flow_queue == NULL) abort(); - dtv = DecodeThreadVarsAlloc(&tv); - DecodeRegisterPerfCounters(dtv, &tv); - tmm_modules[TMM_FLOWWORKER].ThreadInit(&tv, NULL, &fwd); - StatsSetupPrivate(&tv); + dtv = DecodeThreadVarsAlloc(tv); + DecodeRegisterPerfCounters(dtv, tv); + tmm_modules[TMM_FLOWWORKER].ThreadInit(tv, NULL, &fwd); + StatsSetupPrivate(tv); extern uint32_t max_pending_packets; max_pending_packets = 128; @@ -150,7 +150,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) DetectEngineCtx *de_ctx = DetectEngineGetCurrent(); de_ctx->ref_cnt--; - DetectEngineThreadCtx *new_det_ctx = DetectEngineThreadCtxInitForReload(&tv, de_ctx, 1); + DetectEngineThreadCtx *new_det_ctx = DetectEngineThreadCtxInitForReload(tv, de_ctx, 1); FlowWorkerReplaceDetectCtx(fwd, new_det_ctx); DetectEngineThreadCtxDeinit(NULL, old_det_ctx); @@ -167,20 +167,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) while (r > 0) { if (PacketCopyData(p, pkt, header.caplen) == 0) { // DecodePcapFile - TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(&tv, p, dtv); + TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(tv, p, dtv); if (ecode == TM_ECODE_FAILED) { break; } - Packet *extra_p = PacketDequeueNoLock(&tv.decode_pq); + Packet *extra_p = PacketDequeueNoLock(&tv->decode_pq); while (extra_p != NULL) { PacketFreeOrRelease(extra_p); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + extra_p = PacketDequeueNoLock(&tv->decode_pq); } - tmm_modules[TMM_FLOWWORKER].Func(&tv, p, fwd); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + tmm_modules[TMM_FLOWWORKER].Func(tv, p, fwd); + extra_p = PacketDequeueNoLock(&tv->decode_pq); while (extra_p != NULL) { PacketFreeOrRelease(extra_p); - extra_p = PacketDequeueNoLock(&tv.decode_pq); + extra_p = PacketDequeueNoLock(&tv->decode_pq); } } r = FPC_next(&pkts, &header, &pkt); diff --git a/src/threadvars.c b/src/threadvars.c new file mode 100644 index 000000000000..75de75dff165 --- /dev/null +++ b/src/threadvars.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2026 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "threadvars.h" +#include "thread-storage.h" + +/** + * \brief Allocate a new ThreadVars structure. + * + * \retval NULL if allocation failed. + * \retval Pointer to newly allocated ThreadVars structure. + */ +ThreadVars *ThreadVarsAlloc(void) +{ + ThreadVars *tv = SCCalloc(1, sizeof(ThreadVars) + ThreadStorageSize()); + if (tv == NULL) + return NULL; + SC_ATOMIC_INIT(tv->flags); + SCMutexInit(&tv->perf_public_ctx.m, NULL); + return tv; +} + +/** + * \brief Free a ThreadVars structure. + * + * \param tv Pointer to ThreadVars structure to be freed. + */ +void ThreadVarsFree(ThreadVars *tv) +{ + if (tv == NULL) + return; + SCFree(tv); +} diff --git a/src/threadvars.h b/src/threadvars.h index 3646c0f297b2..0b84f1e7e047 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -147,4 +147,19 @@ typedef struct ThreadVars_ { #define THREAD_SET_PRIORITY 0x02 /** Real time priority */ #define THREAD_SET_AFFTYPE 0x04 /** Priority and affinity */ +/** + * \brief Allocate a new ThreadVars structure. + * + * \retval NULL if allocation failed. + * \retval Pointer to newly allocated ThreadVars structure. + */ +ThreadVars *ThreadVarsAlloc(void); + +/** + * \brief Free a ThreadVars structure. + * + * \param tv Pointer to ThreadVars structure to be freed. + */ +void ThreadVarsFree(ThreadVars *tv); + #endif /* SURICATA_THREADVARS_H */ diff --git a/src/tm-threads.c b/src/tm-threads.c index 97a03650a6a3..0adc0d1ad3d5 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -939,20 +939,15 @@ ThreadVars *TmThreadCreate(const char *name, const char *inq_name, const char *i const char *outq_name, const char *outqh_name, const char *slots, void * (*fn_p)(void *), int mucond) { - ThreadVars *tv = NULL; Tmq *tmq = NULL; Tmqh *tmqh = NULL; SCLogDebug("creating thread \"%s\"...", name); - /* XXX create separate function for this: allocate a thread container */ - tv = SCCalloc(1, sizeof(ThreadVars) + ThreadStorageSize()); + ThreadVars *tv = ThreadVarsAlloc(); if (unlikely(tv == NULL)) goto error; - SC_ATOMIC_INIT(tv->flags); - SCMutexInit(&tv->perf_public_ctx.m, NULL); - strlcpy(tv->name, name, sizeof(tv->name)); /* default state for every newly created thread */ @@ -1044,8 +1039,7 @@ ThreadVars *TmThreadCreate(const char *name, const char *inq_name, const char *i error: SCLogError("failed to setup a thread"); - if (tv != NULL) - SCFree(tv); + ThreadVarsFree(tv); return NULL; } @@ -1675,7 +1669,7 @@ static void TmThreadFree(ThreadVars *tv) } TmThreadsUnregisterThread(tv->id); - SCFree(tv); + ThreadVarsFree(tv); } void TmThreadSetGroupName(ThreadVars *tv, const char *name) diff --git a/src/util-file.c b/src/util-file.c index 5a32efe52811..d4a5baccaf69 100644 --- a/src/util-file.c +++ b/src/util-file.c @@ -378,17 +378,17 @@ static int FilePruneFile(File *file, const StreamingBufferConfig *cfg) * do some house keeping here */ if (file->inspect_window != 0 && file->inspect_min_size != 0) { const uint64_t file_offset = StreamingBufferGetOffset(file->sb); - uint32_t window = file->inspect_window; + uint64_t window = file->inspect_window; if (file_offset == 0) - window = MAX(window, file->inspect_min_size); + window = MAX(window, (uint64_t)file->inspect_min_size); uint64_t file_size = FileDataSize(file); uint64_t data_size = file_size - file_offset; - SCLogDebug("window %"PRIu32", file_size %"PRIu64", data_size %"PRIu64, - window, file_size, data_size); + SCLogDebug("window %" PRIu64 ", file_size %" PRIu64 ", data_size %" PRIu64, window, + file_size, data_size); - if (data_size > (window * 3)) { + if (data_size > window * 3) { file->content_inspected = MAX(file->content_inspected, file->size - window); SCLogDebug("file->content_inspected now %" PRIu64, file->content_inspected); } @@ -1192,3 +1192,49 @@ static void FileEndSha256(File *ff) ff->flags |= FILE_SHA256; } } + +#ifdef UNITTESTS +#include "util-unittest.h" + +/** + * \test the inspect window guard must not wrap around + * + * `window * 3` used to be computed in uint32_t arithmetic. The guard is there + * to make sure `file->size > window`, so on wrap around `file->size - window` + * underflows and content_inspected ends up bogus. + */ +static int FilePruneInspectWindowOverflowTest(void) +{ + const int detect_disabled = g_detect_disabled; + g_detect_disabled = 0; + + StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; + FileContainer *ffc = FileContainerAlloc(); + FAIL_IF_NULL(ffc); + + uint8_t data[64]; + memset(data, 'A', sizeof(data)); + + FAIL_IF(FileOpenFileWithId(ffc, &sbcfg, 0, (const uint8_t *)"f", 1, NULL, 0, + FILE_NOMAGIC | FILE_NOMD5 | FILE_NOSHA1 | FILE_NOSHA256) != 0); + FAIL_IF_NULL(ffc->tail); + + /* 0xAAAAAAAB * 3 is 1 when truncated to 32 bits */ + FileSetInspectSizes(ffc->tail, 0xAAAAAAABU, 1); + FAIL_IF(FileAppendData(ffc, &sbcfg, data, sizeof(data)) != 0); + + FilePrune(ffc, &sbcfg); + + FAIL_IF_NULL(ffc->head); + FAIL_IF(ffc->head->content_inspected != 0); + + FileContainerFree(ffc, &sbcfg); + g_detect_disabled = detect_disabled; + PASS; +} + +void FileRegisterTests(void) +{ + UtRegisterTest("FilePruneInspectWindowOverflowTest", FilePruneInspectWindowOverflowTest); +} +#endif /* UNITTESTS */ diff --git a/src/util-file.h b/src/util-file.h index 3e42efda650d..69e2f9a0a5b9 100644 --- a/src/util-file.h +++ b/src/util-file.h @@ -252,4 +252,8 @@ void FilePrintFlags(const File *file); void FilesPrune(FileContainer *fc, const StreamingBufferConfig *sbcfg, const bool trunc); +#ifdef UNITTESTS +void FileRegisterTests(void); +#endif + #endif /* SURICATA_UTIL_FILE_H */ diff --git a/src/util-hash.c b/src/util-hash.c index da9b6413ed88..e4cd341e29e3 100644 --- a/src/util-hash.c +++ b/src/util-hash.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -75,6 +75,18 @@ HashTable* HashTableInit(uint32_t size, uint32_t (*Hash)(struct HashTable_ *, vo return NULL; } +HashTable *HashTableInitWithSeed(uint32_t size, + uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), + char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *), + const uint32_t seed) +{ + HashTable *ht = HashTableInit(size, Hash, Compare, Free); + if (ht != NULL) { + ht->seed = seed; + } + return ht; +} + /** * \brief Free a HashTableBucket and return the next bucket * \param ht Pointer to the HashTable diff --git a/src/util-hash.h b/src/util-hash.h index 40241b3db71a..0b55f927a4ed 100644 --- a/src/util-hash.h +++ b/src/util-hash.h @@ -35,6 +35,7 @@ typedef struct HashTableBucket_ { typedef struct HashTable_ { HashTableBucket **array; uint32_t array_size; + uint32_t seed; /**< optional random seed, to be used by the registered hash function. */ #ifdef UNITTESTS uint32_t count; #endif @@ -47,6 +48,9 @@ typedef struct HashTable_ { /* prototypes */ HashTable* HashTableInit(uint32_t, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *)); +HashTable *HashTableInitWithSeed(uint32_t, uint32_t (*Hash)(struct HashTable_ *, void *, uint16_t), + char (*Compare)(void *, uint16_t, void *, uint16_t), void (*Free)(void *), + const uint32_t seed); void HashTableFree(HashTable *); int HashTableAdd(HashTable *, void *, uint16_t); int HashTableRemove(HashTable *, void *, uint16_t);