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