1 /* Copyright (C) 2007-2014 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
23  *
24  * Multi pattern matcher
25  */
26 
27 #include "suricata.h"
28 #include "suricata-common.h"
29 
30 #include "app-layer-protos.h"
31 
32 #include "decode.h"
33 #include "detect.h"
34 #include "detect-engine.h"
35 #include "detect-engine-siggroup.h"
36 #include "detect-engine-mpm.h"
37 #include "detect-engine-iponly.h"
38 #include "detect-parse.h"
39 #include "detect-engine-prefilter.h"
40 #include "util-mpm.h"
41 #include "util-memcmp.h"
42 #include "util-memcpy.h"
43 #include "conf.h"
44 #include "detect-fast-pattern.h"
45 
46 #include "detect-tcphdr.h"
47 #include "detect-udphdr.h"
48 
49 #include "flow.h"
50 #include "flow-var.h"
51 #include "detect-flow.h"
52 
53 #include "detect-content.h"
54 
55 #include "detect-engine-payload.h"
56 #include "detect-engine-dns.h"
57 
58 #include "stream.h"
59 
60 #include "util-misc.h"
61 #include "util-enum.h"
62 #include "util-debug.h"
63 #include "util-print.h"
64 #include "util-validate.h"
65 
66 const char *builtin_mpms[] = {
67     "toserver TCP packet",
68     "toclient TCP packet",
69     "toserver TCP stream",
70     "toclient TCP stream",
71     "toserver UDP packet",
72     "toclient UDP packet",
73     "other IP packet",
74 
75     NULL };
76 
77 /* Registry for mpm keywords
78  *
79  * Keywords are registered at engine start up
80  */
81 
82 static DetectBufferMpmRegistery *g_mpm_list[DETECT_BUFFER_MPM_TYPE_SIZE] = { NULL, NULL };
83 static int g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_SIZE] = { 0, 0 };
84 
85 /** \brief register a MPM engine
86  *
87  *  \note to be used at start up / registration only. Errors are fatal.
88  */
DetectAppLayerMpmRegister2(const char * name,int direction,int priority,int (* PrefilterRegister)(DetectEngineCtx * de_ctx,SigGroupHead * sgh,MpmCtx * mpm_ctx,const DetectBufferMpmRegistery * mpm_reg,int list_id),InspectionBufferGetDataPtr GetData,AppProto alproto,int tx_min_progress)89 void DetectAppLayerMpmRegister2(const char *name,
90         int direction, int priority,
91         int (*PrefilterRegister)(DetectEngineCtx *de_ctx,
92             SigGroupHead *sgh, MpmCtx *mpm_ctx,
93             const DetectBufferMpmRegistery *mpm_reg, int list_id),
94         InspectionBufferGetDataPtr GetData,
95         AppProto alproto, int tx_min_progress)
96 {
97     SCLogDebug("registering %s/%d/%d/%p/%p/%u/%d", name, direction, priority,
98             PrefilterRegister, GetData, alproto, tx_min_progress);
99 
100     if (PrefilterRegister == PrefilterGenericMpmRegister && GetData == NULL) {
101         // must register GetData with PrefilterGenericMpmRegister
102         abort();
103     }
104 
105     DetectBufferTypeSupportsMpm(name);
106     DetectBufferTypeSupportsTransformations(name);
107     int sm_list = DetectBufferTypeGetByName(name);
108     if (sm_list == -1) {
109         FatalError(SC_ERR_INITIALIZATION,
110                 "MPM engine registration for %s failed", name);
111     }
112 
113     DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
114     BUG_ON(am == NULL);
115     am->name = name;
116     snprintf(am->pname, sizeof(am->pname), "%s", am->name);
117     am->direction = direction;
118     am->sm_list = sm_list;
119     am->sm_list_base = sm_list;
120     am->priority = priority;
121     am->type = DETECT_BUFFER_MPM_TYPE_APP;
122 
123     am->PrefilterRegisterWithListId = PrefilterRegister;
124     am->app_v2.GetData = GetData;
125     am->app_v2.alproto = alproto;
126     am->app_v2.tx_min_progress = tx_min_progress;
127 
128     if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] == NULL) {
129         g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP] = am;
130     } else {
131         DetectBufferMpmRegistery *t = g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP];
132         while (t->next != NULL) {
133             t = t->next;
134         }
135 
136         t->next = am;
137         am->id = t->id + 1;
138     }
139     g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP]++;
140 
141     SupportFastPatternForSigMatchList(sm_list, priority);
142 }
143 
144 /** \brief copy a mpm engine from parent_id, add in transforms */
DetectAppLayerMpmRegisterByParentId(DetectEngineCtx * de_ctx,const int id,const int parent_id,DetectEngineTransforms * transforms)145 void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx,
146         const int id, const int parent_id,
147         DetectEngineTransforms *transforms)
148 {
149     SCLogDebug("registering %d/%d", id, parent_id);
150 
151     DetectBufferMpmRegistery *t = de_ctx->app_mpms_list;
152     while (t) {
153         if (t->sm_list == parent_id) {
154             DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
155             BUG_ON(am == NULL);
156             am->name = t->name;
157             am->direction = t->direction;
158             am->sm_list = id; // use new id
159             am->sm_list_base = t->sm_list;
160             am->type = DETECT_BUFFER_MPM_TYPE_APP;
161             am->PrefilterRegisterWithListId = t->PrefilterRegisterWithListId;
162             am->app_v2.GetData = t->app_v2.GetData;
163             am->app_v2.alproto = t->app_v2.alproto;
164             am->app_v2.tx_min_progress = t->app_v2.tx_min_progress;
165             am->priority = t->priority;
166             am->sgh_mpm_context = t->sgh_mpm_context;
167             am->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, am->name, am->sm_list);
168             am->next = t->next;
169             if (transforms) {
170                 memcpy(&am->transforms, transforms, sizeof(*transforms));
171 
172                 /* create comma separated string of the names of the
173                  * transforms and then shorten it if necessary. Finally
174                  * use it to construct the 'profile' name for the engine */
175                 char xforms[1024] = "";
176                 for (int i = 0; i < transforms->cnt; i++) {
177                     char ttstr[64];
178                     (void)snprintf(ttstr,sizeof(ttstr), "%s,",
179                             sigmatch_table[transforms->transforms[i].transform].name);
180                     strlcat(xforms, ttstr, sizeof(xforms));
181                 }
182                 xforms[strlen(xforms)-1] = '\0';
183 
184                 size_t space = sizeof(am->pname) - strlen(am->name) - 3;
185                 char toprint[space + 1];
186                 memset(toprint, 0x00, space + 1);
187                 if (space < strlen(xforms)) {
188                     ShortenString(xforms, toprint, space, '~');
189                 } else {
190                     strlcpy(toprint, xforms,sizeof(toprint));
191                 }
192                 (void)snprintf(am->pname, sizeof(am->pname), "%s#%d (%s)",
193                         am->name, id, toprint);
194             } else {
195                 (void)snprintf(am->pname, sizeof(am->pname), "%s#%d",
196                         am->name, id);
197             }
198             am->id = de_ctx->app_mpms_list_cnt++;
199 
200             SupportFastPatternForSigMatchList(am->sm_list, am->priority);
201             t->next = am;
202             SCLogDebug("copied mpm registration for %s id %u "
203                     "with parent %u and GetData %p",
204                     t->name, id, parent_id, am->app_v2.GetData);
205             t = am;
206         }
207         t = t->next;
208     }
209 }
210 
DetectMpmInitializeAppMpms(DetectEngineCtx * de_ctx)211 void DetectMpmInitializeAppMpms(DetectEngineCtx *de_ctx)
212 {
213     const DetectBufferMpmRegistery *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_APP];
214     while (list != NULL) {
215         DetectBufferMpmRegistery *n = SCCalloc(1, sizeof(*n));
216         BUG_ON(n == NULL);
217 
218         *n = *list;
219         n->next = NULL;
220 
221         if (de_ctx->app_mpms_list == NULL) {
222             de_ctx->app_mpms_list = n;
223         } else {
224             DetectBufferMpmRegistery *t = de_ctx->app_mpms_list;
225             while (t->next != NULL) {
226                 t = t->next;
227             }
228             t->next = n;
229         }
230 
231         /* default to whatever the global setting is */
232         int shared = (de_ctx->sgh_mpm_ctx_cnf == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
233 
234         /* see if we use a unique or shared mpm ctx for this type */
235         int confshared = 0;
236         char confstring[256] = "detect.mpm.";
237         strlcat(confstring, n->name, sizeof(confstring));
238         strlcat(confstring, ".shared", sizeof(confstring));
239         if (ConfGetBool(confstring, &confshared) == 1)
240             shared = confshared;
241 
242         if (shared == 0) {
243             if (!(de_ctx->flags & DE_QUIET)) {
244                 SCLogPerf("using unique mpm ctx' for %s", n->name);
245             }
246             n->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT;
247         } else {
248             if (!(de_ctx->flags & DE_QUIET)) {
249                 SCLogPerf("using shared mpm ctx' for %s", n->name);
250             }
251             n->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, n->name, n->sm_list);
252         }
253 
254         list = list->next;
255     }
256     de_ctx->app_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_APP];
257     SCLogDebug("mpm: de_ctx app_mpms_list %p %u",
258             de_ctx->app_mpms_list, de_ctx->app_mpms_list_cnt);
259 }
260 
261 /**
262  *  \brief initialize mpm contexts for applayer buffers that are in
263  *         "single or "shared" mode.
264  */
DetectMpmPrepareAppMpms(DetectEngineCtx * de_ctx)265 int DetectMpmPrepareAppMpms(DetectEngineCtx *de_ctx)
266 {
267     int r = 0;
268     const DetectBufferMpmRegistery *am = de_ctx->app_mpms_list;
269     while (am != NULL) {
270         int dir = (am->direction == SIG_FLAG_TOSERVER) ? 1 : 0;
271 
272         if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT)
273         {
274             MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, dir);
275             if (mpm_ctx != NULL) {
276                 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
277                     r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
278                 }
279             }
280         }
281         am = am->next;
282     }
283     return r;
284 }
285 
286 /** \brief register a MPM engine
287  *
288  *  \note to be used at start up / registration only. Errors are fatal.
289  */
DetectPktMpmRegister(const char * name,int priority,int (* PrefilterRegister)(DetectEngineCtx * de_ctx,SigGroupHead * sgh,MpmCtx * mpm_ctx,const DetectBufferMpmRegistery * mpm_reg,int list_id),InspectionBufferGetPktDataPtr GetData)290 void DetectPktMpmRegister(const char *name,
291         int priority,
292         int (*PrefilterRegister)(DetectEngineCtx *de_ctx,
293             SigGroupHead *sgh, MpmCtx *mpm_ctx,
294             const DetectBufferMpmRegistery *mpm_reg, int list_id),
295         InspectionBufferGetPktDataPtr GetData)
296 {
297     SCLogDebug("registering %s/%d/%p/%p", name, priority,
298             PrefilterRegister, GetData);
299 
300     if (PrefilterRegister == PrefilterGenericMpmPktRegister && GetData == NULL) {
301         // must register GetData with PrefilterGenericMpmRegister
302         abort();
303     }
304 
305     DetectBufferTypeSupportsMpm(name);
306     DetectBufferTypeSupportsTransformations(name);
307     int sm_list = DetectBufferTypeGetByName(name);
308     if (sm_list == -1) {
309         FatalError(SC_ERR_INITIALIZATION,
310                 "MPM engine registration for %s failed", name);
311     }
312 
313     DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
314     BUG_ON(am == NULL);
315     am->name = name;
316     snprintf(am->pname, sizeof(am->pname), "%s", am->name);
317     am->sm_list = sm_list;
318     am->priority = priority;
319     am->type = DETECT_BUFFER_MPM_TYPE_PKT;
320 
321     am->PrefilterRegisterWithListId = PrefilterRegister;
322     am->pkt_v1.GetData = GetData;
323 
324     if (g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT] == NULL) {
325         g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT] = am;
326     } else {
327         DetectBufferMpmRegistery *t = g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT];
328         while (t->next != NULL) {
329             t = t->next;
330         }
331         t->next = am;
332         am->id = t->id + 1;
333     }
334     g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_PKT]++;
335 
336     SupportFastPatternForSigMatchList(sm_list, priority);
337     SCLogDebug("%s/%d done", name, sm_list);
338 }
339 
340 /** \brief copy a mpm engine from parent_id, add in transforms */
DetectPktMpmRegisterByParentId(DetectEngineCtx * de_ctx,const int id,const int parent_id,DetectEngineTransforms * transforms)341 void DetectPktMpmRegisterByParentId(DetectEngineCtx *de_ctx,
342         const int id, const int parent_id,
343         DetectEngineTransforms *transforms)
344 {
345     SCLogDebug("registering %d/%d", id, parent_id);
346 
347     DetectBufferMpmRegistery *t = de_ctx->pkt_mpms_list;
348     while (t) {
349         if (t->sm_list == parent_id) {
350             DetectBufferMpmRegistery *am = SCCalloc(1, sizeof(*am));
351             BUG_ON(am == NULL);
352             am->name = t->name;
353             snprintf(am->pname, sizeof(am->pname), "%s#%d", am->name, id);
354             am->sm_list = id; // use new id
355             am->sm_list_base = t->sm_list;
356             am->type = DETECT_BUFFER_MPM_TYPE_PKT;
357             am->PrefilterRegisterWithListId = t->PrefilterRegisterWithListId;
358             am->pkt_v1.GetData = t->pkt_v1.GetData;
359             am->priority = t->priority;
360             am->sgh_mpm_context = t->sgh_mpm_context;
361             am->next = t->next;
362             if (transforms) {
363                 memcpy(&am->transforms, transforms, sizeof(*transforms));
364             }
365             am->id = de_ctx->pkt_mpms_list_cnt++;
366 
367             SupportFastPatternForSigMatchList(am->sm_list, am->priority);
368             t->next = am;
369             SCLogDebug("copied mpm registration for %s id %u "
370                     "with parent %u and GetData %p",
371                     t->name, id, parent_id, am->pkt_v1.GetData);
372             t = am;
373         }
374         t = t->next;
375     }
376 }
377 
DetectMpmInitializePktMpms(DetectEngineCtx * de_ctx)378 void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx)
379 {
380     const DetectBufferMpmRegistery *list = g_mpm_list[DETECT_BUFFER_MPM_TYPE_PKT];
381     while (list != NULL) {
382         DetectBufferMpmRegistery *n = SCCalloc(1, sizeof(*n));
383         BUG_ON(n == NULL);
384 
385         *n = *list;
386         n->next = NULL;
387 
388         if (de_ctx->pkt_mpms_list == NULL) {
389             de_ctx->pkt_mpms_list = n;
390         } else {
391             DetectBufferMpmRegistery *t = de_ctx->pkt_mpms_list;
392             while (t->next != NULL) {
393                 t = t->next;
394             }
395 
396             t->next = n;
397         }
398 
399         /* default to whatever the global setting is */
400         int shared = (de_ctx->sgh_mpm_ctx_cnf == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
401 
402         /* see if we use a unique or shared mpm ctx for this type */
403         int confshared = 0;
404         char confstring[256] = "detect.mpm.";
405         strlcat(confstring, n->name, sizeof(confstring));
406         strlcat(confstring, ".shared", sizeof(confstring));
407         if (ConfGetBool(confstring, &confshared) == 1)
408             shared = confshared;
409 
410         if (shared == 0) {
411             if (!(de_ctx->flags & DE_QUIET)) {
412                 SCLogPerf("using unique mpm ctx' for %s", n->name);
413             }
414             n->sgh_mpm_context = MPM_CTX_FACTORY_UNIQUE_CONTEXT;
415         } else {
416             if (!(de_ctx->flags & DE_QUIET)) {
417                 SCLogPerf("using shared mpm ctx' for %s", n->name);
418             }
419             n->sgh_mpm_context = MpmFactoryRegisterMpmCtxProfile(de_ctx, n->name, n->sm_list);
420         }
421 
422         list = list->next;
423     }
424     de_ctx->pkt_mpms_list_cnt = g_mpm_list_cnt[DETECT_BUFFER_MPM_TYPE_PKT];
425     SCLogDebug("mpm: de_ctx pkt_mpms_list %p %u",
426             de_ctx->pkt_mpms_list, de_ctx->pkt_mpms_list_cnt);
427 }
428 
429 /**
430  *  \brief initialize mpm contexts for applayer buffers that are in
431  *         "single or "shared" mode.
432  */
DetectMpmPreparePktMpms(DetectEngineCtx * de_ctx)433 int DetectMpmPreparePktMpms(DetectEngineCtx *de_ctx)
434 {
435     SCLogDebug("preparing pkt mpm");
436     int r = 0;
437     const DetectBufferMpmRegistery *am = de_ctx->pkt_mpms_list;
438     while (am != NULL) {
439         SCLogDebug("%s", am->name);
440         if (am->sgh_mpm_context != MPM_CTX_FACTORY_UNIQUE_CONTEXT)
441         {
442             MpmCtx *mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, am->sgh_mpm_context, 0);
443             if (mpm_ctx != NULL) {
444                 if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
445                     r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
446                     SCLogDebug("%s: %d", am->name, r);
447                 }
448             }
449         }
450         am = am->next;
451     }
452     return r;
453 }
454 
SetupBuiltinMpm(DetectEngineCtx * de_ctx,const char * name)455 static int32_t SetupBuiltinMpm(DetectEngineCtx *de_ctx, const char *name)
456 {
457     /* default to whatever the global setting is */
458     int shared = (de_ctx->sgh_mpm_ctx_cnf == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE);
459 
460     /* see if we use a unique or shared mpm ctx for this type */
461     int confshared = 0;
462     char confstring[256] = "detect.mpm.";
463     strlcat(confstring, name, sizeof(confstring));
464     strlcat(confstring, ".shared", sizeof(confstring));
465     if (ConfGetBool(confstring, &confshared) == 1)
466         shared = confshared;
467 
468     int32_t ctx;
469     if (shared == 0) {
470         ctx = MPM_CTX_FACTORY_UNIQUE_CONTEXT;
471         SCLogPerf("using unique mpm ctx' for %s", name);
472     } else {
473         ctx = MpmFactoryRegisterMpmCtxProfile(de_ctx, name, DETECT_SM_LIST_PMATCH);
474         SCLogPerf("using shared mpm ctx' for %s", name);
475     }
476     return ctx;
477 }
478 
DetectMpmInitializeBuiltinMpms(DetectEngineCtx * de_ctx)479 void DetectMpmInitializeBuiltinMpms(DetectEngineCtx *de_ctx)
480 {
481     de_ctx->sgh_mpm_context_proto_tcp_packet = SetupBuiltinMpm(de_ctx, "tcp-packet");
482     de_ctx->sgh_mpm_context_stream = SetupBuiltinMpm(de_ctx, "tcp-stream");
483 
484     de_ctx->sgh_mpm_context_proto_udp_packet = SetupBuiltinMpm(de_ctx, "udp-packet");
485     de_ctx->sgh_mpm_context_proto_other_packet = SetupBuiltinMpm(de_ctx, "other-ip");
486 }
487 
488 /**
489  *  \brief initialize mpm contexts for builtin buffers that are in
490  *         "single or "shared" mode.
491  */
DetectMpmPrepareBuiltinMpms(DetectEngineCtx * de_ctx)492 int DetectMpmPrepareBuiltinMpms(DetectEngineCtx *de_ctx)
493 {
494     int r = 0;
495     MpmCtx *mpm_ctx = NULL;
496 
497     if (de_ctx->sgh_mpm_context_proto_tcp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) {
498         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 0);
499         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
500             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
501         }
502         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_tcp_packet, 1);
503         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
504             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
505         }
506     }
507 
508     if (de_ctx->sgh_mpm_context_proto_udp_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) {
509         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 0);
510         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
511             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
512         }
513         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_udp_packet, 1);
514         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
515             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
516         }
517     }
518 
519     if (de_ctx->sgh_mpm_context_proto_other_packet != MPM_CTX_FACTORY_UNIQUE_CONTEXT) {
520         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_proto_other_packet, 0);
521         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
522             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
523         }
524     }
525 
526     if (de_ctx->sgh_mpm_context_stream != MPM_CTX_FACTORY_UNIQUE_CONTEXT) {
527         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 0);
528         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
529             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
530         }
531         mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_stream, 1);
532         if (mpm_table[de_ctx->mpm_matcher].Prepare != NULL) {
533             r |= mpm_table[de_ctx->mpm_matcher].Prepare(mpm_ctx);
534         }
535     }
536 
537     return r;
538 }
539 
540 /**
541  *  \brief check if a signature has patterns that are to be inspected
542  *         against a packets payload (as opposed to the stream payload)
543  *
544  *  \param s signature
545  *
546  *  \retval 1 true
547  *  \retval 0 false
548  */
SignatureHasPacketContent(const Signature * s)549 int SignatureHasPacketContent(const Signature *s)
550 {
551     SCEnter();
552 
553     if (s == NULL) {
554         SCReturnInt(0);
555     }
556 
557     if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) {
558         SCReturnInt(1);
559     }
560 
561     if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) ||
562         (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL))
563     {
564         SCLogDebug("no mpm");
565         SCReturnInt(0);
566     }
567 
568     if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
569         SCReturnInt(0);
570     }
571 
572     SCReturnInt(1);
573 }
574 
575 /**
576  *  \brief check if a signature has patterns that are to be inspected
577  *         against the stream payload (as opposed to the individual packets
578  *         payload(s))
579  *
580  *  \param s signature
581  *
582  *  \retval 1 true
583  *  \retval 0 false
584  */
SignatureHasStreamContent(const Signature * s)585 int SignatureHasStreamContent(const Signature *s)
586 {
587     SCEnter();
588 
589     if (s == NULL) {
590         SCReturnInt(0);
591     }
592 
593     if (!(s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8))) {
594         SCReturnInt(0);
595     }
596 
597     if ((s->init_data != NULL && s->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) ||
598         (s->init_data == NULL && s->sm_arrays[DETECT_SM_LIST_PMATCH] == NULL))
599     {
600         SCLogDebug("no mpm");
601         SCReturnInt(0);
602     }
603 
604     if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
605         SCReturnInt(0);
606     }
607 
608     SCReturnInt(1);
609 }
610 
611 
612 /**
613  *  \brief  Function to return the multi pattern matcher algorithm to be
614  *          used by the engine, based on the mpm-algo setting in yaml
615  *          Use the default mpm if none is specified in the yaml file.
616  *
617  *  \retval mpm algo value
618  */
PatternMatchDefaultMatcher(void)619 uint16_t PatternMatchDefaultMatcher(void)
620 {
621     const char *mpm_algo;
622     uint16_t mpm_algo_val = mpm_default_matcher;
623 
624     /* Get the mpm algo defined in config file by the user */
625     if ((ConfGet("mpm-algo", &mpm_algo)) == 1) {
626         if (mpm_algo != NULL) {
627 #if __BYTE_ORDER == __BIG_ENDIAN
628             if (strcmp(mpm_algo, "ac-ks") == 0) {
629                 FatalError(SC_ERR_FATAL, "ac-ks does "
630                            "not work on big endian systems at this time.");
631             }
632 #endif
633             if (strcmp("auto", mpm_algo) == 0) {
634                 goto done;
635             }
636             for (uint16_t u = 0; u < MPM_TABLE_SIZE; u++) {
637                 if (mpm_table[u].name == NULL)
638                     continue;
639 
640                 if (strcmp(mpm_table[u].name, mpm_algo) == 0) {
641                     mpm_algo_val = u;
642                     goto done;
643                 }
644             }
645 
646 #ifndef BUILD_HYPERSCAN
647             if ((strcmp(mpm_algo, "hs") == 0)) {
648                 FatalError(SC_ERR_INVALID_VALUE, "Hyperscan (hs) support for mpm-algo is "
649                         "not compiled into Suricata.");
650             }
651 #endif
652         }
653         FatalError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid mpm algo supplied "
654                 "in the yaml conf file: \"%s\"", mpm_algo);
655     }
656 
657  done:
658     return mpm_algo_val;
659 }
660 
PatternMatchDestroy(MpmCtx * mpm_ctx,uint16_t mpm_matcher)661 void PatternMatchDestroy(MpmCtx *mpm_ctx, uint16_t mpm_matcher)
662 {
663     SCLogDebug("mpm_ctx %p, mpm_matcher %"PRIu16"", mpm_ctx, mpm_matcher);
664     mpm_table[mpm_matcher].DestroyCtx(mpm_ctx);
665 }
666 
PatternMatchThreadPrint(MpmThreadCtx * mpm_thread_ctx,uint16_t mpm_matcher)667 void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
668 {
669     SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16" defunct", mpm_thread_ctx, mpm_matcher);
670     //mpm_table[mpm_matcher].PrintThreadCtx(mpm_thread_ctx);
671 }
PatternMatchThreadDestroy(MpmThreadCtx * mpm_thread_ctx,uint16_t mpm_matcher)672 void PatternMatchThreadDestroy(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
673 {
674     SCLogDebug("mpm_thread_ctx %p, mpm_matcher %"PRIu16"", mpm_thread_ctx, mpm_matcher);
675     if (mpm_table[mpm_matcher].DestroyThreadCtx != NULL)
676         mpm_table[mpm_matcher].DestroyThreadCtx(NULL, mpm_thread_ctx);
677 }
PatternMatchThreadPrepare(MpmThreadCtx * mpm_thread_ctx,uint16_t mpm_matcher)678 void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
679 {
680     SCLogDebug("mpm_thread_ctx %p, type %"PRIu16, mpm_thread_ctx, mpm_matcher);
681     MpmInitThreadCtx(mpm_thread_ctx, mpm_matcher);
682 }
683 
684 /** \brief Predict a strength value for patterns
685  *
686  *  Patterns with high character diversity score higher.
687  *  Alpha chars score not so high
688  *  Other printable + a few common codes a little higher
689  *  Everything else highest.
690  *  Longer patterns score better than short patters.
691  *
692  *  \param pat pattern
693  *  \param patlen length of the pattern
694  *
695  *  \retval s pattern score
696  */
PatternStrength(uint8_t * pat,uint16_t patlen)697 uint32_t PatternStrength(uint8_t *pat, uint16_t patlen)
698 {
699     uint8_t a[256];
700     memset(&a, 0 ,sizeof(a));
701 
702     uint32_t s = 0;
703     uint16_t u = 0;
704     for (u = 0; u < patlen; u++) {
705         if (a[pat[u]] == 0) {
706             if (isalpha(pat[u]))
707                 s += 3;
708             else if (isprint(pat[u]) || pat[u] == 0x00 || pat[u] == 0x01 || pat[u] == 0xFF)
709                 s += 4;
710             else
711                 s += 6;
712 
713             a[pat[u]] = 1;
714         } else {
715             s++;
716         }
717     }
718 
719     return s;
720 }
721 
PopulateMpmHelperAddPattern(MpmCtx * mpm_ctx,const DetectContentData * cd,const Signature * s,uint8_t flags,int chop)722 static void PopulateMpmHelperAddPattern(MpmCtx *mpm_ctx,
723                                         const DetectContentData *cd,
724                                         const Signature *s, uint8_t flags,
725                                         int chop)
726 {
727     uint16_t pat_offset = cd->offset;
728     uint16_t pat_depth = cd->depth;
729 
730     /* recompute offset/depth to cope with chop */
731     if (chop && (pat_depth || pat_offset)) {
732         pat_offset += cd->fp_chop_offset;
733         if (pat_depth) {
734             pat_depth -= cd->content_len;
735             pat_depth += cd->fp_chop_offset + cd->fp_chop_len;
736         }
737     }
738 
739     /* We have to effectively "wild card" values that will be coming from
740      * byte_extract variables
741      */
742     if (cd->flags & (DETECT_CONTENT_DEPTH_VAR | DETECT_CONTENT_OFFSET_VAR)) {
743         pat_depth = pat_offset = 0;
744     }
745 
746     if (cd->flags & DETECT_CONTENT_NOCASE) {
747         if (chop) {
748             MpmAddPatternCI(mpm_ctx,
749                             cd->content + cd->fp_chop_offset, cd->fp_chop_len,
750                             pat_offset, pat_depth,
751                             cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
752         } else {
753             MpmAddPatternCI(mpm_ctx,
754                             cd->content, cd->content_len,
755                             pat_offset, pat_depth,
756                             cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
757         }
758     } else {
759         if (chop) {
760             MpmAddPatternCS(mpm_ctx,
761                             cd->content + cd->fp_chop_offset, cd->fp_chop_len,
762                             pat_offset, pat_depth,
763                             cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
764         } else {
765             MpmAddPatternCS(mpm_ctx,
766                             cd->content, cd->content_len,
767                             pat_offset, pat_depth,
768                             cd->id, s->num, flags|MPM_PATTERN_CTX_OWNS_ID);
769         }
770     }
771 
772     return;
773 }
774 
775 #define SGH_PROTO(sgh, p) ((sgh)->init->protos[(p)] == 1)
776 #define SGH_DIRECTION_TS(sgh) ((sgh)->init->direction & SIG_FLAG_TOSERVER)
777 #define SGH_DIRECTION_TC(sgh) ((sgh)->init->direction & SIG_FLAG_TOCLIENT)
778 
SetMpm(Signature * s,SigMatch * mpm_sm)779 static void SetMpm(Signature *s, SigMatch *mpm_sm)
780 {
781     if (s == NULL || mpm_sm == NULL)
782         return;
783 
784     DetectContentData *cd = (DetectContentData *)mpm_sm->ctx;
785     if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
786         if (DETECT_CONTENT_IS_SINGLE(cd) &&
787                 !(cd->flags & DETECT_CONTENT_NEGATED) &&
788                 !(cd->flags & DETECT_CONTENT_REPLACE) &&
789                 cd->content_len == cd->fp_chop_len)
790         {
791             cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED;
792         }
793     } else {
794         if (DETECT_CONTENT_IS_SINGLE(cd) &&
795                 !(cd->flags & DETECT_CONTENT_NEGATED) &&
796                 !(cd->flags & DETECT_CONTENT_REPLACE))
797         {
798             cd->flags |= DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED;
799         }
800     }
801     cd->flags |= DETECT_CONTENT_MPM;
802     s->init_data->mpm_sm = mpm_sm;
803     return;
804 }
805 
GetMpmForList(const Signature * s,const int list,SigMatch * mpm_sm,uint16_t max_len,bool skip_negated_content)806 static SigMatch *GetMpmForList(const Signature *s, const int list, SigMatch *mpm_sm,
807     uint16_t max_len, bool skip_negated_content)
808 {
809     for (SigMatch *sm = s->init_data->smlists[list]; sm != NULL; sm = sm->next) {
810         if (sm->type != DETECT_CONTENT)
811             continue;
812 
813         const DetectContentData *cd = (DetectContentData *)sm->ctx;
814         /* skip_negated_content is only set if there's absolutely no
815          * non-negated content present in the sig */
816         if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
817             continue;
818         if (cd->content_len != max_len)
819             continue;
820 
821         if (mpm_sm == NULL) {
822             mpm_sm = sm;
823         } else {
824             DetectContentData *data1 = (DetectContentData *)sm->ctx;
825             DetectContentData *data2 = (DetectContentData *)mpm_sm->ctx;
826             uint32_t ls = PatternStrength(data1->content, data1->content_len);
827             uint32_t ss = PatternStrength(data2->content, data2->content_len);
828             if (ls > ss) {
829                 mpm_sm = sm;
830             } else if (ls == ss) {
831                 /* if 2 patterns are of equal strength, we pick the longest */
832                 if (data1->content_len > data2->content_len)
833                     mpm_sm = sm;
834             } else {
835                 SCLogDebug("sticking with mpm_sm");
836             }
837         }
838     }
839     return mpm_sm;
840 }
841 
RetrieveFPForSig(const DetectEngineCtx * de_ctx,Signature * s)842 void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
843 {
844     if (s->init_data->mpm_sm != NULL)
845         return;
846 
847     SigMatch *mpm_sm = NULL, *sm = NULL;
848     const int nlists = s->init_data->smlists_array_size;
849     int nn_sm_list[nlists];
850     int n_sm_list[nlists];
851     memset(nn_sm_list, 0, nlists * sizeof(int));
852     memset(n_sm_list, 0, nlists * sizeof(int));
853     int count_nn_sm_list = 0;
854     int count_n_sm_list = 0;
855 
856     /* inspect rule to see if we have the fast_pattern reg to
857      * force using a sig, otherwise keep stats about the patterns */
858     for (int list_id = 0; list_id < nlists; list_id++) {
859         if (s->init_data->smlists[list_id] == NULL)
860             continue;
861 
862         if (!FastPatternSupportEnabledForSigMatchList(de_ctx, list_id))
863             continue;
864 
865         for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) {
866             if (sm->type != DETECT_CONTENT)
867                 continue;
868 
869             const DetectContentData *cd = (DetectContentData *)sm->ctx;
870             /* fast_pattern set in rule, so using this pattern */
871             if ((cd->flags & DETECT_CONTENT_FAST_PATTERN)) {
872                 SetMpm(s, sm);
873                 return;
874             }
875 
876             if (cd->flags & DETECT_CONTENT_NEGATED) {
877                 n_sm_list[list_id] = 1;
878                 count_n_sm_list++;
879             } else {
880                 nn_sm_list[list_id] = 1;
881                 count_nn_sm_list++;
882             }
883         }
884     }
885 
886     /* prefer normal not-negated over negated */
887     int *curr_sm_list = NULL;
888     int skip_negated_content = 1;
889     if (count_nn_sm_list > 0) {
890         curr_sm_list = nn_sm_list;
891     } else if (count_n_sm_list > 0) {
892         curr_sm_list = n_sm_list;
893         skip_negated_content = 0;
894     } else {
895         return;
896     }
897 
898     int final_sm_list[nlists];
899     memset(&final_sm_list, 0, (nlists * sizeof(int)));
900 
901     int count_final_sm_list = 0;
902     int priority;
903 
904     const SCFPSupportSMList *tmp = sm_fp_support_smlist_list;
905     while (tmp != NULL) {
906         for (priority = tmp->priority;
907              tmp != NULL && priority == tmp->priority;
908              tmp = tmp->next)
909         {
910             if (tmp->list_id >= nlists)
911                 continue;
912             if (curr_sm_list[tmp->list_id] == 0)
913                 continue;
914             final_sm_list[count_final_sm_list++] = tmp->list_id;
915         }
916         if (count_final_sm_list != 0)
917             break;
918     }
919 
920     BUG_ON(count_final_sm_list == 0);
921 
922     uint16_t max_len = 0;
923     for (int i = 0; i < count_final_sm_list; i++) {
924         if (final_sm_list[i] >= (int)s->init_data->smlists_array_size)
925             continue;
926 
927         for (sm = s->init_data->smlists[final_sm_list[i]]; sm != NULL; sm = sm->next) {
928             if (sm->type != DETECT_CONTENT)
929                 continue;
930 
931             const DetectContentData *cd = (DetectContentData *)sm->ctx;
932             /* skip_negated_content is only set if there's absolutely no
933              * non-negated content present in the sig */
934             if ((cd->flags & DETECT_CONTENT_NEGATED) && skip_negated_content)
935                 continue;
936             if (max_len < cd->content_len)
937                 max_len = cd->content_len;
938         }
939     }
940 
941     for (int i = 0; i < count_final_sm_list; i++) {
942         if (final_sm_list[i] >= (int)s->init_data->smlists_array_size)
943             continue;
944 
945         mpm_sm = GetMpmForList(s, final_sm_list[i], mpm_sm, max_len, skip_negated_content);
946     }
947 
948     /* assign to signature */
949     SetMpm(s, mpm_sm);
950     return;
951 }
952 
953 /** \internal
954  *  \brief The hash function for MpmStore
955  *
956  *  \param ht      Pointer to the hash table.
957  *  \param data    Pointer to the MpmStore.
958  *  \param datalen Not used in our case.
959  *
960  *  \retval hash The generated hash value.
961  */
MpmStoreHashFunc(HashListTable * ht,void * data,uint16_t datalen)962 static uint32_t MpmStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen)
963 {
964     const MpmStore *ms = (MpmStore *)data;
965     uint32_t hash = 0;
966     uint32_t b = 0;
967 
968     for (b = 0; b < ms->sid_array_size; b++)
969         hash += ms->sid_array[b];
970 
971     return hash % ht->array_size;
972 }
973 
974 /**
975  * \brief The Compare function for MpmStore
976  *
977  * \param data1 Pointer to the first MpmStore.
978  * \param len1  Not used.
979  * \param data2 Pointer to the second MpmStore.
980  * \param len2  Not used.
981  *
982  * \retval 1 If the 2 MpmStores sent as args match.
983  * \retval 0 If the 2 MpmStores sent as args do not match.
984  */
MpmStoreCompareFunc(void * data1,uint16_t len1,void * data2,uint16_t len2)985 static char MpmStoreCompareFunc(void *data1, uint16_t len1, void *data2,
986                                 uint16_t len2)
987 {
988     const MpmStore *ms1 = (MpmStore *)data1;
989     const MpmStore *ms2 = (MpmStore *)data2;
990 
991     if (ms1->sid_array_size != ms2->sid_array_size)
992         return 0;
993 
994     if (ms1->buffer != ms2->buffer)
995         return 0;
996 
997     if (ms1->direction != ms2->direction)
998         return 0;
999 
1000     if (ms1->sm_list != ms2->sm_list)
1001         return 0;
1002 
1003     if (SCMemcmp(ms1->sid_array, ms2->sid_array,
1004                  ms1->sid_array_size) != 0)
1005     {
1006         return 0;
1007     }
1008 
1009     return 1;
1010 }
1011 
MpmStoreFreeFunc(void * ptr)1012 static void MpmStoreFreeFunc(void *ptr)
1013 {
1014     MpmStore *ms = ptr;
1015     if (ms != NULL) {
1016         if (ms->mpm_ctx != NULL && !(ms->mpm_ctx->flags & MPMCTX_FLAGS_GLOBAL))
1017         {
1018             SCLogDebug("destroying mpm_ctx %p", ms->mpm_ctx);
1019             mpm_table[ms->mpm_ctx->mpm_type].DestroyCtx(ms->mpm_ctx);
1020             SCFree(ms->mpm_ctx);
1021         }
1022         ms->mpm_ctx = NULL;
1023 
1024         SCFree(ms->sid_array);
1025         SCFree(ms);
1026     }
1027 }
1028 
1029 /**
1030  * \brief Initializes the MpmStore mpm hash table to be used by the detection
1031  *        engine context.
1032  *
1033  * \param de_ctx Pointer to the detection engine context.
1034  *
1035  * \retval  0 On success.
1036  * \retval -1 On failure.
1037  */
MpmStoreInit(DetectEngineCtx * de_ctx)1038 int MpmStoreInit(DetectEngineCtx *de_ctx)
1039 {
1040     de_ctx->mpm_hash_table = HashListTableInit(4096,
1041                                                MpmStoreHashFunc,
1042                                                MpmStoreCompareFunc,
1043                                                MpmStoreFreeFunc);
1044     if (de_ctx->mpm_hash_table == NULL)
1045         goto error;
1046 
1047     return 0;
1048 
1049 error:
1050     return -1;
1051 }
1052 
1053 /**
1054  * \brief Adds a MpmStore to the detection engine context MpmStore
1055  *
1056  * \param de_ctx Pointer to the detection engine context.
1057  * \param sgh    Pointer to the MpmStore.
1058  *
1059  * \retval ret 0 on Successfully adding the argument sgh; -1 on failure.
1060  */
MpmStoreAdd(DetectEngineCtx * de_ctx,MpmStore * s)1061 static int MpmStoreAdd(DetectEngineCtx *de_ctx, MpmStore *s)
1062 {
1063     int ret = HashListTableAdd(de_ctx->mpm_hash_table, (void *)s, 0);
1064     return ret;
1065 }
1066 
1067 /**
1068  * \brief Used to lookup a MpmStore from the MpmStore
1069  *
1070  * \param de_ctx Pointer to the detection engine context.
1071  * \param sgh    Pointer to the MpmStore.
1072  *
1073  * \retval rsgh On success a pointer to the MpmStore if the MpmStore is
1074  *              found in the hash table; NULL on failure.
1075  */
MpmStoreLookup(DetectEngineCtx * de_ctx,MpmStore * s)1076 static MpmStore *MpmStoreLookup(DetectEngineCtx *de_ctx, MpmStore *s)
1077 {
1078     MpmStore *rs = HashListTableLookup(de_ctx->mpm_hash_table,
1079                                              (void *)s, 0);
1080     return rs;
1081 }
1082 
GetByMpmStore(const DetectEngineCtx * de_ctx,const MpmStore * ms)1083 static const DetectBufferMpmRegistery *GetByMpmStore(const DetectEngineCtx *de_ctx,
1084         const MpmStore *ms)
1085 {
1086     const DetectBufferMpmRegistery *am = de_ctx->app_mpms_list;
1087     while (am != NULL) {
1088         if (ms->sm_list == am->sm_list &&
1089             ms->direction == am->direction) {
1090             return am;
1091         }
1092         am = am->next;
1093     }
1094     am = de_ctx->pkt_mpms_list;
1095     while (am != NULL) {
1096         if (ms->sm_list == am->sm_list) {
1097             return am;
1098         }
1099         am = am->next;
1100     }
1101     return NULL;
1102 }
1103 
MpmStoreReportStats(const DetectEngineCtx * de_ctx)1104 void MpmStoreReportStats(const DetectEngineCtx *de_ctx)
1105 {
1106     HashListTableBucket *htb = NULL;
1107 
1108     uint32_t stats[MPMB_MAX] = {0};
1109     int app_mpms_cnt = de_ctx->buffer_type_map_elements;
1110     uint32_t appstats[app_mpms_cnt + 1];    // +1 to silence scan-build
1111     memset(&appstats, 0x00, sizeof(appstats));
1112     int pkt_mpms_cnt = de_ctx->buffer_type_map_elements;
1113     uint32_t pktstats[pkt_mpms_cnt + 1];    // +1 to silence scan-build
1114     memset(&pktstats, 0x00, sizeof(pktstats));
1115 
1116     for (htb = HashListTableGetListHead(de_ctx->mpm_hash_table);
1117             htb != NULL;
1118             htb = HashListTableGetListNext(htb))
1119     {
1120         const MpmStore *ms = (MpmStore *)HashListTableGetListData(htb);
1121         if (ms == NULL || ms->mpm_ctx == NULL) {
1122             continue;
1123         }
1124         if (ms->buffer < MPMB_MAX)
1125             stats[ms->buffer]++;
1126         else if (ms->sm_list != DETECT_SM_LIST_PMATCH) {
1127             const DetectBufferMpmRegistery *am = GetByMpmStore(de_ctx, ms);
1128             if (am != NULL) {
1129                 switch (am->type) {
1130                     case DETECT_BUFFER_MPM_TYPE_PKT:
1131                         SCLogDebug("%s: %u patterns. Min %u, Max %u. Ctx %p",
1132                                 am->name,
1133                                 ms->mpm_ctx->pattern_cnt,
1134                                 ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen,
1135                                 ms->mpm_ctx);
1136                         pktstats[am->sm_list]++;
1137                         break;
1138                     case DETECT_BUFFER_MPM_TYPE_APP:
1139                         SCLogDebug("%s %s: %u patterns. Min %u, Max %u. Ctx %p",
1140                                 am->name,
1141                                 am->direction == SIG_FLAG_TOSERVER ? "toserver":"toclient",
1142                                 ms->mpm_ctx->pattern_cnt,
1143                                 ms->mpm_ctx->minlen, ms->mpm_ctx->maxlen,
1144                                 ms->mpm_ctx);
1145                         appstats[am->sm_list]++;
1146                         break;
1147                     case DETECT_BUFFER_MPM_TYPE_SIZE:
1148                         break;
1149                 }
1150             }
1151         }
1152     }
1153 
1154     if (!(de_ctx->flags & DE_QUIET)) {
1155         for (int x = 0; x < MPMB_MAX; x++) {
1156             SCLogPerf("Builtin MPM \"%s\": %u", builtin_mpms[x], stats[x]);
1157         }
1158         const DetectBufferMpmRegistery *am = de_ctx->app_mpms_list;
1159         while (am != NULL) {
1160             if (appstats[am->sm_list] > 0) {
1161                 const char *name = am->name;
1162                 const char *direction = am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient";
1163                 SCLogPerf("AppLayer MPM \"%s %s (%s)\": %u", direction, name,
1164                         AppProtoToString(am->app_v2.alproto), appstats[am->sm_list]);
1165             }
1166             am = am->next;
1167         }
1168         const DetectBufferMpmRegistery *pm = de_ctx->pkt_mpms_list;
1169         while (pm != NULL) {
1170             if (pktstats[pm->sm_list] > 0) {
1171                 const char *name = pm->name;
1172                 SCLogPerf("Pkt MPM \"%s\": %u", name, pktstats[pm->sm_list]);
1173             }
1174             pm = pm->next;
1175         }
1176     }
1177 }
1178 
1179 /**
1180  * \brief Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by
1181  *        MpmStoreInit() function.
1182  *
1183  * \param de_ctx Pointer to the detection engine context.
1184  */
MpmStoreFree(DetectEngineCtx * de_ctx)1185 void MpmStoreFree(DetectEngineCtx *de_ctx)
1186 {
1187     if (de_ctx->mpm_hash_table == NULL)
1188         return;
1189 
1190     HashListTableFree(de_ctx->mpm_hash_table);
1191     de_ctx->mpm_hash_table = NULL;
1192     return;
1193 }
1194 
MpmStoreSetup(const DetectEngineCtx * de_ctx,MpmStore * ms)1195 static void MpmStoreSetup(const DetectEngineCtx *de_ctx, MpmStore *ms)
1196 {
1197     const Signature *s = NULL;
1198     uint32_t sig;
1199     int dir = 0;
1200 
1201     if (ms->buffer != MPMB_MAX) {
1202         BUG_ON(ms->sm_list != DETECT_SM_LIST_PMATCH);
1203 
1204         switch (ms->buffer) {
1205             /* TS is 1 */
1206             case MPMB_TCP_PKT_TS:
1207             case MPMB_TCP_STREAM_TS:
1208             case MPMB_UDP_TS:
1209                 dir = 1;
1210                 break;
1211 
1212                 /* TC is 0 */
1213             default:
1214             case MPMB_UDP_TC:
1215             case MPMB_TCP_STREAM_TC:
1216             case MPMB_TCP_PKT_TC:
1217             case MPMB_OTHERIP:          /**< use 0 for other */
1218                 dir = 0;
1219                 break;
1220         }
1221     } else {
1222         BUG_ON(ms->sm_list == DETECT_SM_LIST_PMATCH);
1223 
1224         if (ms->direction == SIG_FLAG_TOSERVER)
1225             dir = 1;
1226         else
1227             dir = 0;
1228     }
1229 
1230     ms->mpm_ctx = MpmFactoryGetMpmCtxForProfile(de_ctx, ms->sgh_mpm_context, dir);
1231     if (ms->mpm_ctx == NULL)
1232         return;
1233 
1234     MpmInitCtx(ms->mpm_ctx, de_ctx->mpm_matcher);
1235 
1236     /* add the patterns */
1237     for (sig = 0; sig < (ms->sid_array_size * 8); sig++) {
1238         if (ms->sid_array[sig / 8] & (1 << (sig % 8))) {
1239             s = de_ctx->sig_array[sig];
1240             if (s == NULL)
1241                 continue;
1242             if ((s->flags & ms->direction) == 0)
1243                 continue;
1244             if (s->init_data->mpm_sm == NULL)
1245                 continue;
1246             int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1247             if (list < 0)
1248                 continue;
1249             if (list != ms->sm_list)
1250                 continue;
1251 
1252             SCLogDebug("adding %u", s->id);
1253 
1254             const DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx;
1255 
1256             int skip = 0;
1257             /* negated logic: if mpm match can't be used to be sure about this
1258              * pattern, we have to inspect the rule fully regardless of mpm
1259              * match. So in this case there is no point of adding it at all.
1260              * The non-mpm list entry for the sig will make sure the sig is
1261              * inspected. */
1262             if ((cd->flags & DETECT_CONTENT_NEGATED) &&
1263                 !(DETECT_CONTENT_MPM_IS_CONCLUSIVE(cd)))
1264             {
1265                 skip = 1;
1266                 SCLogDebug("not adding negated mpm as it's not 'single'");
1267             }
1268 
1269             if (!skip) {
1270                 PopulateMpmHelperAddPattern(ms->mpm_ctx,
1271                         cd, s, 0, (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP));
1272             }
1273         }
1274     }
1275 
1276     if (ms->mpm_ctx->pattern_cnt == 0) {
1277         MpmFactoryReClaimMpmCtx(de_ctx, ms->mpm_ctx);
1278         ms->mpm_ctx = NULL;
1279     } else {
1280         if (ms->sgh_mpm_context == MPM_CTX_FACTORY_UNIQUE_CONTEXT) {
1281             if (mpm_table[ms->mpm_ctx->mpm_type].Prepare != NULL) {
1282                 mpm_table[ms->mpm_ctx->mpm_type].Prepare(ms->mpm_ctx);
1283             }
1284         }
1285     }
1286 }
1287 
1288 
1289 /** \brief Get MpmStore for a built-in buffer type
1290  *
1291  */
MpmStorePrepareBuffer(DetectEngineCtx * de_ctx,SigGroupHead * sgh,enum MpmBuiltinBuffers buf)1292 MpmStore *MpmStorePrepareBuffer(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
1293                                 enum MpmBuiltinBuffers buf)
1294 {
1295     const Signature *s = NULL;
1296     uint32_t sig;
1297     uint32_t cnt = 0;
1298     int direction = 0;
1299     uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1300     uint8_t sids_array[max_sid];
1301     memset(sids_array, 0x00, max_sid);
1302     int sgh_mpm_context = 0;
1303     int sm_list = DETECT_SM_LIST_PMATCH;
1304 
1305     switch (buf) {
1306         case MPMB_TCP_PKT_TS:
1307         case MPMB_TCP_PKT_TC:
1308             sgh_mpm_context = de_ctx->sgh_mpm_context_proto_tcp_packet;
1309             break;
1310         case MPMB_TCP_STREAM_TS:
1311         case MPMB_TCP_STREAM_TC:
1312             sgh_mpm_context = de_ctx->sgh_mpm_context_stream;
1313             break;
1314         case MPMB_UDP_TS:
1315         case MPMB_UDP_TC:
1316             sgh_mpm_context = de_ctx->sgh_mpm_context_proto_udp_packet;
1317             break;
1318         case MPMB_OTHERIP:
1319             sgh_mpm_context = de_ctx->sgh_mpm_context_proto_other_packet;
1320             break;
1321         default:
1322             break;
1323     }
1324 
1325     switch(buf) {
1326         case MPMB_TCP_PKT_TS:
1327         case MPMB_TCP_STREAM_TS:
1328         case MPMB_UDP_TS:
1329             direction = SIG_FLAG_TOSERVER;
1330             break;
1331 
1332         case MPMB_TCP_PKT_TC:
1333         case MPMB_TCP_STREAM_TC:
1334         case MPMB_UDP_TC:
1335             direction = SIG_FLAG_TOCLIENT;
1336             break;
1337 
1338         case MPMB_OTHERIP:
1339             direction = (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER);
1340             break;
1341 
1342         case MPMB_MAX:
1343             BUG_ON(1);
1344             break;
1345     }
1346 
1347     for (sig = 0; sig < sgh->sig_cnt; sig++) {
1348         s = sgh->match_array[sig];
1349         if (s == NULL)
1350             continue;
1351 
1352         if (s->init_data->mpm_sm == NULL)
1353             continue;
1354 
1355         int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1356         if (list < 0)
1357             continue;
1358 
1359         if (list != DETECT_SM_LIST_PMATCH)
1360             continue;
1361 
1362         switch (buf) {
1363             case MPMB_TCP_PKT_TS:
1364             case MPMB_TCP_PKT_TC:
1365                 if (SignatureHasPacketContent(s) == 1)
1366                 {
1367                     sids_array[s->num / 8] |= 1 << (s->num % 8);
1368                     cnt++;
1369                 }
1370                 break;
1371             case MPMB_TCP_STREAM_TS:
1372             case MPMB_TCP_STREAM_TC:
1373                 if (SignatureHasStreamContent(s) == 1)
1374                 {
1375                     sids_array[s->num / 8] |= 1 << (s->num % 8);
1376                     cnt++;
1377                 }
1378                 break;
1379             case MPMB_UDP_TS:
1380             case MPMB_UDP_TC:
1381                 sids_array[s->num / 8] |= 1 << (s->num % 8);
1382                 cnt++;
1383                 break;
1384             case MPMB_OTHERIP:
1385                 sids_array[s->num / 8] |= 1 << (s->num % 8);
1386                 cnt++;
1387                 break;
1388             default:
1389                 break;
1390         }
1391     }
1392 
1393     if (cnt == 0)
1394         return NULL;
1395 
1396     MpmStore lookup = { sids_array, max_sid, direction, buf, sm_list, 0, NULL};
1397 
1398     MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1399     if (result == NULL) {
1400         MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1401         if (copy == NULL)
1402             return NULL;
1403         uint8_t *sids = SCCalloc(1, max_sid);
1404         if (sids == NULL) {
1405             SCFree(copy);
1406             return NULL;
1407         }
1408 
1409         memcpy(sids, sids_array, max_sid);
1410         copy->sid_array = sids;
1411         copy->sid_array_size = max_sid;
1412         copy->buffer = buf;
1413         copy->direction = direction;
1414         copy->sm_list = sm_list;
1415         copy->sgh_mpm_context = sgh_mpm_context;
1416 
1417         MpmStoreSetup(de_ctx, copy);
1418         MpmStoreAdd(de_ctx, copy);
1419         return copy;
1420     } else {
1421         return result;
1422     }
1423 }
1424 
MpmStorePrepareBufferAppLayer(DetectEngineCtx * de_ctx,SigGroupHead * sgh,const DetectBufferMpmRegistery * am)1425 static MpmStore *MpmStorePrepareBufferAppLayer(DetectEngineCtx *de_ctx,
1426         SigGroupHead *sgh, const DetectBufferMpmRegistery *am)
1427 {
1428     const Signature *s = NULL;
1429     uint32_t sig;
1430     uint32_t cnt = 0;
1431     uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1432     uint8_t sids_array[max_sid];
1433     memset(sids_array, 0x00, max_sid);
1434 
1435     SCLogDebug("handling %s direction %s for list %d", am->name,
1436             am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1437             am->sm_list);
1438 
1439     for (sig = 0; sig < sgh->sig_cnt; sig++) {
1440         s = sgh->match_array[sig];
1441         if (s == NULL)
1442             continue;
1443 
1444         if (s->init_data->mpm_sm == NULL)
1445             continue;
1446 
1447         int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1448         if (list < 0)
1449             continue;
1450 
1451         if ((s->flags & am->direction) == 0)
1452             continue;
1453 
1454         if (list != am->sm_list)
1455             continue;
1456 
1457         sids_array[s->num / 8] |= 1 << (s->num % 8);
1458         cnt++;
1459     }
1460 
1461     if (cnt == 0)
1462         return NULL;
1463 
1464     MpmStore lookup = { sids_array, max_sid, am->direction,
1465         MPMB_MAX, am->sm_list, 0, NULL};
1466     SCLogDebug("am->direction %d am->sm_list %d",
1467             am->direction, am->sm_list);
1468 
1469     MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1470     if (result == NULL) {
1471         SCLogDebug("new unique mpm for %s %s: %u patterns",
1472                 am->name,
1473                 am->direction == SIG_FLAG_TOSERVER ? "toserver" : "toclient",
1474                 cnt);
1475 
1476         MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1477         if (copy == NULL)
1478             return NULL;
1479         uint8_t *sids = SCCalloc(1, max_sid);
1480         if (sids == NULL) {
1481             SCFree(copy);
1482             return NULL;
1483         }
1484 
1485         memcpy(sids, sids_array, max_sid);
1486         copy->sid_array = sids;
1487         copy->sid_array_size = max_sid;
1488         copy->buffer = MPMB_MAX;
1489         copy->direction = am->direction;
1490         copy->sm_list = am->sm_list;
1491         copy->sgh_mpm_context = am->sgh_mpm_context;
1492 
1493         MpmStoreSetup(de_ctx, copy);
1494         MpmStoreAdd(de_ctx, copy);
1495         return copy;
1496     } else {
1497         SCLogDebug("using existing mpm %p", result);
1498         return result;
1499     }
1500     return NULL;
1501 }
1502 
MpmStorePrepareBufferPkt(DetectEngineCtx * de_ctx,SigGroupHead * sgh,const DetectBufferMpmRegistery * am)1503 static MpmStore *MpmStorePrepareBufferPkt(DetectEngineCtx *de_ctx,
1504         SigGroupHead *sgh, const DetectBufferMpmRegistery *am)
1505 {
1506     const Signature *s = NULL;
1507     uint32_t sig;
1508     uint32_t cnt = 0;
1509     uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx) / 8 + 1;
1510     uint8_t sids_array[max_sid];
1511     memset(sids_array, 0x00, max_sid);
1512 
1513     SCLogDebug("handling %s for list %d", am->name,
1514             am->sm_list);
1515 
1516     for (sig = 0; sig < sgh->sig_cnt; sig++) {
1517         s = sgh->match_array[sig];
1518         if (s == NULL)
1519             continue;
1520 
1521         if (s->init_data->mpm_sm == NULL)
1522             continue;
1523 
1524         int list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1525         if (list < 0)
1526             continue;
1527 
1528         if (list != am->sm_list)
1529             continue;
1530 
1531         sids_array[s->num / 8] |= 1 << (s->num % 8);
1532         cnt++;
1533     }
1534 
1535     if (cnt == 0)
1536         return NULL;
1537 
1538     MpmStore lookup = { sids_array, max_sid, SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT,
1539         MPMB_MAX, am->sm_list, 0, NULL};
1540     SCLogDebug("am->sm_list %d", am->sm_list);
1541 
1542     MpmStore *result = MpmStoreLookup(de_ctx, &lookup);
1543     if (result == NULL) {
1544         SCLogDebug("new unique mpm for %s: %u patterns",
1545                 am->name, cnt);
1546 
1547         MpmStore *copy = SCCalloc(1, sizeof(MpmStore));
1548         if (copy == NULL)
1549             return NULL;
1550         uint8_t *sids = SCCalloc(1, max_sid);
1551         if (sids == NULL) {
1552             SCFree(copy);
1553             return NULL;
1554         }
1555 
1556         memcpy(sids, sids_array, max_sid);
1557         copy->sid_array = sids;
1558         copy->sid_array_size = max_sid;
1559         copy->buffer = MPMB_MAX;
1560         copy->direction = SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT;
1561         copy->sm_list = am->sm_list;
1562         copy->sgh_mpm_context = am->sgh_mpm_context;
1563 
1564         MpmStoreSetup(de_ctx, copy);
1565         MpmStoreAdd(de_ctx, copy);
1566         return copy;
1567     } else {
1568         SCLogDebug("using existing mpm %p", result);
1569         return result;
1570     }
1571     return NULL;
1572 }
1573 
SetRawReassemblyFlag(DetectEngineCtx * de_ctx,SigGroupHead * sgh)1574 static void SetRawReassemblyFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
1575 {
1576     const Signature *s = NULL;
1577     uint32_t sig;
1578 
1579     for (sig = 0; sig < sgh->sig_cnt; sig++) {
1580         s = sgh->match_array[sig];
1581         if (s == NULL)
1582             continue;
1583 
1584         if (SignatureHasStreamContent(s) == 1) {
1585             sgh->flags |= SIG_GROUP_HEAD_HAVERAWSTREAM;
1586             SCLogDebug("rule group %p has SIG_GROUP_HEAD_HAVERAWSTREAM set", sgh);
1587             return;
1588         }
1589     }
1590     SCLogDebug("rule group %p does NOT have SIG_GROUP_HEAD_HAVERAWSTREAM set", sgh);
1591 }
1592 
PrepareAppMpms(DetectEngineCtx * de_ctx,SigGroupHead * sh)1593 static void PrepareAppMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
1594 {
1595     if (de_ctx->app_mpms_list_cnt == 0)
1596         return;
1597 
1598     sh->init->app_mpms = SCCalloc(de_ctx->app_mpms_list_cnt, sizeof(MpmCtx *));
1599     BUG_ON(sh->init->app_mpms == NULL);
1600 
1601     DetectBufferMpmRegistery *a = de_ctx->app_mpms_list;
1602     while (a != NULL) {
1603         if ((a->direction == SIG_FLAG_TOSERVER && SGH_DIRECTION_TS(sh)) ||
1604             (a->direction == SIG_FLAG_TOCLIENT && SGH_DIRECTION_TC(sh)))
1605         {
1606             MpmStore *mpm_store = MpmStorePrepareBufferAppLayer(de_ctx, sh, a);
1607             if (mpm_store != NULL) {
1608                 sh->init->app_mpms[a->id] = mpm_store->mpm_ctx;
1609 
1610                 SCLogDebug("a %p a->name %s a->PrefilterRegisterWithListId %p "
1611                         "mpm_store->mpm_ctx %p", a, a->name,
1612                         a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
1613 
1614                 /* if we have just certain types of negated patterns,
1615                  * mpm_ctx can be NULL */
1616                 if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
1617                     BUG_ON(a->PrefilterRegisterWithListId(de_ctx,
1618                                 sh, mpm_store->mpm_ctx,
1619                                 a, a->sm_list) != 0);
1620                     SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
1621                 }
1622             }
1623         }
1624         a = a->next;
1625     }
1626 }
1627 
PreparePktMpms(DetectEngineCtx * de_ctx,SigGroupHead * sh)1628 static void PreparePktMpms(DetectEngineCtx *de_ctx, SigGroupHead *sh)
1629 {
1630     if (de_ctx->pkt_mpms_list_cnt == 0)
1631         return;
1632 
1633     sh->init->pkt_mpms = SCCalloc(de_ctx->pkt_mpms_list_cnt, sizeof(MpmCtx *));
1634     BUG_ON(sh->init->pkt_mpms == NULL);
1635 
1636     DetectBufferMpmRegistery *a = de_ctx->pkt_mpms_list;
1637     while (a != NULL) {
1638         MpmStore *mpm_store = MpmStorePrepareBufferPkt(de_ctx, sh, a);
1639         if (mpm_store != NULL) {
1640             sh->init->pkt_mpms[a->id] = mpm_store->mpm_ctx;
1641 
1642             SCLogDebug("a %p a->name %s a->reg->PrefilterRegisterWithListId %p "
1643                     "mpm_store->mpm_ctx %p", a, a->name,
1644                     a->PrefilterRegisterWithListId, mpm_store->mpm_ctx);
1645 
1646             /* if we have just certain types of negated patterns,
1647              * mpm_ctx can be NULL */
1648             if (a->PrefilterRegisterWithListId && mpm_store->mpm_ctx) {
1649                 BUG_ON(a->PrefilterRegisterWithListId(de_ctx,
1650                             sh, mpm_store->mpm_ctx,
1651                             a, a->sm_list) != 0);
1652                 SCLogDebug("mpm %s %d set up", a->name, a->sm_list);
1653             }
1654         }
1655         a = a->next;
1656     }
1657 }
1658 
1659 /** \brief Prepare the pattern matcher ctx in a sig group head.
1660  *
1661  */
PatternMatchPrepareGroup(DetectEngineCtx * de_ctx,SigGroupHead * sh)1662 int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
1663 {
1664     MpmStore *mpm_store = NULL;
1665     if (SGH_PROTO(sh, IPPROTO_TCP)) {
1666         if (SGH_DIRECTION_TS(sh)) {
1667             mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TS);
1668             if (mpm_store != NULL) {
1669                 PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1670             }
1671 
1672             mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TS);
1673             if (mpm_store != NULL) {
1674                 PrefilterPktStreamRegister(de_ctx, sh, mpm_store->mpm_ctx);
1675             }
1676 
1677             SetRawReassemblyFlag(de_ctx, sh);
1678         }
1679         if (SGH_DIRECTION_TC(sh)) {
1680             mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_PKT_TC);
1681             if (mpm_store != NULL) {
1682                 PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1683             }
1684 
1685             mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_TCP_STREAM_TC);
1686             if (mpm_store != NULL) {
1687                 PrefilterPktStreamRegister(de_ctx, sh, mpm_store->mpm_ctx);
1688             }
1689 
1690             SetRawReassemblyFlag(de_ctx, sh);
1691        }
1692     } else if (SGH_PROTO(sh, IPPROTO_UDP)) {
1693         if (SGH_DIRECTION_TS(sh)) {
1694             mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TS);
1695             if (mpm_store != NULL) {
1696                 PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1697             }
1698         }
1699         if (SGH_DIRECTION_TC(sh)) {
1700             mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_UDP_TC);
1701             if (mpm_store != NULL) {
1702                 PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1703             }
1704         }
1705     } else {
1706         mpm_store = MpmStorePrepareBuffer(de_ctx, sh, MPMB_OTHERIP);
1707         if (mpm_store != NULL) {
1708             PrefilterPktPayloadRegister(de_ctx, sh, mpm_store->mpm_ctx);
1709         }
1710     }
1711 
1712     PrepareAppMpms(de_ctx, sh);
1713     PreparePktMpms(de_ctx, sh);
1714     return 0;
1715 }
1716 
1717 typedef struct DetectFPAndItsId_ {
1718     PatIntId id;
1719     uint16_t content_len;
1720     uint32_t flags;
1721     int sm_list;
1722 
1723     uint8_t *content;
1724 } DetectFPAndItsId;
1725 
1726 /**
1727  * \brief Figured out the FP and their respective content ids for all the
1728  *        sigs in the engine.
1729  *
1730  * \param de_ctx Detection engine context.
1731  *
1732  * \retval  0 On success.
1733  * \retval -1 On failure.
1734  */
DetectSetFastPatternAndItsId(DetectEngineCtx * de_ctx)1735 int DetectSetFastPatternAndItsId(DetectEngineCtx *de_ctx)
1736 {
1737     uint32_t struct_total_size = 0;
1738     uint32_t content_total_size = 0;
1739     Signature *s = NULL;
1740 
1741     /* Count the amount of memory needed to store all the structures
1742      * and the content of those structures. This will over estimate the
1743      * true size, since duplicates are removed below, but counted here.
1744      */
1745     for (s = de_ctx->sig_list; s != NULL; s = s->next) {
1746         if (s->flags & SIG_FLAG_PREFILTER)
1747             continue;
1748 
1749         RetrieveFPForSig(de_ctx, s);
1750         if (s->init_data->mpm_sm != NULL) {
1751             DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx;
1752             struct_total_size += sizeof(DetectFPAndItsId);
1753             content_total_size += cd->content_len;
1754 
1755             s->flags |= SIG_FLAG_PREFILTER;
1756         }
1757     }
1758     /* no rules */
1759     if (struct_total_size + content_total_size == 0)
1760         return 0;
1761 
1762     /* array hash buffer - I've run out of ideas to name it */
1763     uint8_t *ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size));
1764     if (unlikely(ahb == NULL))
1765         return -1;
1766 
1767     uint8_t *content = NULL;
1768     uint16_t content_len = 0;
1769     PatIntId max_id = 0;
1770     DetectFPAndItsId *struct_offset = (DetectFPAndItsId *)ahb;
1771     uint8_t *content_offset = ahb + struct_total_size;
1772 
1773     for (s = de_ctx->sig_list; s != NULL; s = s->next) {
1774         if (s->init_data->mpm_sm != NULL) {
1775             int sm_list = SigMatchListSMBelongsTo(s, s->init_data->mpm_sm);
1776             BUG_ON(sm_list == -1);
1777 
1778             DetectContentData *cd = (DetectContentData *)s->init_data->mpm_sm->ctx;
1779             DetectFPAndItsId *dup = (DetectFPAndItsId *)ahb;
1780             if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
1781                 content = cd->content + cd->fp_chop_offset;
1782                 content_len = cd->fp_chop_len;
1783             } else {
1784                 content = cd->content;
1785                 content_len = cd->content_len;
1786             }
1787             uint32_t flags = cd->flags & DETECT_CONTENT_NOCASE;
1788             /* Check for content already found on the same list */
1789             for (; dup != struct_offset; dup++) {
1790                 if (dup->content_len != content_len)
1791                     continue;
1792                 if (dup->sm_list != sm_list)
1793                     continue;
1794                 if (dup->flags != flags)
1795                     continue;
1796                 /* Check for pattern matching a duplicate. Use case insensitive matching
1797                  * for case insensitive patterns. */
1798                 if (flags & DETECT_CONTENT_NOCASE) {
1799                     if (SCMemcmpLowercase(dup->content, content, content_len) != 0)
1800                         continue;
1801                 } else {
1802                     /* Case sensitive matching */
1803                     if (SCMemcmp(dup->content, content, content_len) != 0)
1804                         continue;
1805                 }
1806                 /* Found a match with a previous pattern. */
1807                 break;
1808             }
1809             if (dup != struct_offset) {
1810                 /* Exited for-loop before the end, so found an existing match.
1811                  * Use its ID. */
1812                 cd->id = dup->id;
1813                 continue;
1814             }
1815 
1816             /* Not found, so new content. Give it a new ID and add it
1817              * to the array.  Copy the content at the end of the
1818              * content array.
1819              */
1820             struct_offset->id = max_id++;
1821             cd->id = struct_offset->id;
1822             struct_offset->content_len = content_len;
1823             struct_offset->sm_list = sm_list;
1824             struct_offset->content = content_offset;
1825             struct_offset->flags = flags;
1826 
1827             content_offset += content_len;
1828 
1829             if (flags & DETECT_CONTENT_NOCASE) {
1830                 /* Need to store case-insensitive patterns as lower case
1831                  * because SCMemcmpLowercase() above assumes that all
1832                  * patterns are stored lower case so that it doesn't
1833                  * need to re-lower its first argument.
1834                  */
1835                 memcpy_tolower(struct_offset->content, content, content_len);
1836             } else {
1837                 memcpy(struct_offset->content, content, content_len);
1838             }
1839 
1840             struct_offset++;
1841         } /* if (s->mpm_sm != NULL) */
1842     } /* for */
1843 
1844     de_ctx->max_fp_id = max_id;
1845 
1846     SCFree(ahb);
1847 
1848     return 0;
1849 }
1850