|
|
|
/* Copyright (C) 2007-2010 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
*
|
|
|
|
* \author Victor Julien <victor@inliniac.net>
|
|
|
|
*
|
|
|
|
* Multi pattern matcher
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "suricata.h"
|
|
|
|
#include "suricata-common.h"
|
|
|
|
|
|
|
|
#include "app-layer-protos.h"
|
|
|
|
|
|
|
|
#include "decode.h"
|
|
|
|
#include "detect.h"
|
|
|
|
#include "detect-engine.h"
|
|
|
|
#include "detect-engine-siggroup.h"
|
|
|
|
#include "detect-engine-mpm.h"
|
|
|
|
#include "detect-engine-iponly.h"
|
|
|
|
#include "detect-parse.h"
|
|
|
|
#include "util-mpm.h"
|
|
|
|
#include "conf.h"
|
|
|
|
#include "detect-fast-pattern.h"
|
|
|
|
|
|
|
|
#include "flow.h"
|
|
|
|
#include "flow-var.h"
|
|
|
|
#include "detect-flow.h"
|
|
|
|
|
|
|
|
#include "detect-content.h"
|
|
|
|
#include "detect-uricontent.h"
|
|
|
|
|
|
|
|
#include "stream.h"
|
|
|
|
|
|
|
|
#include "util-cuda-handlers.h"
|
|
|
|
#include "util-mpm-b2g-cuda.h"
|
|
|
|
|
|
|
|
#include "util-enum.h"
|
|
|
|
#include "util-debug.h"
|
|
|
|
#include "util-print.h"
|
|
|
|
#include "util-memcmp.h"
|
|
|
|
|
|
|
|
/** \todo make it possible to use multiple pattern matcher algorithms next to
|
|
|
|
eachother. */
|
|
|
|
//#define PM MPM_WUMANBER
|
|
|
|
//#define PM MPM_B2G
|
|
|
|
#ifdef __SC_CUDA_SUPPORT__
|
|
|
|
#define PM MPM_B2G_CUDA
|
|
|
|
#else
|
|
|
|
#define PM MPM_B2G
|
|
|
|
#endif
|
|
|
|
//#define PM MPM_B3G
|
|
|
|
|
|
|
|
#define POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS 0x01
|
|
|
|
#define POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS 0x02
|
|
|
|
#define POPULATE_MPM_AVOID_URI_MPM_PATTERNS 0x04
|
|
|
|
|
|
|
|
/* holds the string-enum mapping for the enums that define the different MPM
|
|
|
|
* algos in util-mpm.h */
|
|
|
|
SCEnumCharMap sc_mpm_algo_map[] = {
|
|
|
|
{ "b2g", MPM_B2G },
|
|
|
|
{ "b3g", MPM_B3G },
|
|
|
|
{ "wumanber", MPM_WUMANBER },
|
|
|
|
{ "ac", MPM_AC },
|
|
|
|
{ "ac-gfbs", MPM_AC_GFBS },
|
|
|
|
#ifdef __SC_CUDA_SUPPORT__
|
|
|
|
{ "b2g_cuda", MPM_B2G_CUDA },
|
|
|
|
#endif
|
|
|
|
{ "b2gc", MPM_B2GC },
|
|
|
|
{ "b2gm", MPM_B2GM },
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief check if a signature has patterns that are to be inspected
|
|
|
|
* against a packets payload (as opposed to the stream payload)
|
|
|
|
*
|
|
|
|
* \param s signature
|
|
|
|
*
|
|
|
|
* \retval 1 true
|
|
|
|
* \retval 0 false
|
|
|
|
*/
|
|
|
|
int SignatureHasPacketContent(Signature *s) {
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
if (s == NULL) {
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(s->flags & SIG_FLAG_MPM)) {
|
|
|
|
SCLogDebug("no mpm");
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->alproto != ALPROTO_UNKNOWN) {
|
|
|
|
SCLogDebug("inspecting app layer");
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH];
|
|
|
|
if (sm == NULL) {
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( ;sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type == DETECT_CONTENT) {
|
|
|
|
SCReturnInt(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief check if a signature has patterns that are to be inspected
|
|
|
|
* against the stream payload (as opposed to the individual packets
|
|
|
|
* payload(s))
|
|
|
|
*
|
|
|
|
* \param s signature
|
|
|
|
*
|
|
|
|
* \retval 1 true
|
|
|
|
* \retval 0 false
|
|
|
|
*/
|
|
|
|
int SignatureHasStreamContent(Signature *s) {
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
if (s == NULL) {
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(s->flags & SIG_FLAG_MPM)) {
|
|
|
|
SCLogDebug("no mpm");
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->flags & SIG_FLAG_DSIZE) {
|
|
|
|
SCLogDebug("dsize");
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SigMatch *sm = s->sm_lists[DETECT_SM_LIST_PMATCH];
|
|
|
|
if (sm == NULL) {
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( ;sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type == DETECT_CONTENT) {
|
|
|
|
SCReturnInt(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** \brief Function to return the default multi pattern matcher algorithm to be
|
|
|
|
* used by the engine
|
|
|
|
* \retval mpm algo value
|
|
|
|
*/
|
|
|
|
uint16_t PatternMatchDefaultMatcher(void) {
|
|
|
|
char *mpm_algo;
|
|
|
|
int mpm_algo_val = PM;
|
|
|
|
|
|
|
|
/* Get the mpm algo defined in config file by the user */
|
|
|
|
if ((ConfGet("mpm-algo", &mpm_algo)) == 1) {
|
|
|
|
mpm_algo_val = SCMapEnumNameToValue(mpm_algo, sc_mpm_algo_map);
|
|
|
|
if (mpm_algo_val == -1) {
|
|
|
|
SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid mpm algo supplied "
|
|
|
|
"in the yaml conf file: \"%s\"", mpm_algo);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mpm_algo_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Pattern match -- searches for only one pattern per signature.
|
|
|
|
*
|
|
|
|
* \param tv threadvars
|
|
|
|
* \param det_ctx detection engine thread ctx
|
|
|
|
* \param p packet to inspect
|
|
|
|
*
|
|
|
|
* \retval ret number of matches
|
|
|
|
*/
|
|
|
|
uint32_t PacketPatternSearch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
|
|
|
|
Packet *p)
|
|
|
|
{
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
uint32_t ret;
|
|
|
|
|
|
|
|
#ifndef __SC_CUDA_SUPPORT__
|
|
|
|
ret = mpm_table[det_ctx->sgh->mpm_ctx->mpm_type].Search(det_ctx->sgh->mpm_ctx,
|
|
|
|
&det_ctx->mtc,
|
|
|
|
&det_ctx->pmq,
|
|
|
|
p->payload,
|
|
|
|
p->payload_len);
|
|
|
|
#else
|
|
|
|
/* if the user has enabled cuda support, but is not using the cuda mpm
|
|
|
|
* algo, then we shouldn't take the path of the dispatcher. Call the mpm
|
|
|
|
* directly */
|
|
|
|
if (det_ctx->sgh->mpm_ctx->mpm_type != MPM_B2G_CUDA) {
|
|
|
|
ret = mpm_table[det_ctx->sgh->mpm_ctx->mpm_type].Search(det_ctx->sgh->mpm_ctx,
|
|
|
|
&det_ctx->mtc,
|
|
|
|
&det_ctx->pmq,
|
|
|
|
p->payload,
|
|
|
|
p->payload_len);
|
|
|
|
SCReturnInt(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->cuda_mpm_enabled) {
|
|
|
|
ret = B2gCudaResultsPostProcessing(p, det_ctx->sgh->mpm_ctx,
|
|
|
|
&det_ctx->mtc, &det_ctx->pmq);
|
|
|
|
} else {
|
|
|
|
ret = mpm_table[det_ctx->sgh->mpm_ctx->mpm_type].Search(det_ctx->sgh->mpm_ctx,
|
|
|
|
&det_ctx->mtc,
|
|
|
|
&det_ctx->pmq,
|
|
|
|
p->payload,
|
|
|
|
p->payload_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SCReturnInt(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Uri Pattern match -- searches for one pattern per signature.
|
|
|
|
*
|
|
|
|
* \param det_ctx detection engine thread ctx
|
|
|
|
* \param p packet to inspect
|
|
|
|
*
|
|
|
|
* \retval ret number of matches
|
|
|
|
*/
|
|
|
|
uint32_t UriPatternSearch(DetectEngineThreadCtx *det_ctx,
|
|
|
|
uint8_t *uri, uint16_t uri_len)
|
|
|
|
{
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
if (det_ctx->sgh->mpm_uri_ctx == NULL)
|
|
|
|
SCReturnUInt(0U);
|
|
|
|
|
|
|
|
//PrintRawDataFp(stdout, uri, uri_len);
|
|
|
|
|
|
|
|
uint32_t ret;
|
|
|
|
ret = mpm_table[det_ctx->sgh->mpm_uri_ctx->mpm_type].Search(det_ctx->sgh->mpm_uri_ctx,
|
|
|
|
&det_ctx->mtcu, &det_ctx->pmq, uri, uri_len);
|
|
|
|
|
|
|
|
SCReturnUInt(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Pattern match -- searches for only one pattern per signature.
|
|
|
|
*
|
|
|
|
* \param tv threadvars
|
|
|
|
* \param det_ctx detection engine thread ctx
|
|
|
|
* \param p packet
|
|
|
|
* \param smsg stream msg (reassembled stream data)
|
|
|
|
* \param flags stream flags
|
|
|
|
*
|
|
|
|
* \retval ret number of matches
|
|
|
|
*/
|
|
|
|
uint32_t StreamPatternSearch(ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
|
|
|
|
Packet *p, StreamMsg *smsg, uint8_t flags)
|
|
|
|
{
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
uint32_t ret = 0;
|
|
|
|
uint8_t cnt = 0;
|
|
|
|
|
|
|
|
for ( ; smsg != NULL; smsg = smsg->next) {
|
|
|
|
if (smsg->data.data_len < det_ctx->sgh->mpm_streamcontent_maxlen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
//PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len);
|
|
|
|
|
|
|
|
uint32_t r = mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Search(det_ctx->sgh->mpm_stream_ctx,
|
|
|
|
&det_ctx->mtcs, &det_ctx->smsg_pmq[cnt], smsg->data.data, smsg->data.data_len);
|
|
|
|
if (r > 0) {
|
|
|
|
ret += r;
|
|
|
|
|
|
|
|
SCLogDebug("smsg match stored in det_ctx->smsg_pmq[%u]", cnt);
|
|
|
|
|
|
|
|
/* merge results with overall pmq */
|
|
|
|
PmqMerge(&det_ctx->smsg_pmq[cnt], &det_ctx->pmq);
|
|
|
|
}
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCReturnInt(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief cleans up the mpm instance after a match */
|
|
|
|
void PacketPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx) {
|
|
|
|
PmqReset(&det_ctx->pmq);
|
|
|
|
|
|
|
|
if (det_ctx->sgh == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* content */
|
|
|
|
if (det_ctx->sgh->mpm_ctx != NULL && mpm_table[det_ctx->sgh->mpm_ctx->mpm_type].Cleanup != NULL) {
|
|
|
|
mpm_table[det_ctx->sgh->mpm_ctx->mpm_type].Cleanup(&det_ctx->mtc);
|
|
|
|
}
|
|
|
|
/* uricontent */
|
|
|
|
if (det_ctx->sgh->mpm_uri_ctx != NULL && mpm_table[det_ctx->sgh->mpm_uri_ctx->mpm_type].Cleanup != NULL) {
|
|
|
|
mpm_table[det_ctx->sgh->mpm_uri_ctx->mpm_type].Cleanup(&det_ctx->mtcu);
|
|
|
|
}
|
|
|
|
/* stream content */
|
|
|
|
if (det_ctx->sgh->mpm_stream_ctx != NULL && mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Cleanup != NULL) {
|
|
|
|
mpm_table[det_ctx->sgh->mpm_stream_ctx->mpm_type].Cleanup(&det_ctx->mtcs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg) {
|
|
|
|
uint8_t cnt = 0;
|
|
|
|
|
|
|
|
while (smsg != NULL) {
|
|
|
|
PmqReset(&det_ctx->smsg_pmq[cnt]);
|
|
|
|
|
|
|
|
smsg = smsg->next;
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher) {
|
|
|
|
SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher);
|
|
|
|
mpm_table[mpm_matcher].DestroyCtx(mpm_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PatternMatchPrepare(MpmCtx *mpm_ctx, uint16_t mpm_matcher) {
|
|
|
|
SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher);
|
|
|
|
MpmInitCtx(mpm_ctx, mpm_matcher, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) {
|
|
|
|
SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher);
|
|
|
|
//mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx);
|
|
|
|
}
|
|
|
|
void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher) {
|
|
|
|
SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher);
|
|
|
|
mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx);
|
|
|
|
}
|
|
|
|
void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher, uint32_t max_id) {
|
|
|
|
SCLogDebug("mpm_thread_ctx %p, type %"PRIu16", max_id %"PRIu32"", mpm_thread_ctx, mpm_matcher, max_id);
|
|
|
|
MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher, max_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* free the pattern matcher part of a SigGroupHead */
|
|
|
|
void PatternMatchDestroyGroup(SigGroupHead *sh) {
|
|
|
|
/* content */
|
|
|
|
if (sh->flags & SIG_GROUP_HAVECONTENT && sh->mpm_ctx != NULL &&
|
|
|
|
!(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) {
|
|
|
|
SCLogDebug("destroying mpm_ctx %p (sh %p)", sh->mpm_ctx, sh);
|
|
|
|
if (!MpmFactoryIsMpmCtxAvailable(sh->mpm_ctx)) {
|
|
|
|
mpm_table[sh->mpm_ctx->mpm_type].DestroyCtx(sh->mpm_ctx);
|
|
|
|
SCFree(sh->mpm_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ready for reuse */
|
|
|
|
sh->mpm_ctx = NULL;
|
|
|
|
sh->flags &= ~SIG_GROUP_HAVECONTENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* uricontent */
|
|
|
|
if (sh->flags & SIG_GROUP_HAVEURICONTENT && sh->mpm_uri_ctx != NULL &&
|
|
|
|
!(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
|
|
|
|
SCLogDebug("destroying mpm_uri_ctx %p (sh %p)", sh->mpm_uri_ctx, sh);
|
|
|
|
if (!MpmFactoryIsMpmCtxAvailable(sh->mpm_uri_ctx)) {
|
|
|
|
mpm_table[sh->mpm_uri_ctx->mpm_type].DestroyCtx(sh->mpm_uri_ctx);
|
|
|
|
SCFree(sh->mpm_uri_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ready for reuse */
|
|
|
|
sh->mpm_uri_ctx = NULL;
|
|
|
|
sh->flags &= ~SIG_GROUP_HAVEURICONTENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stream content */
|
|
|
|
if (sh->flags & SIG_GROUP_HAVESTREAMCONTENT) {
|
|
|
|
if (sh->mpm_stream_ctx != NULL) {
|
|
|
|
if (!(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) {
|
|
|
|
SCLogDebug("destroying mpm_stream_ctx %p (sh %p)", sh->mpm_stream_ctx, sh);
|
|
|
|
if (!MpmFactoryIsMpmCtxAvailable(sh->mpm_stream_ctx)) {
|
|
|
|
mpm_table[sh->mpm_stream_ctx->mpm_type].DestroyCtx(sh->mpm_stream_ctx);
|
|
|
|
SCFree(sh->mpm_stream_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ready for reuse */
|
|
|
|
sh->mpm_stream_ctx = NULL;
|
|
|
|
sh->flags &= ~SIG_GROUP_HAVESTREAMCONTENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Hash for looking up contents that are most used,
|
|
|
|
* always used, etc. */
|
|
|
|
typedef struct ContentHash_ {
|
|
|
|
DetectContentData *ptr;
|
|
|
|
uint16_t cnt;
|
|
|
|
uint8_t use; /* use no matter what */
|
|
|
|
} ContentHash;
|
|
|
|
|
|
|
|
typedef struct UricontentHash_ {
|
|
|
|
DetectUricontentData *ptr;
|
|
|
|
uint16_t cnt;
|
|
|
|
uint8_t use; /* use no matter what */
|
|
|
|
} UricontentHash;
|
|
|
|
|
|
|
|
uint32_t ContentHashFunc(HashTable *ht, void *data, uint16_t datalen) {
|
|
|
|
ContentHash *ch = (ContentHash *)data;
|
|
|
|
DetectContentData *co = ch->ptr;
|
|
|
|
uint32_t hash = 0;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < co->content_len; i++) {
|
|
|
|
hash += co->content[i];
|
|
|
|
}
|
|
|
|
hash = hash % ht->array_size;
|
|
|
|
SCLogDebug("hash %" PRIu32 "", hash);
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t UricontentHashFunc(HashTable *ht, void *data, uint16_t datalen) {
|
|
|
|
UricontentHash *ch = (UricontentHash *)data;
|
|
|
|
DetectUricontentData *ud = ch->ptr;
|
|
|
|
uint32_t hash = 0;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ud->content_len; i++) {
|
|
|
|
hash += ud->content[i];
|
|
|
|
}
|
|
|
|
hash = hash % ht->array_size;
|
|
|
|
SCLogDebug("hash %" PRIu32 "", hash);
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
char ContentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) {
|
|
|
|
ContentHash *ch1 = (ContentHash *)data1;
|
|
|
|
ContentHash *ch2 = (ContentHash *)data2;
|
|
|
|
DetectContentData *co1 = ch1->ptr;
|
|
|
|
DetectContentData *co2 = ch2->ptr;
|
|
|
|
|
|
|
|
if (co1->content_len == co2->content_len &&
|
|
|
|
((co1->flags & DETECT_CONTENT_NOCASE) == (co2->flags & DETECT_CONTENT_NOCASE)) &&
|
|
|
|
SCMemcmp(co1->content, co2->content, co1->content_len) == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char UricontentHashCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2) {
|
|
|
|
UricontentHash *ch1 = (UricontentHash *)data1;
|
|
|
|
UricontentHash *ch2 = (UricontentHash *)data2;
|
|
|
|
DetectUricontentData *ud1 = ch1->ptr;
|
|
|
|
DetectUricontentData *ud2 = ch2->ptr;
|
|
|
|
|
|
|
|
if (ud1->content_len == ud2->content_len &&
|
|
|
|
((ud1->flags & DETECT_URICONTENT_NOCASE) == (ud2->flags & DETECT_URICONTENT_NOCASE)) &&
|
|
|
|
SCMemcmp(ud1->content, ud2->content, ud1->content_len) == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *ContentHashAlloc(DetectContentData *ptr) {
|
|
|
|
ContentHash *ch = SCMalloc(sizeof(ContentHash));
|
|
|
|
if (ch == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ch->ptr = ptr;
|
|
|
|
ch->cnt = 1;
|
|
|
|
ch->use = 0;
|
|
|
|
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
UricontentHash *UricontentHashAlloc(DetectUricontentData *ptr) {
|
|
|
|
UricontentHash *ch = SCMalloc(sizeof(UricontentHash));
|
|
|
|
if (ch == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ch->ptr = ptr;
|
|
|
|
ch->cnt = 1;
|
|
|
|
ch->use = 0;
|
|
|
|
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContentHashFree(void *ch) {
|
|
|
|
SCFree(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UricontentHashFree(void *ch) {
|
|
|
|
SCFree(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Predict a strength value for patterns
|
|
|
|
*
|
|
|
|
* Patterns with high character diversity score higher.
|
|
|
|
* Alpha chars score not so high
|
|
|
|
* Other printable + a few common codes a little higher
|
|
|
|
* Everything else highest.
|
|
|
|
* Longer patterns score better than short patters.
|
|
|
|
*
|
|
|
|
* \param pat pattern
|
|
|
|
* \param patlen length of the patternn
|
|
|
|
*
|
|
|
|
* \retval s pattern score
|
|
|
|
*/
|
|
|
|
uint32_t PatternStrength(uint8_t *pat, uint16_t patlen) {
|
|
|
|
uint8_t a[256];
|
|
|
|
memset(&a, 0 ,sizeof(a));
|
|
|
|
|
|
|
|
uint32_t s = 0;
|
|
|
|
uint16_t u = 0;
|
|
|
|
for (u = 0; u < patlen; u++) {
|
|
|
|
if (a[pat[u]] == 0) {
|
|
|
|
if (isalpha(pat[u]))
|
|
|
|
s += 3;
|
|
|
|
else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF)
|
|
|
|
s += 4;
|
|
|
|
else
|
|
|
|
s += 6;
|
|
|
|
|
|
|
|
a[pat[u]] = 1;
|
|
|
|
} else {
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Setup the mpm content.
|
|
|
|
*
|
|
|
|
* \param de_ctx Pointer to the detect engine context.
|
|
|
|
* \param sgh Pointer to the signature group head against which we are
|
|
|
|
* adding patterns to the mpm ctx.
|
|
|
|
*
|
|
|
|
* \retval 0 Always.
|
|
|
|
*/
|
|
|
|
static int PatternMatchPreparePopulateMpm(DetectEngineCtx *de_ctx,
|
|
|
|
SigGroupHead *sgh)
|
|
|
|
{
|
|
|
|
uint32_t sig;
|
|
|
|
uint32_t *fast_pattern = NULL;
|
|
|
|
|
|
|
|
fast_pattern = (uint32_t *)SCMalloc(sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
if (fast_pattern == NULL) {
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
memset(fast_pattern, 0, sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
|
|
|
|
/* add all mpm candidates to a hash */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int sig_has_no_pkt_and_stream_content = 0;
|
|
|
|
if (!SignatureHasPacketContent(s) && !SignatureHasStreamContent(s)) {
|
|
|
|
sig_has_no_pkt_and_stream_content = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int list_id = 0;
|
|
|
|
for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) {
|
|
|
|
/* we have no keywords that support fp in this Signature sm list */
|
|
|
|
if (!SCFPDoWeSupportFPForSMList(list_id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
/* get the total no of patterns in this Signature, as well as find out
|
|
|
|
* if we have a fast_pattern set in this Signature */
|
|
|
|
for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
|
|
|
|
/* this keyword isn't registered for fp support */
|
|
|
|
if (!SCFPDoWeSupportFPForSMType(sm->type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *cd = NULL;
|
|
|
|
DetectUricontentData *ud = NULL;
|
|
|
|
switch (sm->type) {
|
|
|
|
case DETECT_CONTENT:
|
|
|
|
if (sig_has_no_pkt_and_stream_content ||
|
|
|
|
(!(sgh->flags & SIG_GROUP_HAVECONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_COPY)) &&
|
|
|
|
!(sgh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)))) { break;
|
|
|
|
}
|
|
|
|
cd = (DetectContentData *)sm->ctx;
|
|
|
|
/* special handling of fast pattern keyword */
|
|
|
|
if (cd->flags & DETECT_CONTENT_FAST_PATTERN) {
|
|
|
|
fast_pattern[sig] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case DETECT_URICONTENT:
|
|
|
|
if (!(sgh->flags & SIG_GROUP_HAVEURICONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_URI_COPY))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
/* special handling of fast pattern keyword */
|
|
|
|
if (ud->flags & DETECT_URICONTENT_FAST_PATTERN) {
|
|
|
|
fast_pattern[sig] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
SCLogError(SC_ERR_FATAL, "We shouldn't even be seeing this");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
} /* switch (sm->type) */
|
|
|
|
|
|
|
|
/* found a fast pattern for the sig. Let's get outta here */
|
|
|
|
if (fast_pattern[sig])
|
|
|
|
break;
|
|
|
|
} /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
|
|
|
|
|
|
|
|
/* found a fast pattern for the sig. Let's get outta here */
|
|
|
|
if (fast_pattern[sig])
|
|
|
|
break;
|
|
|
|
} /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
|
|
|
|
} /* for (sig = 0; sig < sgh->sig_cnt; sig++) { */
|
|
|
|
|
|
|
|
/* now determine which one to add to the mpm phase */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int sig_has_no_pkt_and_stream_content = 0;
|
|
|
|
if (!SignatureHasPacketContent(s) && !SignatureHasStreamContent(s)) {
|
|
|
|
sig_has_no_pkt_and_stream_content = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
SigMatch *mpm_sm = NULL;
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
int list_id = 0;
|
|
|
|
for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) {
|
|
|
|
if (!SCFPDoWeSupportFPForSMList(list_id))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) {
|
|
|
|
if (!SCFPDoWeSupportFPForSMType(sm->type))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* skip in case of:
|
|
|
|
* 1. we expect a fastpattern but this isn't it
|
|
|
|
* 2. we have a smaller content than mpm_content_maxlen */
|
|
|
|
if (fast_pattern[sig]) {
|
|
|
|
DetectContentData *cd = NULL;
|
|
|
|
DetectUricontentData *ud = NULL;
|
|
|
|
switch (sm->type) {
|
|
|
|
case DETECT_CONTENT:
|
|
|
|
cd = (DetectContentData *)sm->ctx;
|
|
|
|
if (!(cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
|
|
|
|
SCLogDebug("not a fast pattern %"PRIu32"", co->id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SCLogDebug("fast pattern %"PRIu32"", co->id);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DETECT_URICONTENT:
|
|
|
|
ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
if (!(ud->flags & DETECT_URICONTENT_FAST_PATTERN)) {
|
|
|
|
SCLogDebug("not a fast pattern %"PRIu32"", co->id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SCLogDebug("fast pattern %"PRIu32"", co->id);
|
|
|
|
|
|
|
|
break;
|
|
|
|
} /* switch (sm->type) */
|
|
|
|
} else {
|
|
|
|
DetectContentData *cd = NULL;
|
|
|
|
DetectUricontentData *ud = NULL;
|
|
|
|
switch (sm->type) {
|
|
|
|
case DETECT_CONTENT:
|
|
|
|
if (sig_has_no_pkt_and_stream_content ||
|
|
|
|
(!(sgh->flags & SIG_GROUP_HAVECONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_COPY)) &&
|
|
|
|
!(sgh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
cd = (DetectContentData *)sm->ctx;
|
|
|
|
if (cd->content_len < sgh->mpm_content_maxlen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DETECT_URICONTENT:
|
|
|
|
if (!(sgh->flags & SIG_GROUP_HAVEURICONTENT &&
|
|
|
|
!(sgh->flags & SIG_GROUP_HEAD_MPM_URI_COPY))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
if (ud->content_len < sgh->mpm_uricontent_maxlen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
} /* switch (sm->type) */
|
|
|
|
} /* else - if (fast_pattern[sig] == 1) */
|
|
|
|
|
|
|
|
if (mpm_sm == NULL) {
|
|
|
|
mpm_sm = sm;
|
|
|
|
if (fast_pattern[sig])
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
DetectContentData *data1 = (DetectContentData *)sm->ctx;
|
|
|
|
DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
|
|
|
|
uint32_t ls = PatternStrength(data1->content, data1->content_len);
|
|
|
|
uint32_t ss = PatternStrength(data2->content, data2->content_len);
|
|
|
|
if (ls > ss) {
|
|
|
|
mpm_sm = sm;
|
|
|
|
} else if (ls == ss) {
|
|
|
|
/* if 2 patterns are of equal strength, we pick the longest */
|
|
|
|
if (data1->content_len > data2->content_len)
|
|
|
|
mpm_sm = sm;
|
|
|
|
} else {
|
|
|
|
SCLogDebug("sticking with mpm_sm");
|
|
|
|
}
|
|
|
|
} /* else - if (mpm == NULL) */
|
|
|
|
} /* for (sm = s->sm_lists[list_id]; sm != NULL; sm = sm->next) */
|
|
|
|
if (mpm_sm != NULL && fast_pattern[sig])
|
|
|
|
break;
|
|
|
|
} /* for ( ; list_id < DETECT_SM_LIST_MAX; list_id++) */
|
|
|
|
|
|
|
|
/* now add the mpm_ch to the mpm ctx */
|
|
|
|
if (mpm_sm != NULL) {
|
|
|
|
uint8_t flags = 0;
|
|
|
|
|
|
|
|
DetectContentData *cd = NULL;
|
|
|
|
DetectUricontentData *ud = NULL;
|
|
|
|
switch (mpm_sm->type) {
|
|
|
|
case DETECT_CONTENT:
|
|
|
|
{
|
|
|
|
cd = (DetectContentData *)mpm_sm->ctx;
|
|
|
|
if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (SignatureHasPacketContent(s) &&
|
|
|
|
(sgh->flags & SIG_GROUP_HAVECONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_COPY))) {
|
|
|
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_ctx,
|
|
|
|
cd->content + cd->fp_chop_offset,
|
|
|
|
cd->fp_chop_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_ctx,
|
|
|
|
cd->content + cd->fp_chop_offset,
|
|
|
|
cd->fp_chop_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
}
|
|
|
|
/* tell matcher we are inspecting packet */
|
|
|
|
s->flags |= SIG_FLAG_MPM_PACKET;
|
|
|
|
s->mpm_pattern_id_div_8 = cd->id / 8;
|
|
|
|
s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8);
|
|
|
|
}
|
|
|
|
if (SignatureHasStreamContent(s) &&
|
|
|
|
(sgh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY))) {
|
|
|
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_ctx,
|
|
|
|
cd->content + cd->fp_chop_offset,
|
|
|
|
cd->fp_chop_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_ctx,
|
|
|
|
cd->content + cd->fp_chop_offset,
|
|
|
|
cd->fp_chop_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
}
|
|
|
|
/* tell matcher we are inspecting stream */
|
|
|
|
s->flags |= SIG_FLAG_MPM_STREAM;
|
|
|
|
s->mpm_stream_pattern_id_div_8 = cd->id / 8;
|
|
|
|
s->mpm_stream_pattern_id_mod_8 = 1 << (cd->id % 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
|
|
|
|
cd->avoid_double_check = 1;
|
|
|
|
/* see if we can bypass the match validation for this pattern */
|
|
|
|
} else {
|
|
|
|
if (!(cd->flags & DETECT_CONTENT_RELATIVE_NEXT) &&
|
|
|
|
!(cd->flags & DETECT_CONTENT_DEPTH) &&
|
|
|
|
!(cd->flags & DETECT_CONTENT_OFFSET)) {
|
|
|
|
|
|
|
|
SigMatch *prev_sm = SigMatchGetLastSMFromLists(s, 2,
|
|
|
|
mpm_sm->type, mpm_sm->prev);
|
|
|
|
if (prev_sm != NULL) {
|
|
|
|
DetectContentData *prev_cd = (DetectContentData *)prev_sm->ctx;
|
|
|
|
if (!(prev_cd->flags & DETECT_CONTENT_RELATIVE_NEXT)) {
|
|
|
|
cd->avoid_double_check = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* else - if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) */
|
|
|
|
|
|
|
|
if (SignatureHasPacketContent(s) &&
|
|
|
|
(sgh->flags & SIG_GROUP_HAVECONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_COPY))) {
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_ctx,
|
|
|
|
cd->content, cd->content_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_ctx,
|
|
|
|
cd->content, cd->content_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
}
|
|
|
|
/* tell matcher we are inspecting packet */
|
|
|
|
s->flags |= SIG_FLAG_MPM_PACKET;
|
|
|
|
s->mpm_pattern_id_div_8 = cd->id / 8;
|
|
|
|
s->mpm_pattern_id_mod_8 = 1 << (cd->id % 8);
|
|
|
|
}
|
|
|
|
if (SignatureHasStreamContent(s) &&
|
|
|
|
(sgh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sgh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY))) {
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (cd->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_stream_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_stream_ctx,
|
|
|
|
cd->content, cd->content_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_stream_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_stream_ctx,
|
|
|
|
cd->content, cd->content_len,
|
|
|
|
0, 0, cd->id, s->num, flags);
|
|
|
|
}
|
|
|
|
/* tell matcher we are inspecting stream */
|
|
|
|
s->flags |= SIG_FLAG_MPM_STREAM;
|
|
|
|
s->mpm_stream_pattern_id_div_8 = cd->id / 8;
|
|
|
|
s->mpm_stream_pattern_id_mod_8 = 1 << (cd->id % 8);
|
|
|
|
}
|
|
|
|
if (cd->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id);
|
|
|
|
s->flags |= SIG_FLAG_MPM_NEGCONTENT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
} /* case DETECT_CONTENT */
|
|
|
|
case DETECT_URICONTENT:
|
|
|
|
{
|
|
|
|
ud = (DetectUricontentData *)mpm_sm->ctx;
|
|
|
|
if (ud->flags & DETECT_URICONTENT_FAST_PATTERN_CHOP) {
|
|
|
|
/* add the content to the "uri" mpm */
|
|
|
|
if (ud->flags & DETECT_URICONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_ctx,
|
|
|
|
ud->content + ud->fp_chop_offset,
|
|
|
|
ud->fp_chop_len,
|
|
|
|
0, 0, ud->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_ctx,
|
|
|
|
ud->content + ud->fp_chop_offset,
|
|
|
|
ud->fp_chop_len,
|
|
|
|
0, 0, ud->id, s->num, flags);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ud->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
|
|
|
|
ud->avoid_double_check = 1;
|
|
|
|
/* see if we can bypass the match validation for this pattern */
|
|
|
|
} else {
|
|
|
|
if (!(ud->flags & DETECT_CONTENT_RELATIVE_NEXT) &&
|
|
|
|
!(ud->flags & DETECT_CONTENT_DEPTH) &&
|
|
|
|
!(ud->flags & DETECT_CONTENT_OFFSET)) {
|
|
|
|
|
|
|
|
SigMatch *prev_sm = SigMatchGetLastSMFromLists(s, 2,
|
|
|
|
mpm_sm->type, mpm_sm->prev);
|
|
|
|
if (prev_sm != NULL) {
|
|
|
|
DetectContentData *prev_ud = (DetectContentData *)prev_sm->ctx;
|
|
|
|
if (!(prev_ud->flags & DETECT_CONTENT_RELATIVE_NEXT)) {
|
|
|
|
ud->avoid_double_check = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* else - if (ud->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) */
|
|
|
|
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (ud->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_uri_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_uri_ctx,
|
|
|
|
ud->content, ud->content_len,
|
|
|
|
0, 0, ud->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_uri_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_uri_ctx,
|
|
|
|
ud->content, ud->content_len,
|
|
|
|
0, 0, ud->id, s->num, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* tell matcher we are inspecting uri */
|
|
|
|
s->flags |= SIG_FLAG_MPM_URICONTENT;
|
|
|
|
s->mpm_uripattern_id = ud->id;
|
|
|
|
if (ud->flags & DETECT_URICONTENT_NEGATED)
|
|
|
|
s->flags |= SIG_FLAG_MPM_URICONTENT_NEG;
|
|
|
|
|
|
|
|
break;
|
|
|
|
} /* case DETECT_URICONTENT */
|
|
|
|
} /* switch (mpm_sm->type) */
|
|
|
|
|
|
|
|
SCLogDebug("%"PRIu32" adding co->id %"PRIu32" to the mpm phase (s->num %"PRIu32")", s->id, co->id, s->num);
|
|
|
|
} else {
|
|
|
|
SCLogDebug("%"PRIu32" no mpm pattern selected", s->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Setup the content portion of the sig group head */
|
|
|
|
static int PatternMatchPreprarePopulateMpmPacket(DetectEngineCtx *de_ctx, SigGroupHead *sgh) {
|
|
|
|
uint32_t sig;
|
|
|
|
uint32_t *fast_pattern = NULL;
|
|
|
|
|
|
|
|
fast_pattern = (uint32_t *)SCMalloc(sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
if (fast_pattern == NULL)
|
|
|
|
return -1;
|
|
|
|
memset(fast_pattern, 0, sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
|
|
|
|
HashTable *ht = HashTableInit(4096, ContentHashFunc, ContentHashCompareFunc, ContentHashFree);
|
Memory leak cleanup in detectors
Hello,
I ran the code through an analysis program and found several leaks that
should be cleaned up.
*In src/detect-engine-address-ipv4.c at line 472, the test for ag == NULL
will never be true since that is the loop entry test.
*In src/detect-engine-port.c at line 1133, the test for p == NULL will
never be true since that is the loop entry test.
*In src/detect-engine-mpm.c at line 263 is a return without freeing
fast_pattern
*In src/detect-ack.c at line 80 and 85, data catches the return from malloc.
One of them should be deleted.
*In src/detect-seq.c at line 81 and 86, data catches the return from malloc.
One of them should be deleted.
*In src/detect-content.c at line 749, many of the paths that lead to the error
exit still has temp pointing to allocated memory. To clean this up, temp
should be set to NULL if not immediately assigning and new value.
*In src/detect-uricontent.c at line 319, both cd and str needto be freed. At
lines 344, str needs to be freed. And at line 347 str and temp need to be
freed.
*In src/detect-flowbits.c at line 231 and 235, str was not being freed. cd was
not being freed at line 235.
*In src/detect-flowvar.c at line 127, str was not being freed. At line 194, cd
and str were not being freed.
*In src/detect-flowint.c at line 277, sfd was not being freed. At line 315, str
was not being freed.
*In src/detect-pktvar.c at line 121, str was not being freed. At line 188, str
and cd was not being freed.
*In src/detect-pcre.c at line 389, there is an extra free of "re" that should
be deleted.
*In src/detect-depth.c at line 42 & 48, str has not been freed.
*In src/detect-distance.c at line 49 and 55, str has not been freed
*In src/detect-offset.c at line 45, str has not been freed.
The patch below fixes these issues.
-Steve
16 years ago
|
|
|
if (ht == NULL) {
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
return -1;
|
Memory leak cleanup in detectors
Hello,
I ran the code through an analysis program and found several leaks that
should be cleaned up.
*In src/detect-engine-address-ipv4.c at line 472, the test for ag == NULL
will never be true since that is the loop entry test.
*In src/detect-engine-port.c at line 1133, the test for p == NULL will
never be true since that is the loop entry test.
*In src/detect-engine-mpm.c at line 263 is a return without freeing
fast_pattern
*In src/detect-ack.c at line 80 and 85, data catches the return from malloc.
One of them should be deleted.
*In src/detect-seq.c at line 81 and 86, data catches the return from malloc.
One of them should be deleted.
*In src/detect-content.c at line 749, many of the paths that lead to the error
exit still has temp pointing to allocated memory. To clean this up, temp
should be set to NULL if not immediately assigning and new value.
*In src/detect-uricontent.c at line 319, both cd and str needto be freed. At
lines 344, str needs to be freed. And at line 347 str and temp need to be
freed.
*In src/detect-flowbits.c at line 231 and 235, str was not being freed. cd was
not being freed at line 235.
*In src/detect-flowvar.c at line 127, str was not being freed. At line 194, cd
and str were not being freed.
*In src/detect-flowint.c at line 277, sfd was not being freed. At line 315, str
was not being freed.
*In src/detect-pktvar.c at line 121, str was not being freed. At line 188, str
and cd was not being freed.
*In src/detect-pcre.c at line 389, there is an extra free of "re" that should
be deleted.
*In src/detect-depth.c at line 42 & 48, str has not been freed.
*In src/detect-distance.c at line 49 and 55, str has not been freed
*In src/detect-offset.c at line 45, str has not been freed.
The patch below fixes these issues.
-Steve
16 years ago
|
|
|
}
|
|
|
|
|
|
|
|
/* add all the contents to a counting hash */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (SignatureHasPacketContent(s) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cnt = 0;
|
|
|
|
SigMatch *sm;
|
|
|
|
|
|
|
|
/* get the total no of patterns in this Signature, as well as find out
|
|
|
|
* if we have a fast_pattern set in this Signature */
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *co = (DetectContentData *)sm->ctx;
|
|
|
|
if (co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
|
|
|
|
/* special handling of fast pattern keyword */
|
|
|
|
if (co->flags & DETECT_CONTENT_FAST_PATTERN) {
|
|
|
|
fast_pattern[sig] = 1;
|
|
|
|
SCLogDebug("sig %"PRIu32" has a fast pattern, id %"PRIu32"", s->id, co->id);
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
if (HashTableAdd(ht, ch, 0) < 0)
|
|
|
|
printf("Add hash failed\n");
|
|
|
|
} else {
|
|
|
|
lookup_ch->cnt++;
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fast_pattern[sig] == 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *co = (DetectContentData *)sm->ctx;
|
|
|
|
if (co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (co->content_len < sgh->mpm_content_maxlen) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (cnt == 1) {
|
|
|
|
SCLogDebug("sig has just one pattern, so we know we will "
|
|
|
|
"use it in the mpm phase.");
|
|
|
|
ch->use = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
int r = HashTableAdd(ht, ch, 0);
|
|
|
|
if (r < 0)
|
|
|
|
printf("Add hash failed\n");
|
|
|
|
} else {
|
|
|
|
lookup_ch->use = ch->use;
|
|
|
|
|
|
|
|
lookup_ch->cnt++;
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now determine which one to add to the mpm phase */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (SignatureHasPacketContent(s) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *mpm_ch = NULL;
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *co = (DetectContentData *)sm->ctx;
|
|
|
|
if (co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* skip in case of:
|
|
|
|
* 1. we expect a fastpattern but this isn't it
|
|
|
|
* 2. we have a smaller content than mpm_content_maxlen */
|
|
|
|
if (fast_pattern[sig] == 1) {
|
|
|
|
if (!(co->flags & DETECT_CONTENT_FAST_PATTERN)) {
|
|
|
|
SCLogDebug("not a fast pattern %"PRIu32"", co->id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SCLogDebug("fast pattern %"PRIu32"", co->id);
|
|
|
|
|
|
|
|
} else if (co->content_len < sgh->mpm_content_maxlen) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCLogDebug("lookup_ch->use %u, cnt %u", lookup_ch->use, lookup_ch->cnt);
|
|
|
|
|
|
|
|
if (mpm_ch == NULL) {
|
|
|
|
SCLogDebug("mpm_ch == NULL, so selecting lookup_ch->ptr->id %"PRIu32"", lookup_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
} else {
|
|
|
|
uint32_t ls = PatternStrength(lookup_ch->ptr->content,lookup_ch->ptr->content_len);
|
|
|
|
uint32_t ss = PatternStrength(mpm_ch->ptr->content,mpm_ch->ptr->content_len);
|
|
|
|
if (ls > ss) {
|
|
|
|
SCLogDebug("lookup_ch->ptr->id %"PRIu32" selected over %"PRIu32"", lookup_ch->ptr->id, mpm_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
}
|
|
|
|
else if (ls == ss) {
|
|
|
|
/* if 2 patterns are of equal strength, we pick the longest */
|
|
|
|
if (lookup_ch->ptr->content_len > mpm_ch->ptr->content_len) {
|
|
|
|
SCLogDebug("lookup_ch->ptr->id %"PRIu32" selected over %"PRIu32" as the first is longer",
|
|
|
|
lookup_ch->ptr->id, mpm_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SCLogDebug("sticking with mpm_ch");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now add the mpm_ch to the mpm ctx */
|
|
|
|
if (mpm_ch != NULL) {
|
|
|
|
DetectContentData *co = mpm_ch->ptr;
|
|
|
|
uint16_t offset = s->flags & SIG_FLAG_RECURSIVE ? 0 : co->offset;
|
|
|
|
uint16_t depth = s->flags & SIG_FLAG_RECURSIVE ? 0 : co->depth;
|
|
|
|
offset = mpm_ch->cnt ? 0 : offset;
|
|
|
|
depth = mpm_ch->cnt ? 0 : depth;
|
|
|
|
uint8_t flags = 0;
|
|
|
|
char scan_negated = 0;
|
|
|
|
|
|
|
|
/* see if our content is actually negated */
|
|
|
|
SigMatch *tmpsm = s->sm_lists[DETECT_SM_LIST_PMATCH];
|
|
|
|
for ( ; tmpsm != NULL; tmpsm = tmpsm->next) {
|
|
|
|
if (tmpsm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *tmp = (DetectContentData *)tmpsm->ctx;
|
|
|
|
if (tmp == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (co->id == tmp->id) {
|
|
|
|
if (tmp->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
scan_negated = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (co->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_ctx,
|
|
|
|
co->content + co->fp_chop_offset,
|
|
|
|
co->fp_chop_len,
|
|
|
|
0, 0, co->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_ctx,
|
|
|
|
co->content + co->fp_chop_offset,
|
|
|
|
co->fp_chop_len,
|
|
|
|
0, 0, co->id, s->num, flags);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (co->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
|
|
|
|
co->avoid_double_check = 1;
|
|
|
|
/* see if we can bypass the match validation for this pattern */
|
|
|
|
} else {
|
|
|
|
if (!(co->flags & DETECT_CONTENT_RELATIVE_NEXT)) {
|
|
|
|
SigMatch *tmp_sm = s->sm_lists[DETECT_SM_LIST_PMATCH];
|
|
|
|
for ( ; tmp_sm != NULL; tmp_sm = tmp_sm->next) {
|
|
|
|
if (tmp_sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *tmp_co = (DetectContentData *)tmpsm->ctx;
|
|
|
|
if (tmp_co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (co->id == tmp_co->id)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SigMatch *prev_sm = SigMatchGetLastSMFromLists(s, 2,
|
|
|
|
DETECT_CONTENT, tmp_sm->prev);
|
|
|
|
if (prev_sm != NULL) {
|
|
|
|
DetectContentData *prev_co = (DetectContentData *)prev_sm->ctx;
|
|
|
|
if (!(prev_co->flags & DETECT_CONTENT_RELATIVE_NEXT)) {
|
|
|
|
co->avoid_double_check = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} /* else - if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) */
|
|
|
|
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (co->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPatternNocase(sgh->mpm_ctx,
|
|
|
|
co->content, co->content_len,
|
|
|
|
offset, depth, co->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_ctx->mpm_type].
|
|
|
|
AddPattern(sgh->mpm_ctx,
|
|
|
|
co->content, co->content_len,
|
|
|
|
offset, depth, co->id, s->num, flags);
|
|
|
|
}
|
|
|
|
} /* else - if (co->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) */
|
|
|
|
|
|
|
|
/* tell matcher we are inspecting packet */
|
|
|
|
s->flags |= SIG_FLAG_MPM_PACKET;
|
|
|
|
|
|
|
|
s->mpm_pattern_id_mod_8 = 1<<(co->id%8);
|
|
|
|
s->mpm_pattern_id_div_8 = co->id/8;
|
|
|
|
if (scan_negated) {
|
|
|
|
SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id);
|
|
|
|
s->flags |= SIG_FLAG_MPM_NEGCONTENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCLogDebug("%"PRIu32" adding co->id %"PRIu32" to the mpm phase (s->num %"PRIu32")", s->id, co->id, s->num);
|
|
|
|
} else {
|
|
|
|
SCLogDebug("%"PRIu32" no mpm pattern selected", s->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
|
|
|
|
HashTableFree(ht);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
|
|
|
|
if (ht != NULL)
|
|
|
|
HashTableFree(ht);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Setup the content portion of the sig group head */
|
|
|
|
static int PatternMatchPreprarePopulateMpmStream(DetectEngineCtx *de_ctx, SigGroupHead *sgh) {
|
|
|
|
uint32_t sig;
|
|
|
|
uint32_t *fast_pattern = NULL;
|
|
|
|
|
|
|
|
fast_pattern = (uint32_t *)SCMalloc(sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
if (fast_pattern == NULL)
|
|
|
|
return -1;
|
|
|
|
memset(fast_pattern, 0, sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
|
|
|
|
HashTable *ht = HashTableInit(4096, ContentHashFunc, ContentHashCompareFunc, ContentHashFree);
|
|
|
|
if (ht == NULL) {
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add all the contents to a counting hash */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (SignatureHasStreamContent(s) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cnt = 0;
|
|
|
|
SigMatch *sm;
|
|
|
|
|
|
|
|
/* get the total no of patterns in this Signature, as well as find out
|
|
|
|
* if we have a fast_pattern set in this Signature */
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *co = (DetectContentData *)sm->ctx;
|
|
|
|
if (co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
|
|
|
|
/* special handling of fast pattern keyword */
|
|
|
|
if (co->flags & DETECT_CONTENT_FAST_PATTERN) {
|
|
|
|
fast_pattern[sig] = 1;
|
|
|
|
SCLogDebug("sig %"PRIu32" has a fast pattern, id %"PRIu32"", s->id, co->id);
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
if (HashTableAdd(ht, ch, 0) < 0)
|
|
|
|
printf("Add hash failed\n");
|
|
|
|
} else {
|
|
|
|
lookup_ch->cnt++;
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fast_pattern[sig] == 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *co = (DetectContentData *)sm->ctx;
|
|
|
|
if (co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (co->content_len < sgh->mpm_content_maxlen) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (cnt == 1) {
|
|
|
|
SCLogDebug("sig has just one pattern, so we know we will "
|
|
|
|
"use it in the mpm phase.");
|
|
|
|
ch->use = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
int r = HashTableAdd(ht, ch, 0);
|
|
|
|
if (r < 0)
|
|
|
|
printf("Add hash failed\n");
|
|
|
|
} else {
|
|
|
|
lookup_ch->use = ch->use;
|
|
|
|
|
|
|
|
lookup_ch->cnt++;
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now determine which one to add to the mpm phase */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL || s->sm_lists[DETECT_SM_LIST_PMATCH] == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (SignatureHasStreamContent(s) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *mpm_ch = NULL;
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *co = (DetectContentData *)sm->ctx;
|
|
|
|
if (co == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* skip in case of:
|
|
|
|
* 1. we expect a fastpattern but this isn't it
|
|
|
|
* 2. we have a smaller content than mpm_content_maxlen */
|
|
|
|
if (fast_pattern[sig] == 1) {
|
|
|
|
if (!(co->flags & DETECT_CONTENT_FAST_PATTERN)) {
|
|
|
|
SCLogDebug("not a fast pattern %"PRIu32"", co->id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SCLogDebug("fast pattern %"PRIu32"", co->id);
|
|
|
|
} else if (co->content_len < sgh->mpm_streamcontent_maxlen) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCLogDebug("lookup_ch->use %u, cnt %u", lookup_ch->use, lookup_ch->cnt);
|
|
|
|
|
|
|
|
if (mpm_ch == NULL) {
|
|
|
|
SCLogDebug("mpm_ch == NULL, so selecting lookup_ch->ptr->id %"PRIu32"", lookup_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
} else {
|
|
|
|
uint32_t ls = PatternStrength(lookup_ch->ptr->content,lookup_ch->ptr->content_len);
|
|
|
|
uint32_t ss = PatternStrength(mpm_ch->ptr->content,mpm_ch->ptr->content_len);
|
|
|
|
if (ls > ss) {
|
|
|
|
SCLogDebug("lookup_ch->ptr->id %"PRIu32" selected over %"PRIu32"", lookup_ch->ptr->id, mpm_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
}
|
|
|
|
else if (ls == ss) {
|
|
|
|
/* if 2 patterns are of equal strength, we pick the longest */
|
|
|
|
if (lookup_ch->ptr->content_len > mpm_ch->ptr->content_len) {
|
|
|
|
SCLogDebug("lookup_ch->ptr->id %"PRIu32" selected over %"PRIu32" as the first is longer",
|
|
|
|
lookup_ch->ptr->id, mpm_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SCLogDebug("sticking with mpm_ch");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now add the mpm_ch to the mpm ctx */
|
|
|
|
if (mpm_ch != NULL) {
|
|
|
|
DetectContentData *co = mpm_ch->ptr;
|
|
|
|
uint16_t offset = s->flags & SIG_FLAG_RECURSIVE ? 0 : co->offset;
|
|
|
|
uint16_t depth = s->flags & SIG_FLAG_RECURSIVE ? 0 : co->depth;
|
|
|
|
offset = mpm_ch->cnt ? 0 : offset;
|
|
|
|
depth = mpm_ch->cnt ? 0 : depth;
|
|
|
|
uint8_t flags = 0;
|
|
|
|
char scan_negated = 0;
|
|
|
|
|
|
|
|
/* see if our content is actually negated */
|
|
|
|
SigMatch *tmpsm = s->sm_lists[DETECT_SM_LIST_PMATCH];
|
|
|
|
for ( ; tmpsm != NULL; tmpsm = tmpsm->next) {
|
|
|
|
if (tmpsm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *tmp = (DetectContentData *)tmpsm->ctx;
|
|
|
|
if (tmp == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (co->id == tmp->id) {
|
|
|
|
if (tmp->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
scan_negated = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SCLogDebug("mpm_stream_ctx %p", sgh->mpm_stream_ctx);
|
|
|
|
/* add the content to the "stream" mpm */
|
|
|
|
if (co->flags & DETECT_CONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_stream_ctx->mpm_type].AddPatternNocase(sgh->mpm_stream_ctx,
|
|
|
|
co->content, co->content_len, offset, depth, co->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_stream_ctx->mpm_type].AddPattern(sgh->mpm_stream_ctx,
|
|
|
|
co->content, co->content_len, offset, depth, co->id, s->num, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tell matcher we are inspecting stream */
|
|
|
|
s->flags |= SIG_FLAG_MPM_STREAM;
|
|
|
|
|
|
|
|
s->mpm_stream_pattern_id_div_8 = co->id/8;
|
|
|
|
s->mpm_stream_pattern_id_mod_8 = 1<<(co->id%8);
|
|
|
|
if (scan_negated) {
|
|
|
|
SCLogDebug("flagging sig %"PRIu32" to be looking for negated mpm", s->id);
|
|
|
|
s->flags |= SIG_FLAG_MPM_NEGCONTENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCLogDebug("%"PRIu32" adding co->id %"PRIu32" to the mpm phase (s->num %"PRIu32")", s->id, co->id, s->num);
|
|
|
|
} else {
|
|
|
|
SCLogDebug("%"PRIu32" no mpm pattern selected", s->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
|
|
|
|
HashTableFree(ht);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
|
|
|
|
if (ht != NULL)
|
|
|
|
HashTableFree(ht);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Setup the content portion of the sig group head */
|
|
|
|
static int PatternMatchPreprarePopulateMpmUri(DetectEngineCtx *de_ctx, SigGroupHead *sgh) {
|
|
|
|
uint32_t sig;
|
|
|
|
#if 0
|
|
|
|
uint32_t *fast_pattern = NULL;
|
|
|
|
fast_pattern = (uint32_t *)SCMalloc(sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
if (fast_pattern == NULL)
|
|
|
|
return -1;
|
|
|
|
memset(fast_pattern, 0, sgh->sig_cnt * sizeof(uint32_t));
|
|
|
|
#endif
|
|
|
|
HashTable *ht = HashTableInit(4096, UricontentHashFunc, UricontentHashCompareFunc, UricontentHashFree);
|
|
|
|
if (ht == NULL) {
|
|
|
|
#if 0
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add all the contents to a counting hash */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int cnt = 0;
|
|
|
|
SigMatch *sm;
|
|
|
|
|
|
|
|
/* get the total no of patterns in this Signature, as well as find out
|
|
|
|
* if we have a fast_pattern set in this Signature */
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_URICONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
if (ud == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
#if 0
|
|
|
|
/* special handling of fast pattern keyword */
|
|
|
|
if (co->flags & DETECT_URICONTENT_FAST_PATTERN) {
|
|
|
|
fast_pattern[sig] = 1;
|
|
|
|
SCLogDebug("sig %"PRIu32" has a fast pattern, id %"PRIu32"", s->id, co->id);
|
|
|
|
|
|
|
|
ContentHash *ch = ContentHashAlloc(co);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ContentHash *lookup_ch = (ContentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
if (HashTableAdd(ht, ch, 0) < 0)
|
|
|
|
printf("Add hash failed\n");
|
|
|
|
} else {
|
|
|
|
lookup_ch->cnt++;
|
|
|
|
ContentHashFree(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
if (fast_pattern[sig] == 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_URICONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
if (ud == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ud->content_len < sgh->mpm_uricontent_maxlen) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
UricontentHash *ch = UricontentHashAlloc(ud);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (cnt == 1) {
|
|
|
|
SCLogDebug("sig has just one pattern, so we know we will "
|
|
|
|
"use it in the mpm phase.");
|
|
|
|
ch->use = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
UricontentHash *lookup_ch = (UricontentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
int r = HashTableAdd(ht, ch, 0);
|
|
|
|
if (r < 0)
|
|
|
|
printf("Add hash failed\n");
|
|
|
|
} else {
|
|
|
|
lookup_ch->use = ch->use;
|
|
|
|
|
|
|
|
lookup_ch->cnt++;
|
|
|
|
UricontentHashFree(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now determine which one to add to the mpm phase */
|
|
|
|
for (sig = 0; sig < sgh->sig_cnt; sig++) {
|
|
|
|
Signature *s = sgh->match_array[sig];
|
|
|
|
if (s == NULL || s->sm_lists[DETECT_SM_LIST_UMATCH] == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
UricontentHash *mpm_ch = NULL;
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_URICONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
if (ud == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* skip in case of:
|
|
|
|
* 1. we expect a fastpattern but this isn't it
|
|
|
|
* 2. we have a smaller content than mpm_content_maxlen */
|
|
|
|
#if 0
|
|
|
|
if (fast_pattern[sig] == 1) {
|
|
|
|
if (!(co->flags & DETECT_CONTENT_FAST_PATTERN)) {
|
|
|
|
SCLogDebug("not a fast pattern %"PRIu32"", co->id);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
SCLogDebug("fast pattern %"PRIu32"", co->id);
|
|
|
|
|
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
if (ud->content_len < sgh->mpm_uricontent_maxlen) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
UricontentHash *ch = UricontentHashAlloc(ud);
|
|
|
|
if (ch == NULL)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
UricontentHash *lookup_ch = (UricontentHash *)HashTableLookup(ht, ch, 0);
|
|
|
|
if (lookup_ch == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCLogDebug("lookup_ch->use %u, cnt %u", lookup_ch->use, lookup_ch->cnt);
|
|
|
|
|
|
|
|
if (mpm_ch == NULL) {
|
|
|
|
SCLogDebug("mpm_ch == NULL, so selecting lookup_ch->ptr->id %"PRIu32"", lookup_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
} else {
|
|
|
|
uint32_t ls = PatternStrength(lookup_ch->ptr->content,lookup_ch->ptr->content_len);
|
|
|
|
uint32_t ss = PatternStrength(mpm_ch->ptr->content,mpm_ch->ptr->content_len);
|
|
|
|
if (ls > ss) {
|
|
|
|
SCLogDebug("lookup_ch->ptr->id %"PRIu32" selected over %"PRIu32"", lookup_ch->ptr->id, mpm_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
}
|
|
|
|
else if (ls == ss) {
|
|
|
|
/* if 2 patterns are of equal strength, we pick the longest */
|
|
|
|
if (lookup_ch->ptr->content_len > mpm_ch->ptr->content_len) {
|
|
|
|
SCLogDebug("lookup_ch->ptr->id %"PRIu32" selected over %"PRIu32" as the first is longer",
|
|
|
|
lookup_ch->ptr->id, mpm_ch->ptr->id);
|
|
|
|
mpm_ch = lookup_ch;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SCLogDebug("sticking with mpm_ch");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UricontentHashFree(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now add the mpm_ch to the mpm ctx */
|
|
|
|
if (mpm_ch != NULL) {
|
|
|
|
DetectUricontentData *ud = mpm_ch->ptr;
|
|
|
|
uint8_t flags = 0;
|
|
|
|
#if 0
|
|
|
|
/* see if our content is actually negated */
|
|
|
|
SigMatch *tmpsm = s->sm_lists[DETECT_SM_LIST_PMATCH];
|
|
|
|
for ( ; tmpsm != NULL; tmpsm = tmpsm->next) {
|
|
|
|
if (tmpsm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *tmp = (DetectContentData *)tmpsm->ctx;
|
|
|
|
if (tmp == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (co->id == tmp->id) {
|
|
|
|
if (tmp->flags & DETECT_CONTENT_NEGATED) {
|
|
|
|
scan_negated = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* add the content to the "packet" mpm */
|
|
|
|
if (ud->flags & DETECT_URICONTENT_NOCASE) {
|
|
|
|
mpm_table[sgh->mpm_uri_ctx->mpm_type].AddPatternNocase(sgh->mpm_uri_ctx,
|
|
|
|
ud->content, ud->content_len, 0, 0, ud->id, s->num, flags);
|
|
|
|
} else {
|
|
|
|
mpm_table[sgh->mpm_uri_ctx->mpm_type].AddPattern(sgh->mpm_uri_ctx,
|
|
|
|
ud->content, ud->content_len, 0, 0, ud->id,
|
|
|
|
s->num, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
s->mpm_uripattern_id = ud->id;
|
|
|
|
|
|
|
|
SCLogDebug("%"PRIu32" adding ud->id %"PRIu32" to the mpm phase (s->num %"PRIu32")", s->id, ud->id, s->num);
|
|
|
|
} else {
|
|
|
|
SCLogDebug("%"PRIu32" no mpm pattern selected", s->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
#endif
|
|
|
|
HashTableFree(ht);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
#if 0
|
|
|
|
if (fast_pattern != NULL)
|
|
|
|
SCFree(fast_pattern);
|
|
|
|
#endif
|
|
|
|
if (ht != NULL)
|
|
|
|
HashTableFree(ht);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Prepare the pattern matcher ctx in a sig group head.
|
|
|
|
*
|
|
|
|
* \todo determine if a content match can set the 'single' flag
|
|
|
|
* \todo do error checking
|
|
|
|
* \todo rewrite the COPY stuff
|
|
|
|
*/
|
|
|
|
int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
|
|
|
|
{
|
|
|
|
Signature *s = NULL;
|
|
|
|
SigMatch *sm = NULL;
|
|
|
|
uint32_t has_co_packet = 0; /**< our sgh has packet payload inspecting content */
|
|
|
|
uint32_t has_co_stream = 0; /**< our sgh has stream inspecting content */
|
|
|
|
uint32_t has_co_uri = 0; /**< our sgh has uri inspecting content */
|
|
|
|
uint32_t cnt = 0;
|
|
|
|
uint32_t sig = 0;
|
|
|
|
uint8_t populate_mpm_flags = 0;
|
|
|
|
|
|
|
|
if (!(sh->flags & SIG_GROUP_HEAD_MPM_COPY))
|
|
|
|
sh->mpm_content_maxlen = 0;
|
|
|
|
|
|
|
|
if (!(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY))
|
|
|
|
sh->mpm_uricontent_maxlen = 0;
|
|
|
|
|
|
|
|
if (!(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY))
|
|
|
|
sh->mpm_streamcontent_maxlen = 0;
|
|
|
|
|
|
|
|
/* see if this head has content and/or uricontent */
|
|
|
|
for (sig = 0; sig < sh->sig_cnt; sig++) {
|
|
|
|
s = sh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (SignatureHasPacketContent(s) == 1) {
|
|
|
|
has_co_packet = 1;
|
|
|
|
}
|
|
|
|
if (SignatureHasStreamContent(s) == 1) {
|
|
|
|
has_co_stream = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type == DETECT_URICONTENT) {
|
|
|
|
has_co_uri = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_co_packet > 0) {
|
|
|
|
sh->flags |= SIG_GROUP_HAVECONTENT;
|
|
|
|
}
|
|
|
|
if (has_co_stream > 0) {
|
|
|
|
sh->flags |= SIG_GROUP_HAVESTREAMCONTENT;
|
|
|
|
}
|
|
|
|
if (has_co_uri > 0) {
|
|
|
|
sh->flags |= SIG_GROUP_HAVEURICONTENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* intialize contexes */
|
|
|
|
populate_mpm_flags |= POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS;
|
|
|
|
if (sh->flags & SIG_GROUP_HAVECONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) {
|
|
|
|
populate_mpm_flags &= ~POPULATE_MPM_AVOID_PACKET_MPM_PATTERNS;
|
|
|
|
if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) {
|
|
|
|
sh->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_packet);
|
|
|
|
} else {
|
|
|
|
sh->mpm_ctx = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef __SC_CUDA_SUPPORT__
|
|
|
|
MpmInitCtx(sh->mpm_ctx, de_ctx->mpm_matcher, -1);
|
|
|
|
#else
|
|
|
|
MpmInitCtx(sh->mpm_ctx, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
populate_mpm_flags |= POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS;
|
|
|
|
if (sh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) {
|
|
|
|
populate_mpm_flags &= ~POPULATE_MPM_AVOID_STREAM_MPM_PATTERNS;
|
|
|
|
if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) {
|
|
|
|
sh->mpm_stream_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_stream);
|
|
|
|
} else {
|
|
|
|
sh->mpm_stream_ctx = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef __SC_CUDA_SUPPORT__
|
|
|
|
MpmInitCtx(sh->mpm_stream_ctx, de_ctx->mpm_matcher, -1);
|
|
|
|
#else
|
|
|
|
MpmInitCtx(sh->mpm_stream_ctx, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
populate_mpm_flags |= POPULATE_MPM_AVOID_URI_MPM_PATTERNS;
|
|
|
|
if (sh->flags & SIG_GROUP_HAVEURICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
|
|
|
|
populate_mpm_flags &= ~POPULATE_MPM_AVOID_URI_MPM_PATTERNS;
|
|
|
|
if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) {
|
|
|
|
sh->mpm_uri_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx->sgh_mpm_context_uri);
|
|
|
|
} else {
|
|
|
|
sh->mpm_uri_ctx = MpmFactoryGetMpmCtxForProfile(MPM_CTX_FACTORY_UNIQUE_CONTEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef __SC_CUDA_SUPPORT__
|
|
|
|
MpmInitCtx(sh->mpm_uri_ctx, de_ctx->mpm_matcher, -1);
|
|
|
|
#else
|
|
|
|
MpmInitCtx(sh->mpm_uri_ctx, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for each signature in this group do */
|
|
|
|
for (sig = 0; sig < sh->sig_cnt; sig++) {
|
|
|
|
s = sh->match_array[sig];
|
|
|
|
if (s == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cnt++;
|
|
|
|
|
|
|
|
char content_added = 0;
|
|
|
|
char uricontent_added = 0;
|
|
|
|
char stream_content_added = 0;
|
|
|
|
uint16_t content_maxlen = 0, stream_content_maxlen = 0;
|
|
|
|
uint16_t content_minlen = 0, stream_content_minlen = 0;
|
|
|
|
uint16_t uricontent_maxlen = 0;
|
|
|
|
uint16_t uricontent_minlen = 0;
|
|
|
|
|
|
|
|
SigMatch *sm;
|
|
|
|
|
|
|
|
/* determine the length of the longest pattern */
|
|
|
|
if (sh->flags & SIG_GROUP_HAVECONTENT &&
|
|
|
|
!(sh->flags & SIG_GROUP_HEAD_MPM_COPY))
|
|
|
|
{
|
|
|
|
if (SignatureHasPacketContent(s) == 1) {
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *cd = (DetectContentData *)sm->ctx;
|
|
|
|
if (cd == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cd->content_len > content_maxlen)
|
|
|
|
content_maxlen = cd->content_len;
|
|
|
|
|
|
|
|
if (content_minlen == 0)
|
|
|
|
content_minlen = cd->content_len;
|
|
|
|
else if (cd->content_len < content_minlen)
|
|
|
|
content_minlen = cd->content_len;
|
|
|
|
|
|
|
|
if (!content_added) {
|
|
|
|
content_added = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content_added > 0) {
|
|
|
|
if (sh->mpm_content_maxlen == 0)
|
|
|
|
sh->mpm_content_maxlen = content_maxlen;
|
|
|
|
if (sh->mpm_content_maxlen > content_maxlen) {
|
|
|
|
SCLogDebug("sgh (%p) sh->mpm_content_maxlen %u set to %u",
|
|
|
|
sh, sh->mpm_content_maxlen, content_maxlen);
|
|
|
|
|
|
|
|
sh->mpm_content_maxlen = content_maxlen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sh->flags & SIG_GROUP_HAVESTREAMCONTENT &&
|
|
|
|
!(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY))
|
|
|
|
{
|
|
|
|
if (SignatureHasStreamContent(s) == 1) {
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_PMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_CONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectContentData *cd = (DetectContentData *)sm->ctx;
|
|
|
|
if (cd == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cd->content_len > stream_content_maxlen)
|
|
|
|
stream_content_maxlen = cd->content_len;
|
|
|
|
|
|
|
|
if (stream_content_minlen == 0)
|
|
|
|
stream_content_minlen = cd->content_len;
|
|
|
|
else if (cd->content_len < stream_content_minlen)
|
|
|
|
stream_content_minlen = cd->content_len;
|
|
|
|
|
|
|
|
if (!stream_content_added) {
|
|
|
|
stream_content_added = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stream_content_added > 0) {
|
|
|
|
if (sh->mpm_streamcontent_maxlen == 0)
|
|
|
|
sh->mpm_streamcontent_maxlen = stream_content_maxlen;
|
|
|
|
if (sh->mpm_streamcontent_maxlen > stream_content_maxlen) {
|
|
|
|
SCLogDebug("sgh (%p) sh->mpm_streamcontent_maxlen %u set to %u",
|
|
|
|
sh, sh->mpm_streamcontent_maxlen, stream_content_maxlen);
|
|
|
|
|
|
|
|
sh->mpm_streamcontent_maxlen = stream_content_maxlen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sh->flags & SIG_GROUP_HAVEURICONTENT &&
|
|
|
|
!(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY))
|
|
|
|
{
|
|
|
|
/* determine the length of the longest pattern */
|
|
|
|
for (sm = s->sm_lists[DETECT_SM_LIST_UMATCH]; sm != NULL; sm = sm->next) {
|
|
|
|
if (sm->type != DETECT_URICONTENT)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
DetectUricontentData *ud = (DetectUricontentData *)sm->ctx;
|
|
|
|
if (ud == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ud->content_len > uricontent_maxlen)
|
|
|
|
uricontent_maxlen = ud->content_len;
|
|
|
|
|
|
|
|
if (uricontent_minlen == 0)
|
|
|
|
uricontent_minlen = ud->content_len;
|
|
|
|
else if (ud->content_len < uricontent_minlen)
|
|
|
|
uricontent_minlen = ud->content_len;
|
|
|
|
|
|
|
|
if (!uricontent_added) {
|
|
|
|
uricontent_added = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uricontent_added) {
|
|
|
|
if (sh->mpm_uricontent_maxlen == 0)
|
|
|
|
sh->mpm_uricontent_maxlen = uricontent_maxlen;
|
|
|
|
if (sh->mpm_uricontent_maxlen > uricontent_maxlen)
|
|
|
|
sh->mpm_uricontent_maxlen = uricontent_maxlen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (sh->flags & SIG_GROUP_HAVECONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) ||
|
|
|
|
(sh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) ||
|
|
|
|
(sh->flags & SIG_GROUP_HAVEURICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) ) {
|
|
|
|
|
|
|
|
PatternMatchPreparePopulateMpm(de_ctx, sh);
|
|
|
|
|
|
|
|
if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) {
|
|
|
|
if (sh->mpm_ctx != NULL) {
|
|
|
|
if (sh->mpm_ctx->pattern_cnt == 0) {
|
|
|
|
sh->mpm_ctx = NULL;
|
|
|
|
} else {
|
|
|
|
if (sh->flags & SIG_GROUP_HAVECONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) {
|
|
|
|
if (mpm_table[sh->mpm_ctx->mpm_type].Prepare != NULL)
|
|
|
|
mpm_table[sh->mpm_ctx->mpm_type].Prepare(sh->mpm_ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sh->mpm_stream_ctx != NULL) {
|
|
|
|
if (sh->mpm_stream_ctx->pattern_cnt == 0) {
|
|
|
|
sh->mpm_stream_ctx = NULL;
|
|
|
|
} else {
|
|
|
|
if (sh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) {
|
|
|
|
if (mpm_table[sh->mpm_stream_ctx->mpm_type].Prepare != NULL)
|
|
|
|
mpm_table[sh->mpm_stream_ctx->mpm_type].Prepare(sh->mpm_stream_ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sh->mpm_uri_ctx != NULL) {
|
|
|
|
if (sh->mpm_uri_ctx->pattern_cnt == 0) {
|
|
|
|
sh->mpm_uri_ctx = NULL;
|
|
|
|
} else {
|
|
|
|
if (sh->flags & SIG_GROUP_HAVEURICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
|
|
|
|
if (mpm_table[sh->mpm_uri_ctx->mpm_type].Prepare != NULL)
|
|
|
|
mpm_table[sh->mpm_uri_ctx->mpm_type].Prepare(sh->mpm_uri_ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///* uricontent */
|
|
|
|
//if (sh->flags & SIG_GROUP_HAVEURICONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_URI_COPY)) {
|
|
|
|
// PatternMatchPreprarePopulateMpmUri(de_ctx, sh);
|
|
|
|
//
|
|
|
|
// if (mpm_table[sh->mpm_uri_ctx->mpm_type].Prepare != NULL) {
|
|
|
|
// if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) {
|
|
|
|
// mpm_table[sh->mpm_uri_ctx->mpm_type].Prepare(sh->mpm_uri_ctx);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// //sh->mpm_uri_ctx->PrintCtx(sh->mpm_uri_ctx);
|
|
|
|
//
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
///* content */
|
|
|
|
//if (sh->flags & SIG_GROUP_HAVECONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_COPY)) {
|
|
|
|
// PatternMatchPreprarePopulateMpmPacket(de_ctx, sh);
|
|
|
|
//
|
|
|
|
// if (mpm_table[sh->mpm_ctx->mpm_type].Prepare != NULL) {
|
|
|
|
// if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) {
|
|
|
|
// mpm_table[sh->mpm_ctx->mpm_type].Prepare(sh->mpm_ctx);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
///* stream content */
|
|
|
|
//if (sh->flags & SIG_GROUP_HAVESTREAMCONTENT && !(sh->flags & SIG_GROUP_HEAD_MPM_STREAM_COPY)) {
|
|
|
|
// PatternMatchPreprarePopulateMpmStream(de_ctx, sh);
|
|
|
|
// SCLogDebug("preparing mpm_stream_ctx %p", sh->mpm_stream_ctx);
|
|
|
|
// if (mpm_table[sh->mpm_stream_ctx->mpm_type].Prepare != NULL) {
|
|
|
|
// if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) {
|
|
|
|
// mpm_table[sh->mpm_stream_ctx->mpm_type].Prepare(sh->mpm_stream_ctx);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
//error:
|
|
|
|
/* XXX */
|
|
|
|
//return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Pattern ID Hash for sharing pattern id's
|
|
|
|
*
|
|
|
|
* A per detection engine hash to make sure each pattern has a unique
|
|
|
|
* global id but patterns that are the same share id's.
|
|
|
|
*/
|
|
|
|
typedef struct MpmPatternIdTableElmt_ {
|
|
|
|
uint8_t *pattern; /**< ptr to the pattern */
|
|
|
|
uint16_t pattern_len; /**< pattern len */
|
|
|
|
PatIntId id; /**< pattern id */
|
|
|
|
uint16_t dup_count; /**< duplicate count */
|
|
|
|
uint8_t sm_type; /**< SigMatch type */
|
|
|
|
} MpmPatternIdTableElmt;
|
|
|
|
|
|
|
|
/** \brief Hash compare func for MpmPatternId api
|
|
|
|
* \retval 1 patterns are the same
|
|
|
|
* \retval 0 patterns are not the same
|
|
|
|
**/
|
|
|
|
static char MpmPatternIdCompare(void *p1, uint16_t len1, void *p2, uint16_t len2) {
|
|
|
|
SCEnter();
|
|
|
|
BUG_ON(len1 < sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(len2 < sizeof(MpmPatternIdTableElmt));
|
|
|
|
|
|
|
|
MpmPatternIdTableElmt *e1 = (MpmPatternIdTableElmt *)p1;
|
|
|
|
MpmPatternIdTableElmt *e2 = (MpmPatternIdTableElmt *)p2;
|
|
|
|
|
|
|
|
if (e1->pattern_len != e2->pattern_len ||
|
|
|
|
e1->sm_type != e2->sm_type) {
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SCMemcmp(e1->pattern, e2->pattern, e1->pattern_len) != 0) {
|
|
|
|
SCReturnInt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCReturnInt(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Hash func for MpmPatternId api
|
|
|
|
* \retval hash hash value
|
|
|
|
*/
|
|
|
|
static uint32_t MpmPatternIdHashFunc(HashTable *ht, void *p, uint16_t len) {
|
|
|
|
SCEnter();
|
|
|
|
BUG_ON(len < sizeof(MpmPatternIdTableElmt));
|
|
|
|
|
|
|
|
MpmPatternIdTableElmt *e = (MpmPatternIdTableElmt *)p;
|
|
|
|
uint32_t hash = e->pattern_len;
|
|
|
|
uint16_t u = 0;
|
|
|
|
|
|
|
|
for (u = 0; u < e->pattern_len; u++) {
|
|
|
|
hash += e->pattern[u];
|
|
|
|
}
|
|
|
|
|
|
|
|
SCReturnUInt(hash % ht->array_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief free a MpmPatternIdTableElmt */
|
|
|
|
static void MpmPatternIdTableElmtFree(void *e) {
|
|
|
|
SCEnter();
|
|
|
|
MpmPatternIdTableElmt *c = (MpmPatternIdTableElmt *)e;
|
|
|
|
SCFree(c->pattern);
|
|
|
|
SCFree(c);
|
|
|
|
SCReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief alloc initialize the MpmPatternIdHash */
|
|
|
|
MpmPatternIdStore *MpmPatternIdTableInitHash(void) {
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
MpmPatternIdStore *ht = SCMalloc(sizeof(MpmPatternIdStore));
|
|
|
|
BUG_ON(ht == NULL);
|
|
|
|
memset(ht, 0x00, sizeof(MpmPatternIdStore));
|
|
|
|
|
|
|
|
ht->hash = HashTableInit(65536, MpmPatternIdHashFunc, MpmPatternIdCompare, MpmPatternIdTableElmtFree);
|
|
|
|
BUG_ON(ht->hash == NULL);
|
|
|
|
|
|
|
|
SCReturnPtr(ht, "MpmPatternIdStore");
|
|
|
|
}
|
|
|
|
|
|
|
|
void MpmPatternIdTableFreeHash(MpmPatternIdStore *ht) {
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
if (ht == NULL) {
|
|
|
|
SCReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ht->hash != NULL) {
|
|
|
|
HashTableFree(ht->hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
SCFree(ht);
|
|
|
|
SCReturn;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t MpmPatternIdStoreGetMaxId(MpmPatternIdStore *ht) {
|
|
|
|
if (ht == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ht->max_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Get the pattern id for a content pattern
|
|
|
|
*
|
|
|
|
* \param ht mpm pattern id hash table store
|
|
|
|
* \param co content pattern data
|
|
|
|
*
|
|
|
|
* \retval id pattern id
|
|
|
|
* \initonly
|
|
|
|
*/
|
|
|
|
uint32_t DetectContentGetId(MpmPatternIdStore *ht, DetectContentData *co) {
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
BUG_ON(ht == NULL || ht->hash == NULL);
|
|
|
|
|
|
|
|
MpmPatternIdTableElmt *e = NULL;
|
|
|
|
MpmPatternIdTableElmt *r = NULL;
|
|
|
|
uint32_t id = 0;
|
|
|
|
|
|
|
|
e = malloc(sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(e == NULL);
|
|
|
|
e->pattern = SCMalloc(co->content_len);
|
|
|
|
BUG_ON(e->pattern == NULL);
|
|
|
|
memcpy(e->pattern, co->content, co->content_len);
|
|
|
|
e->pattern_len = co->content_len;
|
|
|
|
e->id = 0;
|
|
|
|
|
|
|
|
r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
if (r == NULL) {
|
|
|
|
e->id = ht->max_id;
|
|
|
|
ht->max_id++;
|
|
|
|
id = e->id;
|
|
|
|
|
|
|
|
int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(ret != 0);
|
|
|
|
|
|
|
|
e = NULL;
|
|
|
|
|
|
|
|
ht->unique_patterns++;
|
|
|
|
} else {
|
|
|
|
id = r->id;
|
|
|
|
|
|
|
|
ht->shared_patterns++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e != NULL)
|
|
|
|
MpmPatternIdTableElmtFree(e);
|
|
|
|
|
|
|
|
SCReturnUInt(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Get the pattern id for a uricontent pattern
|
|
|
|
*
|
|
|
|
* \param ht mpm pattern id hash table store
|
|
|
|
* \param co content pattern data
|
|
|
|
*
|
|
|
|
* \retval id pattern id
|
|
|
|
*/
|
|
|
|
uint32_t DetectUricontentGetId(MpmPatternIdStore *ht, DetectUricontentData *co) {
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
BUG_ON(ht == NULL || ht->hash == NULL);
|
|
|
|
|
|
|
|
MpmPatternIdTableElmt *e = NULL;
|
|
|
|
MpmPatternIdTableElmt *r = NULL;
|
|
|
|
uint32_t id = 0;
|
|
|
|
|
|
|
|
e = malloc(sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(e == NULL);
|
|
|
|
e->pattern = SCMalloc(co->content_len);
|
|
|
|
BUG_ON(e->pattern == NULL);
|
|
|
|
memcpy(e->pattern, co->content, co->content_len);
|
|
|
|
e->pattern_len = co->content_len;
|
|
|
|
e->sm_type = DETECT_URICONTENT;
|
|
|
|
e->dup_count = 1;
|
|
|
|
e->id = 0;
|
|
|
|
|
|
|
|
r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
if (r == NULL) {
|
|
|
|
e->id = ht->max_id;
|
|
|
|
ht->max_id++;
|
|
|
|
id = e->id;
|
|
|
|
|
|
|
|
int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(ret != 0);
|
|
|
|
|
|
|
|
e = NULL;
|
|
|
|
|
|
|
|
ht->unique_patterns++;
|
|
|
|
} else {
|
|
|
|
id = r->id;
|
|
|
|
r->dup_count++;
|
|
|
|
|
|
|
|
ht->shared_patterns++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e != NULL)
|
|
|
|
MpmPatternIdTableElmtFree(e);
|
|
|
|
|
|
|
|
SCReturnUInt(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Get the pattern id for a for any content related keyword.
|
|
|
|
*
|
|
|
|
* Supported keywords are content, http_client_body,
|
|
|
|
* http_method, http_uri, http_header, http_cookie.
|
|
|
|
*
|
|
|
|
* Please note that you can't use it to get a pattern id for
|
|
|
|
* uricontent. To retrieve a uricontent pattern id please
|
|
|
|
* use DetectUricontentGetId().
|
|
|
|
*
|
|
|
|
* \param ht Mpm pattern id hash table store.
|
|
|
|
* \param ctx The keyword context.
|
|
|
|
* \param type The SigMatch context.
|
|
|
|
*
|
|
|
|
* \retval id Pattern id.
|
|
|
|
*/
|
|
|
|
uint32_t DetectPatternGetId(MpmPatternIdStore *ht, void *ctx, uint8_t sm_type)
|
|
|
|
{
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
MpmPatternIdTableElmt *e = NULL;
|
|
|
|
MpmPatternIdTableElmt *r = NULL;
|
|
|
|
PatIntId id = 0;
|
|
|
|
|
|
|
|
e = malloc(sizeof(MpmPatternIdTableElmt));
|
|
|
|
if (e == NULL) {
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if uricontent had used content and content_len as its struct members
|
|
|
|
* we wouldn't have needed this if/else here */
|
|
|
|
if (sm_type == DETECT_URICONTENT) {
|
|
|
|
DetectUricontentData *ud = ctx;
|
|
|
|
e->pattern = SCMalloc(ud->content_len);
|
|
|
|
if (e->pattern == NULL) {
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
memcpy(e->pattern, ud->content, ud->content_len);
|
|
|
|
e->pattern_len = ud->content_len;
|
|
|
|
|
|
|
|
/* CONTENT, HTTP_(CLIENT_BODY|METHOD|URI|COOKIE|HEADER) */
|
|
|
|
} else {
|
|
|
|
DetectContentData *cd = ctx;
|
|
|
|
e->pattern = SCMalloc(cd->content_len);
|
|
|
|
if (e->pattern == NULL) {
|
|
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
memcpy(e->pattern, cd->content, cd->content_len);
|
|
|
|
e->pattern_len = cd->content_len;
|
|
|
|
}
|
|
|
|
e->dup_count = 1;
|
|
|
|
e->sm_type = sm_type;
|
|
|
|
e->id = 0;
|
|
|
|
|
|
|
|
r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
if (r == NULL) {
|
|
|
|
/* we don't have a duplicate with this pattern + id type. If the id is
|
|
|
|
* for content, then it is the first entry for such a
|
|
|
|
* pattern + id combination. Let us create an entry for it */
|
|
|
|
if (sm_type == DETECT_CONTENT) {
|
|
|
|
e->id = ht->max_id;
|
|
|
|
ht->max_id++;
|
|
|
|
id = e->id;
|
|
|
|
|
|
|
|
int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(ret != 0);
|
|
|
|
|
|
|
|
e = NULL;
|
|
|
|
|
|
|
|
/* the id type is not content or uricontent. It would be one of
|
|
|
|
* those http_ modifiers against content then */
|
|
|
|
} else {
|
|
|
|
/* we know that this is one of those http_ modifiers against content.
|
|
|
|
* So we would have seen a content before coming across this http_
|
|
|
|
* modifier. Let's retrieve this content entry that has already
|
|
|
|
* been registered. */
|
|
|
|
e->sm_type = DETECT_CONTENT;
|
|
|
|
MpmPatternIdTableElmt *tmp_r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
if (tmp_r == NULL) {
|
|
|
|
SCLogError(SC_ERR_FATAL, "How can this happen? We have to have "
|
|
|
|
"a content of type DETECT_CONTENT already registered "
|
|
|
|
"at this point. Impossible");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have retrieved the content, and the content registered was the
|
|
|
|
* first entry made(dup_count is 1) for that content. Let us just
|
|
|
|
* reset the sm_type to the http_ keyword's sm_type */
|
|
|
|
if (tmp_r->dup_count == 1) {
|
|
|
|
tmp_r->sm_type = sm_type;
|
|
|
|
id = tmp_r->id;
|
|
|
|
|
|
|
|
/* interestingly we have more than one entry for this content.
|
|
|
|
* Out of these tmp_r->dup_count entries, one would be for the content
|
|
|
|
* entry made for this http_ modifier. Erase this entry and make
|
|
|
|
* a separate entry for the http_ modifier(of course with a new id) */
|
|
|
|
} else {
|
|
|
|
tmp_r->dup_count--;
|
|
|
|
/* reset the sm_type, since we changed it to DETECT_CONTENT prev */
|
|
|
|
e->sm_type = sm_type;
|
|
|
|
e->id = ht->max_id;
|
|
|
|
ht->max_id++;
|
|
|
|
id = e->id;
|
|
|
|
|
|
|
|
int ret = HashTableAdd(ht->hash, e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
BUG_ON(ret != 0);
|
|
|
|
|
|
|
|
e = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we do seem to have an entry for this already */
|
|
|
|
} else {
|
|
|
|
/* oh cool! It is a duplicate for content, uricontent types. Update the
|
|
|
|
* dup_count and get out */
|
|
|
|
if (sm_type == DETECT_CONTENT) {
|
|
|
|
r->dup_count++;
|
|
|
|
id = r->id;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* uh oh! a duplicate for a http_ modifier type. Let's increase the
|
|
|
|
* dup_count for the entry */
|
|
|
|
r->dup_count++;
|
|
|
|
id = r->id;
|
|
|
|
|
|
|
|
/* let's get the content entry associated with the http keyword we are
|
|
|
|
* currently operating on */
|
|
|
|
e->sm_type = DETECT_CONTENT;
|
|
|
|
MpmPatternIdTableElmt *tmp_r = HashTableLookup(ht->hash, (void *)e, sizeof(MpmPatternIdTableElmt));
|
|
|
|
if (tmp_r == NULL) {
|
|
|
|
SCLogError(SC_ERR_FATAL, "How can this happen? We have to have "
|
|
|
|
"a content of type DETECT_CONTENT already registered "
|
|
|
|
"at this point. Impossible");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
/* so there are more than one content keyword entries for this pattern.
|
|
|
|
* Reduce the dup_count */
|
|
|
|
if (tmp_r->dup_count > 1) {
|
|
|
|
tmp_r->dup_count--;
|
|
|
|
|
|
|
|
/* We have just one entry. Remove this hash table entry */
|
|
|
|
} else {
|
|
|
|
HashTableRemove(ht->hash, tmp_r, sizeof(MpmPatternIdTableElmt));
|
|
|
|
ht->max_id--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (e != NULL)
|
|
|
|
MpmPatternIdTableElmtFree(e);
|
|
|
|
|
|
|
|
SCReturnUInt(id);
|
|
|
|
}
|