Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-engine.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 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
 */
23
24
#include "suricata-common.h"
25
#include "suricata.h"
26
#include "detect.h"
27
#include "flow.h"
28
#include "flow-private.h"
29
#include "flow-util.h"
30
#include "flow-worker.h"
31
#include "conf.h"
32
#include "conf-yaml-loader.h"
33
#include "datasets.h"
34
35
#include "app-layer-parser.h"
36
#include "app-layer-events.h"
37
#include "app-layer-htp.h"
38
39
#include "detect-parse.h"
40
#include "detect-engine-sigorder.h"
41
42
#include "detect-engine-build.h"
43
#include "detect-engine-siggroup.h"
44
#include "detect-engine-address.h"
45
#include "detect-engine-port.h"
46
#include "detect-engine-prefilter.h"
47
#include "detect-engine-mpm.h"
48
#include "detect-engine-iponly.h"
49
#include "detect-engine-tag.h"
50
#include "detect-engine-frame.h"
51
52
#include "detect-engine-file.h"
53
54
#include "detect-engine.h"
55
#include "detect-engine-state.h"
56
#include "detect-engine-payload.h"
57
#include "detect-fast-pattern.h"
58
#include "detect-byte-extract.h"
59
#include "detect-content.h"
60
#include "detect-uricontent.h"
61
#include "detect-tcphdr.h"
62
#include "detect-engine-threshold.h"
63
#include "detect-engine-content-inspection.h"
64
65
#include "detect-engine-loader.h"
66
67
#include "detect-engine-alert.h"
68
69
#include "util-classification-config.h"
70
#include "util-reference-config.h"
71
#include "util-threshold-config.h"
72
#include "util-error.h"
73
#include "util-hash.h"
74
#include "util-byte.h"
75
#include "util-debug.h"
76
#include "util-unittest.h"
77
#include "util-action.h"
78
#include "util-magic.h"
79
#include "util-signal.h"
80
#include "util-spm.h"
81
#include "util-device-private.h"
82
#include "util-var-name.h"
83
#include "util-path.h"
84
#include "util-profiling.h"
85
#include "util-validate.h"
86
#include "util-hash-string.h"
87
#include "util-enum.h"
88
#include "util-conf.h"
89
90
#include "tm-threads.h"
91
#include "runmodes.h"
92
93
#include "reputation.h"
94
95
114k
#define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000
96
97
static int DetectEngineCtxLoadConf(DetectEngineCtx *);
98
99
static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
100
    0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0};
101
102
static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
103
static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
104
static void TenantIdFree(void *d);
105
static uint32_t DetectEngineTenantGetIdFromLivedev(const void *ctx, const Packet *p);
106
static uint32_t DetectEngineTenantGetIdFromVlanId(const void *ctx, const Packet *p);
107
static uint32_t DetectEngineTenantGetIdFromPcap(const void *ctx, const Packet *p);
108
109
static bool DetectEngineMultiTenantEnabledWithLock(void);
110
static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL;
111
static DetectEnginePktInspectionEngine *g_pkt_inspect_engines = NULL;
112
static DetectEngineFrameInspectionEngine *g_frame_inspect_engines = NULL;
113
114
// clang-format off
115
// rule types documentation tag start: SignatureProperties
116
const struct SignatureProperties signature_properties[SIG_TYPE_MAX] = {
117
    /* SIG_TYPE_NOT_SET */      { SIG_PROP_FLOW_ACTION_PACKET, },
118
    /* SIG_TYPE_IPONLY */       { SIG_PROP_FLOW_ACTION_FLOW, },
119
    /* SIG_TYPE_LIKE_IPONLY */  { SIG_PROP_FLOW_ACTION_FLOW, },
120
    /* SIG_TYPE_PDONLY */       { SIG_PROP_FLOW_ACTION_FLOW, },
121
    /* SIG_TYPE_DEONLY */       { SIG_PROP_FLOW_ACTION_PACKET, },
122
    /* SIG_TYPE_PKT */          { SIG_PROP_FLOW_ACTION_PACKET, },
123
    /* SIG_TYPE_PKT_STREAM */   { SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL, },
124
    /* SIG_TYPE_STREAM */       { SIG_PROP_FLOW_ACTION_FLOW_IF_STATEFUL, },
125
    /* SIG_TYPE_APPLAYER */     { SIG_PROP_FLOW_ACTION_FLOW, },
126
    /* SIG_TYPE_APP_TX */       { SIG_PROP_FLOW_ACTION_FLOW, },
127
};
128
// rule types documentation tag end: SignatureProperties
129
// clang-format on
130
131
const char *DetectTableToString(enum DetectTable table)
132
0
{
133
0
    switch (table) {
134
0
        case DETECT_TABLE_NOT_SET:
135
0
            return "not_set";
136
0
        case DETECT_TABLE_PACKET_PRE_FLOW:
137
0
            return "pre_flow";
138
0
        case DETECT_TABLE_PACKET_PRE_STREAM:
139
0
            return "pre_stream";
140
0
        case DETECT_TABLE_PACKET_FILTER:
141
0
            return "packet_filter";
142
0
        case DETECT_TABLE_PACKET_TD:
143
0
            return "packet_td";
144
0
        case DETECT_TABLE_APP_FILTER:
145
0
            return "app_filter";
146
0
        case DETECT_TABLE_APP_TD:
147
0
            return "app_td";
148
0
        default:
149
0
            return "unknown";
150
0
    }
151
0
}
152
153
/** \brief register inspect engine at start up time
154
 *
155
 *  \note errors are fatal */
156
void DetectPktInspectEngineRegister(const char *name,
157
        InspectionBufferGetPktDataPtr GetPktData,
158
        InspectionBufferPktInspectFunc Callback)
159
792
{
160
792
    DetectBufferTypeRegister(name);
161
792
    const int sm_list = DetectBufferTypeGetByName(name);
162
792
    if (sm_list == -1) {
163
0
        FatalError("failed to register inspect engine %s", name);
164
0
    }
165
166
792
    if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
167
792
        (Callback == NULL))
168
0
    {
169
0
        SCLogError("Invalid arguments");
170
0
        BUG_ON(1);
171
0
    }
172
173
792
    DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
174
792
    if (unlikely(new_engine == NULL)) {
175
0
        FatalError("failed to register inspect engine %s: %s", name, strerror(errno));
176
0
    }
177
792
    new_engine->sm_list = (uint16_t)sm_list;
178
792
    new_engine->sm_list_base = (uint16_t)sm_list;
179
792
    new_engine->v1.Callback = Callback;
180
792
    new_engine->v1.GetData = GetPktData;
181
182
792
    if (g_pkt_inspect_engines == NULL) {
183
79
        g_pkt_inspect_engines = new_engine;
184
713
    } else {
185
713
        DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
186
3.73k
        while (t->next != NULL) {
187
3.01k
            t = t->next;
188
3.01k
        }
189
190
713
        t->next = new_engine;
191
713
    }
192
792
}
193
194
/** \brief register inspect engine at start up time
195
 *
196
 *  \note errors are fatal */
197
static void AppLayerInspectEngineRegisterInternal(const char *name, AppProto alproto, uint32_t dir,
198
        int progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData,
199
        InspectionSingleBufferGetDataPtr GetDataSingle,
200
        InspectionMultiBufferGetDataPtr GetMultiData)
201
26.1k
{
202
26.1k
    BUG_ON(progress >= 48);
203
204
26.1k
    DetectBufferTypeRegister(name);
205
26.1k
    const int sm_list = DetectBufferTypeGetByName(name);
206
26.1k
    if (sm_list == -1) {
207
0
        FatalError("failed to register inspect engine %s", name);
208
0
    }
209
26.1k
    SCLogDebug("name %s id %d", name, sm_list);
210
211
26.1k
    if ((alproto == ALPROTO_FAILED) || (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) ||
212
26.1k
            (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
213
26.1k
            (progress < 0 || progress >= SHRT_MAX) || (Callback == NULL)) {
214
0
        SCLogError("Invalid arguments");
215
0
        BUG_ON(1);
216
26.1k
    } else if (Callback == DetectEngineInspectBufferGeneric && GetData == NULL) {
217
0
        SCLogError("Invalid arguments: must register "
218
0
                   "GetData with DetectEngineInspectBufferGeneric");
219
0
        BUG_ON(1);
220
26.1k
    } else if (Callback == DetectEngineInspectBufferSingle && GetDataSingle == NULL) {
221
0
        SCLogError("Invalid arguments: must register "
222
0
                   "GetData with DetectEngineInspectBufferGeneric");
223
0
        BUG_ON(1);
224
26.1k
    } else if (Callback == DetectEngineInspectMultiBufferGeneric && GetMultiData == NULL) {
225
0
        SCLogError("Invalid arguments: must register "
226
0
                   "GetData with DetectEngineInspectMultiBufferGeneric");
227
0
        BUG_ON(1);
228
0
    }
229
230
26.1k
    uint8_t direction;
231
26.1k
    if (dir == SIG_FLAG_TOSERVER) {
232
14.0k
        direction = 0;
233
14.0k
    } else {
234
12.0k
        direction = 1;
235
12.0k
    }
236
    // every DNS or HTTP2 can be accessed from DOH2
237
26.1k
    if (alproto == ALPROTO_HTTP2 || alproto == ALPROTO_DNS) {
238
2.84k
        AppLayerInspectEngineRegisterInternal(
239
2.84k
                name, ALPROTO_DOH2, dir, progress, Callback, GetData, GetDataSingle, GetMultiData);
240
2.84k
    }
241
242
26.1k
    DetectEngineAppInspectionEngine *new_engine =
243
26.1k
            SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
244
26.1k
    if (unlikely(new_engine == NULL)) {
245
0
        exit(EXIT_FAILURE);
246
0
    }
247
26.1k
    new_engine->alproto = alproto;
248
26.1k
    new_engine->dir = direction;
249
26.1k
    new_engine->sm_list = (uint16_t)sm_list;
250
26.1k
    new_engine->sm_list_base = (uint16_t)sm_list;
251
26.1k
    new_engine->progress = (int16_t)progress;
252
26.1k
    new_engine->v2.Callback = Callback;
253
26.1k
    if (Callback == DetectEngineInspectBufferGeneric) {
254
5.92k
        new_engine->v2.GetData = GetData;
255
20.1k
    } else if (Callback == DetectEngineInspectBufferSingle) {
256
2.37k
        new_engine->v2.GetDataSingle = GetDataSingle;
257
17.8k
    } else if (Callback == DetectEngineInspectMultiBufferGeneric) {
258
3.62k
        new_engine->v2.GetMultiData = GetMultiData;
259
3.62k
    }
260
261
26.1k
    if (g_app_inspect_engines == NULL) {
262
39
        g_app_inspect_engines = new_engine;
263
26.0k
    } else {
264
26.0k
        DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
265
8.73M
        while (t->next != NULL) {
266
8.71M
            t = t->next;
267
8.71M
        }
268
269
26.0k
        t->next = new_engine;
270
26.0k
    }
271
26.1k
}
272
273
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir,
274
        int progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData)
275
17.9k
{
276
    /* before adding, check that we don't add a duplicate entry, which will
277
     * propagate all the way into the packet runtime if allowed. */
278
17.9k
    DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
279
5.05M
    while (t != NULL) {
280
5.03M
        const uint32_t t_direction = t->dir == 0 ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT;
281
5.03M
        const int sm_list = DetectBufferTypeGetByName(name);
282
283
5.03M
        if (t->sm_list == sm_list && t->alproto == alproto && t_direction == dir &&
284
0
                t->progress == progress && t->v2.Callback == Callback && t->v2.GetData == GetData) {
285
0
            DEBUG_VALIDATE_BUG_ON(1);
286
0
            return;
287
0
        }
288
5.03M
        t = t->next;
289
5.03M
    }
290
291
17.9k
    AppLayerInspectEngineRegisterInternal(
292
17.9k
            name, alproto, dir, progress, Callback, GetData, NULL, NULL);
293
17.9k
}
294
295
void DetectAppLayerInspectEngineRegisterSingle(const char *name, AppProto alproto, uint32_t dir,
296
        int progress, InspectEngineFuncPtr Callback, InspectionSingleBufferGetDataPtr GetData)
297
5.81k
{
298
    /* before adding, check that we don't add a duplicate entry, which will
299
     * propagate all the way into the packet runtime if allowed. */
300
5.81k
    DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
301
3.24M
    while (t != NULL) {
302
3.23M
        const uint32_t t_direction = t->dir == 0 ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT;
303
3.23M
        const int sm_list = DetectBufferTypeGetByName(name);
304
305
3.23M
        if (t->sm_list == sm_list && t->alproto == alproto && t_direction == dir &&
306
0
                t->progress == progress && t->v2.Callback == Callback &&
307
0
                t->v2.GetDataSingle == GetData) {
308
0
            DEBUG_VALIDATE_BUG_ON(1);
309
0
            return;
310
0
        }
311
3.23M
        t = t->next;
312
3.23M
    }
313
314
5.81k
    AppLayerInspectEngineRegisterInternal(
315
5.81k
            name, alproto, dir, progress, Callback, NULL, GetData, NULL);
316
5.81k
}
317
318
/* copy an inspect engine with transforms to a new list id. */
319
static void DetectAppLayerInspectEngineCopy(
320
        DetectEngineCtx *de_ctx,
321
        int sm_list, int new_list,
322
        const DetectEngineTransforms *transforms)
323
64.8k
{
324
64.8k
    const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
325
42.9M
    while (t) {
326
42.9M
        if (t->sm_list == sm_list) {
327
411k
            DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
328
411k
            if (unlikely(new_engine == NULL)) {
329
0
                exit(EXIT_FAILURE);
330
0
            }
331
411k
            new_engine->alproto = t->alproto;
332
411k
            new_engine->dir = t->dir;
333
411k
            DEBUG_VALIDATE_BUG_ON(new_list < 0 || new_list > UINT16_MAX);
334
411k
            new_engine->sm_list = (uint16_t)new_list; /* use new list id */
335
411k
            DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX);
336
411k
            new_engine->sm_list_base = (uint16_t)sm_list;
337
411k
            new_engine->progress = t->progress;
338
411k
            new_engine->v2 = t->v2;
339
411k
            new_engine->v2.transforms = transforms; /* assign transforms */
340
341
411k
            if (de_ctx->app_inspect_engines == NULL) {
342
0
                de_ctx->app_inspect_engines = new_engine;
343
411k
            } else {
344
411k
                DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines;
345
753M
                while (list->next != NULL) {
346
753M
                    list = list->next;
347
753M
                }
348
349
411k
                list->next = new_engine;
350
411k
            }
351
411k
        }
352
42.9M
        t = t->next;
353
42.9M
    }
354
64.8k
}
355
356
/* copy inspect engines from global registrations to de_ctx list */
357
static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
358
114k
{
359
114k
    const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
360
114k
    DetectEngineAppInspectionEngine *list = de_ctx->app_inspect_engines;
361
76.0M
    while (t) {
362
75.9M
        DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
363
75.9M
        if (unlikely(new_engine == NULL)) {
364
0
            exit(EXIT_FAILURE);
365
0
        }
366
75.9M
        new_engine->alproto = t->alproto;
367
75.9M
        new_engine->dir = t->dir;
368
75.9M
        new_engine->sm_list = t->sm_list;
369
75.9M
        new_engine->sm_list_base = t->sm_list;
370
75.9M
        new_engine->progress = t->progress;
371
75.9M
        new_engine->v2 = t->v2;
372
373
75.9M
        if (list == NULL) {
374
114k
            de_ctx->app_inspect_engines = new_engine;
375
75.8M
        } else {
376
75.8M
            list->next = new_engine;
377
75.8M
        }
378
75.9M
        list = new_engine;
379
380
75.9M
        t = t->next;
381
75.9M
    }
382
114k
}
383
384
/* copy an inspect engine with transforms to a new list id. */
385
static void DetectPktInspectEngineCopy(
386
        DetectEngineCtx *de_ctx,
387
        int sm_list, int new_list,
388
        const DetectEngineTransforms *transforms)
389
6.52k
{
390
6.52k
    const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
391
83.4k
    while (t) {
392
76.9k
        if (t->sm_list == sm_list) {
393
6.52k
            DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
394
6.52k
            if (unlikely(new_engine == NULL)) {
395
0
                exit(EXIT_FAILURE);
396
0
            }
397
6.52k
            DEBUG_VALIDATE_BUG_ON(new_list < 0 || new_list > UINT16_MAX);
398
6.52k
            new_engine->sm_list = (uint16_t)new_list; /* use new list id */
399
6.52k
            DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX);
400
6.52k
            new_engine->sm_list_base = (uint16_t)sm_list;
401
6.52k
            new_engine->v1 = t->v1;
402
6.52k
            new_engine->v1.transforms = transforms; /* assign transforms */
403
404
6.52k
            if (de_ctx->pkt_inspect_engines == NULL) {
405
0
                de_ctx->pkt_inspect_engines = new_engine;
406
6.52k
            } else {
407
6.52k
                DetectEnginePktInspectionEngine *list = de_ctx->pkt_inspect_engines;
408
616k
                while (list->next != NULL) {
409
610k
                    list = list->next;
410
610k
                }
411
412
6.52k
                list->next = new_engine;
413
6.52k
            }
414
6.52k
        }
415
76.9k
        t = t->next;
416
76.9k
    }
417
6.52k
}
418
419
/* copy inspect engines from global registrations to de_ctx list */
420
static void DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
421
114k
{
422
114k
    const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
423
1.42M
    while (t) {
424
1.30M
        SCLogDebug("engine %p", t);
425
1.30M
        DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
426
1.30M
        if (unlikely(new_engine == NULL)) {
427
0
            exit(EXIT_FAILURE);
428
0
        }
429
1.30M
        new_engine->sm_list = t->sm_list;
430
1.30M
        new_engine->sm_list_base = t->sm_list;
431
1.30M
        new_engine->v1 = t->v1;
432
433
1.30M
        if (de_ctx->pkt_inspect_engines == NULL) {
434
114k
            de_ctx->pkt_inspect_engines = new_engine;
435
1.19M
        } else {
436
1.19M
            DetectEnginePktInspectionEngine *list = de_ctx->pkt_inspect_engines;
437
6.90M
            while (list->next != NULL) {
438
5.71M
                list = list->next;
439
5.71M
            }
440
441
1.19M
            list->next = new_engine;
442
1.19M
        }
443
444
1.30M
        t = t->next;
445
1.30M
    }
446
114k
}
447
448
/** \brief register inspect engine at start up time
449
 *
450
 *  \note errors are fatal */
451
void DetectEngineFrameInspectEngineRegister(DetectEngineCtx *de_ctx, const char *name, int dir,
452
        InspectionBufferFrameInspectFunc Callback, AppProto alproto, uint8_t type)
453
8.84k
{
454
8.84k
    const int sm_list = DetectEngineBufferTypeRegister(de_ctx, name);
455
8.84k
    if (sm_list < 0) {
456
0
        FatalError("failed to register inspect engine %s", name);
457
0
    }
458
459
8.84k
    if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) || (Callback == NULL)) {
460
0
        SCLogError("Invalid arguments");
461
0
        BUG_ON(1);
462
0
    }
463
464
8.84k
    uint8_t direction;
465
8.84k
    if (dir == SIG_FLAG_TOSERVER) {
466
4.42k
        direction = 0;
467
4.42k
    } else {
468
4.42k
        direction = 1;
469
4.42k
    }
470
471
8.84k
    DetectEngineFrameInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
472
8.84k
    if (unlikely(new_engine == NULL)) {
473
0
        FatalError("failed to register inspect engine %s: %s", name, strerror(errno));
474
0
    }
475
8.84k
    new_engine->sm_list = (uint16_t)sm_list;
476
8.84k
    new_engine->sm_list_base = (uint16_t)sm_list;
477
8.84k
    new_engine->dir = direction;
478
8.84k
    new_engine->v1.Callback = Callback;
479
8.84k
    new_engine->alproto = alproto;
480
8.84k
    new_engine->type = type;
481
482
8.84k
    if (de_ctx->frame_inspect_engines == NULL) {
483
2.68k
        de_ctx->frame_inspect_engines = new_engine;
484
6.16k
    } else {
485
6.16k
        DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
486
17.2k
        while (list->next != NULL) {
487
11.0k
            list = list->next;
488
11.0k
        }
489
490
6.16k
        list->next = new_engine;
491
6.16k
    }
492
8.84k
}
493
494
/* copy an inspect engine with transforms to a new list id. */
495
static void DetectFrameInspectEngineCopy(DetectEngineCtx *de_ctx, int sm_list, int new_list,
496
        const DetectEngineTransforms *transforms)
497
709
{
498
    /* take the list from the detect engine as the buffers can be registered
499
     * dynamically. */
500
709
    DetectEngineFrameInspectionEngine *t = de_ctx->frame_inspect_engines;
501
15.9k
    while (t) {
502
15.2k
        if (t->sm_list == sm_list) {
503
1.41k
            DetectEngineFrameInspectionEngine *new_engine =
504
1.41k
                    SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
505
1.41k
            if (unlikely(new_engine == NULL)) {
506
0
                exit(EXIT_FAILURE);
507
0
            }
508
1.41k
            DEBUG_VALIDATE_BUG_ON(new_list < 0 || new_list > UINT16_MAX);
509
1.41k
            new_engine->sm_list = (uint16_t)new_list; /* use new list id */
510
1.41k
            DEBUG_VALIDATE_BUG_ON(sm_list < 0 || sm_list > UINT16_MAX);
511
1.41k
            new_engine->sm_list_base = (uint16_t)sm_list;
512
1.41k
            new_engine->dir = t->dir;
513
1.41k
            new_engine->alproto = t->alproto;
514
1.41k
            new_engine->type = t->type;
515
1.41k
            new_engine->v1 = t->v1;
516
1.41k
            new_engine->v1.transforms = transforms; /* assign transforms */
517
518
            /* append to the list */
519
1.41k
            DetectEngineFrameInspectionEngine *list = t;
520
25.3k
            while (list->next != NULL) {
521
23.9k
                list = list->next;
522
23.9k
            }
523
524
1.41k
            list->next = new_engine;
525
1.41k
        }
526
15.2k
        t = t->next;
527
15.2k
    }
528
709
}
529
530
/* copy inspect engines from global registrations to de_ctx list */
531
static void DetectFrameInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
532
114k
{
533
114k
    const DetectEngineFrameInspectionEngine *t = g_frame_inspect_engines;
534
114k
    while (t) {
535
0
        SCLogDebug("engine %p", t);
536
0
        DetectEngineFrameInspectionEngine *new_engine =
537
0
                SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
538
0
        if (unlikely(new_engine == NULL)) {
539
0
            exit(EXIT_FAILURE);
540
0
        }
541
0
        new_engine->sm_list = t->sm_list;
542
0
        new_engine->sm_list_base = t->sm_list;
543
0
        new_engine->dir = t->dir;
544
0
        new_engine->alproto = t->alproto;
545
0
        new_engine->type = t->type;
546
0
        new_engine->v1 = t->v1;
547
548
0
        if (de_ctx->frame_inspect_engines == NULL) {
549
0
            de_ctx->frame_inspect_engines = new_engine;
550
0
        } else {
551
0
            DetectEngineFrameInspectionEngine *list = de_ctx->frame_inspect_engines;
552
0
            while (list->next != NULL) {
553
0
                list = list->next;
554
0
            }
555
556
0
            list->next = new_engine;
557
0
        }
558
559
0
        t = t->next;
560
0
    }
561
114k
}
562
563
/** \internal
564
 *  \brief append the stream inspection
565
 *
566
 *  If stream inspection is MPM, then prepend it.
567
 */
568
static void AppendStreamInspectEngine(
569
        Signature *s, SigMatchData *stream, uint8_t direction, uint8_t id)
570
11.7k
{
571
11.7k
    bool prepend = false;
572
573
11.7k
    DetectEngineAppInspectionEngine *new_engine = SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
574
11.7k
    if (unlikely(new_engine == NULL)) {
575
0
        exit(EXIT_FAILURE);
576
0
    }
577
11.7k
    if (s->init_data->mpm_sm_list == DETECT_SM_LIST_PMATCH) {
578
1.96k
        SCLogDebug("stream is mpm");
579
1.96k
        prepend = true;
580
1.96k
        new_engine->mpm = true;
581
1.96k
    }
582
11.7k
    new_engine->alproto = ALPROTO_UNKNOWN; /* all */
583
11.7k
    new_engine->dir = direction;
584
11.7k
    new_engine->stream = true;
585
11.7k
    new_engine->sm_list = DETECT_SM_LIST_PMATCH;
586
11.7k
    new_engine->sm_list_base = DETECT_SM_LIST_PMATCH;
587
11.7k
    new_engine->smd = stream;
588
11.7k
    new_engine->v2.Callback = DetectEngineInspectStream;
589
11.7k
    new_engine->progress = 0;
590
591
    /* append */
592
11.7k
    if (s->app_inspect == NULL) {
593
2
        s->app_inspect = new_engine;
594
2
        new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
595
11.7k
    } else if (prepend) {
596
1.96k
        new_engine->next = s->app_inspect;
597
1.96k
        s->app_inspect = new_engine;
598
1.96k
        new_engine->id = id;
599
600
9.74k
    } else {
601
9.74k
        DetectEngineAppInspectionEngine *a = s->app_inspect;
602
132k
        while (a->next != NULL) {
603
122k
            a = a->next;
604
122k
        }
605
606
9.74k
        a->next = new_engine;
607
9.74k
        new_engine->id = id;
608
9.74k
    }
609
11.7k
    SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
610
11.7k
}
611
612
static void AppendFrameInspectEngine(DetectEngineCtx *de_ctx,
613
        const DetectEngineFrameInspectionEngine *u, Signature *s, SigMatchData *smd,
614
        const int mpm_list)
615
8.55k
{
616
8.55k
    bool prepend = false;
617
618
8.55k
    if (u->alproto == ALPROTO_UNKNOWN) {
619
        /* special case, inspect engine applies to all protocols */
620
8.55k
    } else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, u->alproto))
621
0
        return;
622
623
8.55k
    if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
624
2.60k
        if (u->dir == 1)
625
1.30k
            return;
626
5.95k
    } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
627
1.51k
        if (u->dir == 0)
628
757
            return;
629
1.51k
    }
630
631
6.49k
    DetectEngineFrameInspectionEngine *new_engine =
632
6.49k
            SCCalloc(1, sizeof(DetectEngineFrameInspectionEngine));
633
6.49k
    if (unlikely(new_engine == NULL)) {
634
0
        exit(EXIT_FAILURE);
635
0
    }
636
6.49k
    if (mpm_list == u->sm_list) {
637
4.59k
        SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, u->sm_list));
638
4.59k
        prepend = true;
639
4.59k
        new_engine->mpm = true;
640
4.59k
    }
641
642
6.49k
    new_engine->type = u->type;
643
6.49k
    new_engine->sm_list = u->sm_list;
644
6.49k
    new_engine->sm_list_base = u->sm_list_base;
645
6.49k
    new_engine->smd = smd;
646
6.49k
    new_engine->v1 = u->v1;
647
6.49k
    SCLogDebug("sm_list %d new_engine->v1 %p/%p", new_engine->sm_list, new_engine->v1.Callback,
648
6.49k
            new_engine->v1.transforms);
649
650
6.49k
    if (s->frame_inspect == NULL) {
651
4.06k
        s->frame_inspect = new_engine;
652
4.06k
    } else if (prepend) {
653
1.28k
        new_engine->next = s->frame_inspect;
654
1.28k
        s->frame_inspect = new_engine;
655
1.28k
    } else {
656
1.15k
        DetectEngineFrameInspectionEngine *a = s->frame_inspect;
657
7.95k
        while (a->next != NULL) {
658
6.80k
            a = a->next;
659
6.80k
        }
660
1.15k
        new_engine->next = a->next;
661
1.15k
        a->next = new_engine;
662
1.15k
    }
663
6.49k
}
664
665
static void AppendPacketInspectEngine(DetectEngineCtx *de_ctx,
666
        const DetectEnginePktInspectionEngine *e, Signature *s, SigMatchData *smd,
667
        const int mpm_list)
668
4.37k
{
669
4.37k
    bool prepend = false;
670
671
4.37k
    DetectEnginePktInspectionEngine *new_engine =
672
4.37k
            SCCalloc(1, sizeof(DetectEnginePktInspectionEngine));
673
4.37k
    if (unlikely(new_engine == NULL)) {
674
0
        exit(EXIT_FAILURE);
675
0
    }
676
4.37k
    if (mpm_list == e->sm_list) {
677
1.23k
        SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, e->sm_list));
678
1.23k
        prepend = true;
679
1.23k
        new_engine->mpm = true;
680
1.23k
    }
681
682
4.37k
    new_engine->sm_list = e->sm_list;
683
4.37k
    new_engine->sm_list_base = e->sm_list_base;
684
4.37k
    new_engine->smd = smd;
685
4.37k
    new_engine->v1 = e->v1;
686
4.37k
    SCLogDebug("sm_list %d new_engine->v1 %p/%p/%p", new_engine->sm_list, new_engine->v1.Callback,
687
4.37k
            new_engine->v1.GetData, new_engine->v1.transforms);
688
689
4.37k
    if (s->pkt_inspect == NULL) {
690
2.58k
        s->pkt_inspect = new_engine;
691
2.58k
    } else if (prepend) {
692
59
        new_engine->next = s->pkt_inspect;
693
59
        s->pkt_inspect = new_engine;
694
1.72k
    } else {
695
1.72k
        DetectEnginePktInspectionEngine *a = s->pkt_inspect;
696
27.2k
        while (a->next != NULL) {
697
25.4k
            a = a->next;
698
25.4k
        }
699
1.72k
        new_engine->next = a->next;
700
1.72k
        a->next = new_engine;
701
1.72k
    }
702
4.37k
}
703
704
static void AppendAppInspectEngine(DetectEngineCtx *de_ctx,
705
        const DetectEngineAppInspectionEngine *t, Signature *s, SigMatchData *smd,
706
        const int mpm_list, const int files_id, uint8_t *last_id, bool *head_is_mpm)
707
27.6k
{
708
27.6k
    if (t->alproto == ALPROTO_UNKNOWN) {
709
        /* special case, inspect engine applies to all protocols */
710
21.4k
    } else if (s->alproto != ALPROTO_UNKNOWN) {
711
12.7k
        if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_APP) {
712
            /* SIGNATURE_HOOK_TYPE_APP rules are exact about their protocol */
713
4
            if (t->alproto != s->alproto) {
714
2
                return;
715
2
            }
716
12.7k
        } else {
717
            /* other rules use the more relax AppProtoEquals logic */
718
12.7k
            if (!AppProtoEquals(s->alproto, t->alproto)) {
719
6.38k
                return;
720
6.38k
            }
721
12.7k
        }
722
12.7k
    }
723
724
21.2k
    if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
725
5.44k
        if (t->dir == 1)
726
1.32k
            return;
727
15.7k
    } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
728
2.20k
        if (t->dir == 0)
729
851
            return;
730
2.20k
    }
731
19.0k
    SCLogDebug("app engine: t %p t->id %u => alproto:%s files:%s", t, t->id,
732
19.0k
            AppProtoToString(t->alproto), BOOL2STR(t->sm_list == files_id));
733
734
19.0k
    DetectEngineAppInspectionEngine *new_engine =
735
19.0k
            SCCalloc(1, sizeof(DetectEngineAppInspectionEngine));
736
19.0k
    if (unlikely(new_engine == NULL)) {
737
0
        exit(EXIT_FAILURE);
738
0
    }
739
19.0k
    bool prepend = false;
740
19.0k
    if (mpm_list == t->sm_list) {
741
8.72k
        SCLogDebug("%s is mpm", DetectEngineBufferTypeGetNameById(de_ctx, t->sm_list));
742
8.72k
        prepend = true;
743
8.72k
        *head_is_mpm = true;
744
8.72k
        new_engine->mpm = true;
745
8.72k
    }
746
747
19.0k
    new_engine->alproto = t->alproto;
748
19.0k
    new_engine->dir = t->dir;
749
19.0k
    new_engine->sm_list = t->sm_list;
750
19.0k
    new_engine->sm_list_base = t->sm_list_base;
751
19.0k
    new_engine->smd = smd;
752
19.0k
    new_engine->match_on_null = smd ? DetectContentInspectionMatchOnAbsentBuffer(smd) : false;
753
19.0k
    new_engine->progress = t->progress;
754
19.0k
    new_engine->v2 = t->v2;
755
19.0k
    SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p", new_engine->sm_list, new_engine->v2.Callback,
756
19.0k
            new_engine->v2.GetData, new_engine->v2.transforms);
757
758
19.0k
    if (s->app_inspect == NULL) {
759
6.78k
        s->app_inspect = new_engine;
760
6.78k
        if (new_engine->sm_list == files_id) {
761
107
            new_engine->id = DE_STATE_ID_FILE_INSPECT;
762
107
            SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
763
6.67k
        } else {
764
6.67k
            new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
765
6.67k
            SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
766
6.67k
                    DetectEngineBufferTypeGetNameById(de_ctx, new_engine->sm_list));
767
6.67k
        }
768
769
        /* prepend engine if forced or if our engine has a lower progress. */
770
12.2k
    } else if (prepend || (!(*head_is_mpm) && s->app_inspect->progress > new_engine->progress)) {
771
6.90k
        new_engine->next = s->app_inspect;
772
6.90k
        s->app_inspect = new_engine;
773
6.90k
        if (new_engine->sm_list == files_id) {
774
0
            new_engine->id = DE_STATE_ID_FILE_INSPECT;
775
0
            SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
776
6.90k
        } else {
777
6.90k
            new_engine->id = ++(*last_id);
778
6.90k
            SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
779
6.90k
                    DetectEngineBufferTypeGetNameById(de_ctx, new_engine->sm_list));
780
6.90k
        }
781
782
6.90k
    } else {
783
5.38k
        DetectEngineAppInspectionEngine *a = s->app_inspect;
784
27.4k
        while (a->next != NULL) {
785
24.0k
            if (a->next && a->next->progress > new_engine->progress) {
786
1.97k
                break;
787
1.97k
            }
788
22.1k
            a = a->next;
789
22.1k
        }
790
791
5.38k
        new_engine->next = a->next;
792
5.38k
        a->next = new_engine;
793
5.38k
        if (new_engine->sm_list == files_id) {
794
2.92k
            new_engine->id = DE_STATE_ID_FILE_INSPECT;
795
2.92k
            SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
796
2.92k
        } else {
797
2.45k
            new_engine->id = ++(*last_id);
798
2.45k
            SCLogDebug("sid %u: engine %p/%u %s", s->id, new_engine, new_engine->id,
799
2.45k
                    DetectEngineBufferTypeGetNameById(de_ctx, new_engine->sm_list));
800
2.45k
        }
801
5.38k
    }
802
803
19.0k
    SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
804
805
19.0k
    s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
806
19.0k
}
807
808
/**
809
 * \param direction STREAM_TOSERVER or STREAM_TOCLIENT
810
 */
811
const char *DetectEngineAppHookToName(
812
        const AppProto p, const uint8_t state, const uint8_t direction)
813
0
{
814
0
    if (!((direction & (STREAM_TOSERVER | STREAM_TOCLIENT)) == STREAM_TOSERVER) &&
815
0
            !((direction & (STREAM_TOSERVER | STREAM_TOCLIENT)) == STREAM_TOCLIENT))
816
0
        return NULL;
817
818
0
    const char *pname = AppLayerParserGetStateNameById(IPPROTO_TCP, // TODO
819
0
            p, state, direction);
820
0
    if (pname == NULL) {
821
0
        if (state == 0) {
822
0
            if (direction == STREAM_TOSERVER) {
823
0
                pname = "request_started";
824
0
            } else {
825
0
                pname = "response_started";
826
0
            }
827
0
        } else {
828
0
            const int complete = AppLayerParserGetStateProgressCompletionStatus(p, direction);
829
0
            if (state == complete) {
830
0
                if (direction == STREAM_TOSERVER) {
831
0
                    pname = "request_complete";
832
0
                } else {
833
0
                    pname = "response_complete";
834
0
                }
835
0
            }
836
0
        }
837
0
    }
838
0
    return pname;
839
0
}
840
841
/** \brief get the sm_list for a app hook */
842
int DetectEngineAppHookToSmlist(const AppProto p, const uint8_t state, const int direction)
843
0
{
844
0
    const char *app_proto = AppProtoToStringRaw(p);
845
0
    if (app_proto == NULL) {
846
0
        SCLogError("unknown app_proto %u", p);
847
0
        return -1;
848
0
    }
849
850
0
    const char *name =
851
0
            DetectEngineAppHookToName(p, state, direction & (STREAM_TOSERVER | STREAM_TOCLIENT));
852
0
    if (name == NULL) {
853
0
        return -1;
854
0
    }
855
856
0
    char generic_hook_name[256];
857
0
    snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:%s:generic", app_proto, name);
858
0
    int list = DetectBufferTypeGetByName(generic_hook_name);
859
0
    if (list < 0) {
860
0
        SCLogError("no list registered as %s for %s hook %s", generic_hook_name, app_proto, name);
861
0
        return -1;
862
0
    }
863
0
    return list;
864
0
}
865
866
/**
867
 *  \note for the file inspect engine, the id DE_STATE_ID_FILE_INSPECT
868
 *        is assigned.
869
 */
870
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s)
871
161k
{
872
161k
    const int mpm_list = s->init_data->mpm_sm ? s->init_data->mpm_sm_list : -1;
873
161k
    const int files_id = DetectBufferTypeGetByName("files");
874
161k
    bool head_is_mpm = false;
875
161k
    uint8_t last_id = DE_STATE_FLAG_BASE;
876
161k
    SCLogDebug("%u: setup app inspect engines. %u buffers", s->id, s->init_data->buffer_index);
877
878
161k
    if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
879
0
        SCLogDebug("need an inspect engine per state, range 0-%u", s->app_progress_hook);
880
0
        for (uint8_t state = 0; state < s->app_progress_hook; state++) {
881
0
            uint8_t dir = 0;
882
0
            int direction = 0;
883
0
            BUG_ON((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) ==
884
0
                    (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT));
885
0
            BUG_ON((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == 0);
886
0
            if (s->flags & SIG_FLAG_TOSERVER) {
887
0
                direction = STREAM_TOSERVER;
888
0
                dir = 0;
889
0
            } else if (s->flags & SIG_FLAG_TOCLIENT) {
890
0
                direction = STREAM_TOCLIENT;
891
0
                dir = 1;
892
0
            }
893
894
0
            int sm_list =
895
0
                    DetectEngineAppHookToSmlist(s->init_data->hook.t.app.alproto, 0, direction);
896
0
            if (sm_list < 0)
897
0
                return -1;
898
899
0
            DetectEngineAppInspectionEngine t = {
900
0
                .alproto = s->init_data->hook.t.app.alproto,
901
0
                .progress = (uint16_t)state,
902
0
                .sm_list = (uint16_t)sm_list,
903
0
                .sm_list_base = (uint16_t)sm_list,
904
0
                .dir = dir,
905
0
            };
906
0
            AppendAppInspectEngine(de_ctx, &t, s, NULL, mpm_list, files_id, &last_id, &head_is_mpm);
907
0
            SCLogDebug("sid %u: appended pass-tru engine at hook:%u sm_list:%d for "
908
0
                       "SIG_FLAG_INIT_HOOK_LTE",
909
0
                    s->id, state, sm_list);
910
0
        }
911
0
    }
912
913
261k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
914
99.8k
        SigMatchData *smd = SigMatchList2DataArray(s->init_data->buffers[x].head);
915
99.8k
        SCLogDebug("smd %p, id %u", smd, s->init_data->buffers[x].id);
916
917
99.8k
        const DetectBufferType *b =
918
99.8k
                DetectEngineBufferTypeGetById(de_ctx, s->init_data->buffers[x].id);
919
99.8k
        if (b == NULL)
920
0
            FatalError("unknown buffer");
921
922
99.8k
        if (b->frame) {
923
4.27k
            for (const DetectEngineFrameInspectionEngine *u = de_ctx->frame_inspect_engines;
924
37.9k
                    u != NULL; u = u->next) {
925
33.6k
                if (u->sm_list == s->init_data->buffers[x].id) {
926
8.55k
                    AppendFrameInspectEngine(de_ctx, u, s, smd, mpm_list);
927
8.55k
                }
928
33.6k
            }
929
95.6k
        } else if (b->packet) {
930
            /* set up pkt inspect engines */
931
162k
            for (const DetectEnginePktInspectionEngine *e = de_ctx->pkt_inspect_engines; e != NULL;
932
158k
                    e = e->next) {
933
158k
                SCLogDebug("e %p sm_list %u", e, e->sm_list);
934
158k
                if (e->sm_list == s->init_data->buffers[x].id) {
935
4.37k
                    AppendPacketInspectEngine(de_ctx, e, s, smd, mpm_list);
936
4.37k
                }
937
158k
            }
938
91.2k
        } else {
939
91.2k
            SCLogDebug("app %s id %u parent %u rule %u xforms %u", b->name, b->id, b->parent_id,
940
91.2k
                    s->init_data->buffers[x].id, b->transforms.cnt);
941
64.9M
            for (const DetectEngineAppInspectionEngine *t = de_ctx->app_inspect_engines; t != NULL;
942
64.8M
                    t = t->next) {
943
64.8M
                if (t->sm_list == s->init_data->buffers[x].id) {
944
391k
                    if (s->flags & SIG_FLAG_TXBOTHDIR) {
945
                        // ambiguous keywords have app engines in both directions
946
                        // so we skip the wrong direction for this buffer
947
6.44k
                        if (s->init_data->buffers[x].only_tc && t->dir == 0) {
948
2.07k
                            continue;
949
4.36k
                        } else if (s->init_data->buffers[x].only_ts && t->dir == 1) {
950
257
                            continue;
951
257
                        }
952
6.44k
                    }
953
389k
                    AppendAppInspectEngine(
954
389k
                            de_ctx, t, s, smd, mpm_list, files_id, &last_id, &head_is_mpm);
955
389k
                }
956
64.8M
            }
957
91.2k
        }
958
99.8k
    }
959
960
    /* handle rules that have an app-layer hook w/o bringing their own app inspect engine,
961
     * e.g. `alert dns:request_complete ... (sid:1;)`
962
     *
963
     * Here we use a minimal stub inspect engine in which we set:
964
     * - alproto
965
     * - progress
966
     * - sm_list/sm_list_base to get the mapping to the hook name
967
     * - dir based on sig direction
968
     *
969
     * The inspect engine has no callback and is thus considered a straight match.
970
     */
971
161k
    if (s->init_data->buffer_index == 0 && s->init_data->hook.type == SIGNATURE_HOOK_TYPE_APP) {
972
86
        uint8_t dir = 0;
973
86
        BUG_ON((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) ==
974
86
                (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT));
975
86
        BUG_ON((s->flags & (SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT)) == 0);
976
86
        if (s->flags & SIG_FLAG_TOSERVER)
977
8
            dir = 0;
978
78
        else if (s->flags & SIG_FLAG_TOCLIENT)
979
78
            dir = 1;
980
981
86
        DetectEngineAppInspectionEngine t = {
982
86
            .alproto = s->init_data->hook.t.app.alproto,
983
86
            .progress = (uint16_t)s->init_data->hook.t.app.app_progress,
984
86
            .sm_list = (uint16_t)s->init_data->hook.sm_list,
985
86
            .sm_list_base = (uint16_t)s->init_data->hook.sm_list,
986
86
            .dir = dir,
987
86
        };
988
86
        AppendAppInspectEngine(de_ctx, &t, s, NULL, mpm_list, files_id, &last_id, &head_is_mpm);
989
86
    }
990
991
161k
    if ((s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) &&
992
70.0k
            s->init_data->smlists[DETECT_SM_LIST_PMATCH] != NULL)
993
7.46k
    {
994
        /* if engine is added multiple times, we pass it the same list */
995
7.46k
        SigMatchData *stream = SigMatchList2DataArray(s->init_data->smlists[DETECT_SM_LIST_PMATCH]);
996
7.46k
        BUG_ON(stream == NULL);
997
7.46k
        if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
998
2.64k
            AppendStreamInspectEngine(s, stream, 0, last_id + 1);
999
4.82k
        } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
1000
574
            AppendStreamInspectEngine(s, stream, 1, last_id + 1);
1001
4.24k
        } else {
1002
4.24k
            AppendStreamInspectEngine(s, stream, 0, last_id + 1);
1003
4.24k
            AppendStreamInspectEngine(s, stream, 1, last_id + 1);
1004
4.24k
        }
1005
1006
7.46k
        if (s->init_data->init_flags & SIG_FLAG_INIT_NEED_FLUSH) {
1007
915
            SCLogDebug("set SIG_FLAG_FLUSH on %u", s->id);
1008
915
            s->flags |= SIG_FLAG_FLUSH;
1009
915
        }
1010
7.46k
    }
1011
1012
#ifdef DEBUG
1013
    const DetectEngineAppInspectionEngine *iter = s->app_inspect;
1014
    while (iter) {
1015
        SCLogDebug("%u: engine %s id %u progress %d %s", s->id,
1016
                DetectEngineBufferTypeGetNameById(de_ctx, iter->sm_list), iter->id, iter->progress,
1017
                iter->sm_list == mpm_list ? "MPM" : "");
1018
        iter = iter->next;
1019
    }
1020
#endif
1021
161k
    return 0;
1022
161k
}
1023
1024
/** \brief free app inspect engines for a signature
1025
 *
1026
 *  For lists that are registered multiple times, like http_header and
1027
 *  http_cookie, making the engines owner of the lists is complicated.
1028
 *  Multiple engines in a sig may be pointing to the same list. To
1029
 *  address this the 'free' code needs to be extra careful about not
1030
 *  double freeing, so it takes an approach to first fill an array
1031
 *  of the to-free pointers before freeing them.
1032
 */
1033
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
1034
4.96M
{
1035
4.96M
    int engines = 0;
1036
1037
4.96M
    DetectEngineAppInspectionEngine *ie = s->app_inspect;
1038
5.25M
    while (ie) {
1039
288k
        ie = ie->next;
1040
288k
        engines++;
1041
288k
    }
1042
4.96M
    DetectEnginePktInspectionEngine *e = s->pkt_inspect;
1043
5.05M
    while (e) {
1044
94.1k
        e = e->next;
1045
94.1k
        engines++;
1046
94.1k
    }
1047
4.96M
    DetectEngineFrameInspectionEngine *u = s->frame_inspect;
1048
4.97M
    while (u) {
1049
6.49k
        u = u->next;
1050
6.49k
        engines++;
1051
6.49k
    }
1052
4.96M
    if (engines == 0) {
1053
4.81M
        BUG_ON(s->pkt_inspect);
1054
4.81M
        BUG_ON(s->frame_inspect);
1055
4.81M
        return;
1056
4.81M
    }
1057
1058
146k
    SigMatchData *bufs[engines];
1059
146k
    memset(&bufs, 0, (engines * sizeof(SigMatchData *)));
1060
146k
    int arrays = 0;
1061
1062
    /* free engines and put smd in the array */
1063
146k
    ie = s->app_inspect;
1064
434k
    while (ie) {
1065
288k
        DetectEngineAppInspectionEngine *next = ie->next;
1066
1067
288k
        bool skip = false;
1068
788k
        for (int i = 0; i < arrays; i++) {
1069
690k
            if (bufs[i] == ie->smd) {
1070
189k
                skip = true;
1071
189k
                break;
1072
189k
            }
1073
690k
        }
1074
288k
        if (!skip) {
1075
98.7k
            bufs[arrays++] = ie->smd;
1076
98.7k
        }
1077
288k
        SCFree(ie);
1078
288k
        ie = next;
1079
288k
    }
1080
146k
    e = s->pkt_inspect;
1081
240k
    while (e) {
1082
94.1k
        DetectEnginePktInspectionEngine *next = e->next;
1083
1084
94.1k
        bool skip = false;
1085
146k
        for (int i = 0; i < arrays; i++) {
1086
57.4k
            if (bufs[i] == e->smd) {
1087
4.71k
                skip = true;
1088
4.71k
                break;
1089
4.71k
            }
1090
57.4k
        }
1091
94.1k
        if (!skip) {
1092
89.4k
            bufs[arrays++] = e->smd;
1093
89.4k
        }
1094
94.1k
        SCFree(e);
1095
94.1k
        e = next;
1096
94.1k
    }
1097
146k
    u = s->frame_inspect;
1098
152k
    while (u) {
1099
6.49k
        DetectEngineFrameInspectionEngine *next = u->next;
1100
1101
6.49k
        bool skip = false;
1102
10.5k
        for (int i = 0; i < arrays; i++) {
1103
6.25k
            if (bufs[i] == u->smd) {
1104
2.21k
                skip = true;
1105
2.21k
                break;
1106
2.21k
            }
1107
6.25k
        }
1108
6.49k
        if (!skip) {
1109
4.27k
            bufs[arrays++] = u->smd;
1110
4.27k
        }
1111
6.49k
        SCFree(u);
1112
6.49k
        u = next;
1113
6.49k
    }
1114
1115
535k
    for (int i = 0; i < engines; i++) {
1116
389k
        if (bufs[i] == NULL)
1117
281k
            continue;
1118
107k
        SigMatchData *smd = bufs[i];
1119
240k
        while (1) {
1120
240k
            if (sigmatch_table[smd->type].Free != NULL) {
1121
240k
                sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
1122
240k
            }
1123
240k
            if (smd->is_last)
1124
107k
                break;
1125
133k
            smd++;
1126
133k
        }
1127
107k
        SCFree(bufs[i]);
1128
107k
    }
1129
146k
}
1130
1131
/* code for registering buffers */
1132
1133
#include "util-hash-lookup3.h"
1134
1135
static HashListTable *g_buffer_type_hash = NULL;
1136
static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START;
1137
static int g_buffer_type_reg_closed = 0;
1138
1139
int DetectBufferTypeMaxId(void)
1140
0
{
1141
0
    return g_buffer_type_id;
1142
0
}
1143
1144
static void DetectBufferAddTransformData(DetectBufferType *map)
1145
108k
{
1146
246k
    for (int i = 0; i < map->transforms.cnt; i++) {
1147
137k
        const TransformData *t = &map->transforms.transforms[i];
1148
137k
        if (sigmatch_table[t->transform].TransformId) {
1149
70.8k
            sigmatch_table[t->transform].TransformId(
1150
70.8k
                    &map->xform_id[i].id_data, &map->xform_id[i].id_data_len, t->options);
1151
70.8k
            SCLogDebug("transform identity data: [%p] \"%s\" [%d]", map->xform_id[i].id_data,
1152
70.8k
                    (char *)map->xform_id[i].id_data, map->xform_id[i].id_data_len);
1153
70.8k
        }
1154
137k
    }
1155
108k
}
1156
1157
static uint32_t DetectBufferTypeHashNameFunc(HashListTable *ht, void *data, uint16_t datalen)
1158
65.4M
{
1159
65.4M
    const DetectBufferType *map = (DetectBufferType *)data;
1160
65.4M
    uint32_t hash = hashlittle_safe(map->name, strlen(map->name), 0);
1161
1162
    // Add the transform data
1163
    // - Collect transform id and position
1164
    // - Collect identity data, if any
1165
65.4M
    hash += hashlittle_safe((uint8_t *)&map->transforms.cnt, sizeof(map->transforms.cnt), 0);
1166
65.7M
    for (int i = 0; i < map->transforms.cnt; i++) {
1167
236k
        const TransformData *t = &map->transforms.transforms[i];
1168
236k
        int tval = t->transform;
1169
236k
        hash += hashlittle_safe((uint8_t *)&tval, sizeof(tval), 0);
1170
236k
        if (map->xform_id[i].id_data) {
1171
70.8k
            hash += hashlittle_safe(
1172
70.8k
                    &map->xform_id[i].id_data_len, sizeof(map->xform_id[i].id_data_len), 0);
1173
70.8k
            hash += hashlittle_safe(map->xform_id[i].id_data, map->xform_id[i].id_data_len, 0);
1174
70.8k
        }
1175
236k
    }
1176
65.4M
    hash %= ht->array_size;
1177
65.4M
    SCLogDebug("map->name %s, hash %d", map->name, hash);
1178
65.4M
    return hash;
1179
65.4M
}
1180
1181
static uint32_t DetectBufferTypeHashIdFunc(HashListTable *ht, void *data, uint16_t datalen)
1182
56.5M
{
1183
56.5M
    const DetectBufferType *map = (DetectBufferType *)data;
1184
56.5M
    uint32_t hash = map->id;
1185
56.5M
    hash %= ht->array_size;
1186
56.5M
    return hash;
1187
56.5M
}
1188
1189
static char DetectBufferTypeCompareNameFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
1190
17.5M
{
1191
17.5M
    DetectBufferType *map1 = (DetectBufferType *)data1;
1192
17.5M
    DetectBufferType *map2 = (DetectBufferType *)data2;
1193
1194
17.5M
    char r = (strcmp(map1->name, map2->name) == 0);
1195
1196
    // Compare the transforms
1197
    // the transform supports identity, that data will also be added.
1198
17.5M
    r &= map1->transforms.cnt == map2->transforms.cnt;
1199
17.5M
    if (r && map1->transforms.cnt) {
1200
83.3k
        for (int i = 0; i < map1->transforms.cnt; i++) {
1201
46.5k
            if (map1->transforms.transforms[i].transform !=
1202
46.5k
                    map2->transforms.transforms[i].transform) {
1203
61
                r = 0;
1204
61
                break;
1205
61
            }
1206
1207
46.5k
            SCLogDebug("%s: transform ids match; checking specialized data", map1->name);
1208
            // Checks
1209
            // - Both NULL: --> ok, continue
1210
            // - One NULL: --> no match, break?
1211
            // - identity data lengths match: --> ok, continue
1212
            // - identity data matches: ok
1213
1214
            // Stop if only one is NULL
1215
46.5k
            if ((map1->xform_id[i].id_data == NULL) ^ (map2->xform_id[i].id_data == NULL)) {
1216
3.75k
                SCLogDebug("identity data: only one is null");
1217
3.75k
                r = 0;
1218
3.75k
                break;
1219
42.7k
            } else if (map1->xform_id[i].id_data == NULL) { /* continue when both are null */
1220
42.7k
                SCLogDebug("identity data: both null");
1221
42.7k
                r = 1;
1222
42.7k
                continue;
1223
42.7k
            } else if (map1->xform_id[i].id_data_len != map2->xform_id[i].id_data_len) {
1224
                // Stop when id data lengths aren't equal
1225
0
                SCLogDebug("id data: unequal lengths");
1226
0
                r = 0;
1227
0
                break;
1228
0
            }
1229
1230
            // stop if the identity data is different
1231
0
            r &= memcmp(map1->xform_id[i].id_data, map2->xform_id[i].id_data,
1232
0
                         map1->xform_id[i].id_data_len) == 0;
1233
0
            if (r == 0)
1234
0
                break;
1235
0
            SCLogDebug("identity data: data matches");
1236
0
        }
1237
40.6k
    }
1238
17.5M
    return r;
1239
17.5M
}
1240
1241
static char DetectBufferTypeCompareIdFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
1242
6.49M
{
1243
6.49M
    DetectBufferType *map1 = (DetectBufferType *)data1;
1244
6.49M
    DetectBufferType *map2 = (DetectBufferType *)data2;
1245
6.49M
    return map1->id == map2->id;
1246
6.49M
}
1247
1248
static void DetectBufferTypeFreeFunc(void *data)
1249
50.5M
{
1250
50.5M
    DetectBufferType *map = (DetectBufferType *)data;
1251
1252
50.5M
    if (map == NULL) {
1253
0
        return;
1254
0
    }
1255
1256
    /* Release transformation option memory, if any */
1257
50.6M
    for (int i = 0; i < map->transforms.cnt; i++) {
1258
98.8k
        if (map->transforms.transforms[i].options == NULL)
1259
28.5k
            continue;
1260
1261
70.3k
        if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) {
1262
0
            SCLogError("%s allocates transform option memory but has no free routine",
1263
0
                    sigmatch_table[map->transforms.transforms[i].transform].name);
1264
0
            continue;
1265
0
        }
1266
70.3k
        sigmatch_table[map->transforms.transforms[i].transform].Free(NULL, map->transforms.transforms[i].options);
1267
70.3k
    }
1268
1269
50.5M
    SCFree(map);
1270
50.5M
}
1271
1272
static int DetectBufferTypeInit(void)
1273
79
{
1274
79
    BUG_ON(g_buffer_type_hash);
1275
79
    g_buffer_type_hash = HashListTableInit(256, DetectBufferTypeHashNameFunc,
1276
79
            DetectBufferTypeCompareNameFunc, DetectBufferTypeFreeFunc);
1277
79
    if (g_buffer_type_hash == NULL)
1278
0
        return -1;
1279
1280
79
    return 0;
1281
79
}
1282
#if 0
1283
static void DetectBufferTypeFree(void)
1284
{
1285
    if (g_buffer_type_hash == NULL)
1286
        return;
1287
1288
    HashListTableFree(g_buffer_type_hash);
1289
    g_buffer_type_hash = NULL;
1290
}
1291
#endif
1292
static int DetectBufferTypeAdd(const char *string)
1293
33.7k
{
1294
33.7k
    BUG_ON(string == NULL || strlen(string) >= 64);
1295
1296
33.7k
    DetectBufferType *map = SCCalloc(1, sizeof(*map));
1297
33.7k
    if (map == NULL)
1298
0
        return -1;
1299
1300
33.7k
    strlcpy(map->name, string, sizeof(map->name));
1301
33.7k
    map->id = g_buffer_type_id++;
1302
1303
33.7k
    BUG_ON(HashListTableAdd(g_buffer_type_hash, (void *)map, 0) != 0);
1304
33.7k
    SCLogDebug("buffer %s registered with id %d", map->name, map->id);
1305
33.7k
    return map->id;
1306
33.7k
}
1307
1308
static DetectBufferType *DetectBufferTypeLookupByName(const char *string)
1309
14.7M
{
1310
14.7M
    DetectBufferType map;
1311
14.7M
    memset(&map, 0, sizeof(map));
1312
14.7M
    strlcpy(map.name, string, sizeof(map.name));
1313
1314
14.7M
    DetectBufferType *res = HashListTableLookup(g_buffer_type_hash, &map, 0);
1315
14.7M
    return res;
1316
14.7M
}
1317
1318
int DetectBufferTypeRegister(const char *name)
1319
122k
{
1320
122k
    BUG_ON(g_buffer_type_reg_closed);
1321
122k
    if (g_buffer_type_hash == NULL)
1322
79
        DetectBufferTypeInit();
1323
1324
122k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1325
122k
    if (!exists) {
1326
33.7k
        return DetectBufferTypeAdd(name);
1327
89.2k
    } else {
1328
89.2k
        return exists->id;
1329
89.2k
    }
1330
122k
}
1331
1332
void DetectBufferTypeSupportsMultiInstance(const char *name)
1333
4.23k
{
1334
4.23k
    BUG_ON(g_buffer_type_reg_closed);
1335
4.23k
    DetectBufferTypeRegister(name);
1336
4.23k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1337
4.23k
    BUG_ON(!exists);
1338
4.23k
    exists->multi_instance = true;
1339
4.23k
    SCLogDebug("%p %s -- %d supports multi instance", exists, name, exists->id);
1340
4.23k
}
1341
1342
void DetectBufferTypeSupportsFrames(const char *name)
1343
0
{
1344
0
    BUG_ON(g_buffer_type_reg_closed);
1345
0
    DetectBufferTypeRegister(name);
1346
0
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1347
0
    BUG_ON(!exists);
1348
0
    exists->frame = true;
1349
0
    SCLogDebug("%p %s -- %d supports frame inspection", exists, name, exists->id);
1350
0
}
1351
1352
void DetectBufferTypeSupportsPacket(const char *name)
1353
792
{
1354
792
    BUG_ON(g_buffer_type_reg_closed);
1355
792
    DetectBufferTypeRegister(name);
1356
792
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1357
792
    BUG_ON(!exists);
1358
792
    exists->packet = true;
1359
792
    SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id);
1360
792
}
1361
1362
void DetectBufferTypeSupportsMpm(const char *name)
1363
27.9k
{
1364
27.9k
    BUG_ON(g_buffer_type_reg_closed);
1365
27.9k
    DetectBufferTypeRegister(name);
1366
27.9k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1367
27.9k
    BUG_ON(!exists);
1368
27.9k
    exists->mpm = true;
1369
27.9k
    SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id);
1370
27.9k
}
1371
1372
void DetectBufferTypeSupportsTransformations(const char *name)
1373
27.9k
{
1374
27.9k
    BUG_ON(g_buffer_type_reg_closed);
1375
27.9k
    DetectBufferTypeRegister(name);
1376
27.9k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1377
27.9k
    BUG_ON(!exists);
1378
27.9k
    exists->supports_transforms = true;
1379
27.9k
    SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
1380
27.9k
}
1381
1382
int DetectBufferTypeGetByName(const char *name)
1383
14.5M
{
1384
14.5M
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1385
14.5M
    if (!exists) {
1386
7.00M
        return -1;
1387
7.00M
    }
1388
7.50M
    return exists->id;
1389
14.5M
}
1390
1391
static DetectBufferType *DetectEngineBufferTypeLookupByName(
1392
        const DetectEngineCtx *de_ctx, const char *string)
1393
78.4k
{
1394
78.4k
    DetectBufferType map;
1395
78.4k
    memset(&map, 0, sizeof(map));
1396
78.4k
    strlcpy(map.name, string, sizeof(map.name));
1397
1398
78.4k
    DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash_name, &map, 0);
1399
78.4k
    return res;
1400
78.4k
}
1401
1402
const DetectBufferType *DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
1403
6.01M
{
1404
6.01M
    DetectBufferType lookup;
1405
6.01M
    memset(&lookup, 0, sizeof(lookup));
1406
6.01M
    lookup.id = id;
1407
6.01M
    const DetectBufferType *res =
1408
6.01M
            HashListTableLookup(de_ctx->buffer_type_hash_id, (void *)&lookup, 0);
1409
6.01M
    return res;
1410
6.01M
}
1411
1412
const char *DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
1413
178k
{
1414
178k
    const DetectBufferType *res = DetectEngineBufferTypeGetById(de_ctx, id);
1415
178k
    return res ? res->name : NULL;
1416
178k
}
1417
1418
static int DetectEngineBufferTypeAdd(DetectEngineCtx *de_ctx, const char *string)
1419
4.42k
{
1420
4.42k
    BUG_ON(string == NULL || strlen(string) >= 32);
1421
1422
4.42k
    DetectBufferType *map = SCCalloc(1, sizeof(*map));
1423
4.42k
    if (map == NULL)
1424
0
        return -1;
1425
1426
4.42k
    strlcpy(map->name, string, sizeof(map->name));
1427
4.42k
    map->id = de_ctx->buffer_type_id++;
1428
1429
4.42k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)map, 0) != 0);
1430
4.42k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_id, (void *)map, 0) != 0);
1431
4.42k
    SCLogDebug("buffer %s registered with id %d", map->name, map->id);
1432
4.42k
    return map->id;
1433
4.42k
}
1434
1435
int DetectEngineBufferTypeRegisterWithFrameEngines(DetectEngineCtx *de_ctx, const char *name,
1436
        const int direction, const AppProto alproto, const uint8_t frame_type)
1437
34.2k
{
1438
34.2k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1439
34.2k
    if (exists) {
1440
29.8k
        return exists->id;
1441
29.8k
    }
1442
1443
4.42k
    const int buffer_id = DetectEngineBufferTypeAdd(de_ctx, name);
1444
4.42k
    if (buffer_id < 0) {
1445
0
        return -1;
1446
0
    }
1447
1448
    /* TODO hack we need the map to get the name. Should we return the map at reg? */
1449
4.42k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, buffer_id);
1450
4.42k
    BUG_ON(!map);
1451
1452
    /* register MPM/inspect engines */
1453
4.42k
    if (direction & SIG_FLAG_TOSERVER) {
1454
4.42k
        DetectEngineFrameMpmRegister(de_ctx, map->name, SIG_FLAG_TOSERVER, 2,
1455
4.42k
                PrefilterGenericMpmFrameRegister, alproto, frame_type);
1456
4.42k
        DetectEngineFrameInspectEngineRegister(de_ctx, map->name, SIG_FLAG_TOSERVER,
1457
4.42k
                DetectEngineInspectFrameBufferGeneric, alproto, frame_type);
1458
4.42k
    }
1459
4.42k
    if (direction & SIG_FLAG_TOCLIENT) {
1460
4.42k
        DetectEngineFrameMpmRegister(de_ctx, map->name, SIG_FLAG_TOCLIENT, 2,
1461
4.42k
                PrefilterGenericMpmFrameRegister, alproto, frame_type);
1462
4.42k
        DetectEngineFrameInspectEngineRegister(de_ctx, map->name, SIG_FLAG_TOCLIENT,
1463
4.42k
                DetectEngineInspectFrameBufferGeneric, alproto, frame_type);
1464
4.42k
    }
1465
1466
4.42k
    return buffer_id;
1467
4.42k
}
1468
1469
int DetectEngineBufferTypeRegister(DetectEngineCtx *de_ctx, const char *name)
1470
17.6k
{
1471
17.6k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1472
17.6k
    if (!exists) {
1473
0
        return DetectEngineBufferTypeAdd(de_ctx, name);
1474
17.6k
    } else {
1475
17.6k
        return exists->id;
1476
17.6k
    }
1477
17.6k
}
1478
1479
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
1480
12.4k
{
1481
12.4k
    BUG_ON(desc == NULL || strlen(desc) >= 128);
1482
1483
12.4k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1484
12.4k
    if (!exists) {
1485
79
        return;
1486
79
    }
1487
12.3k
    strlcpy(exists->description, desc, sizeof(exists->description));
1488
12.3k
}
1489
1490
const char *DetectEngineBufferTypeGetDescriptionById(const DetectEngineCtx *de_ctx, const int id)
1491
1.11k
{
1492
1.11k
    const DetectBufferType *exists = DetectEngineBufferTypeGetById(de_ctx, id);
1493
1.11k
    if (!exists) {
1494
0
        return NULL;
1495
0
    }
1496
1.11k
    return exists->description;
1497
1.11k
}
1498
1499
const char *DetectBufferTypeGetDescriptionByName(const char *name)
1500
0
{
1501
0
    const DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1502
0
    if (!exists) {
1503
0
        return NULL;
1504
0
    }
1505
0
    return exists->description;
1506
0
}
1507
1508
void DetectEngineBufferTypeSupportsFrames(DetectEngineCtx *de_ctx, const char *name)
1509
8.84k
{
1510
8.84k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1511
8.84k
    BUG_ON(!exists);
1512
8.84k
    exists->frame = true;
1513
8.84k
    SCLogDebug("%p %s -- %d supports frame inspection", exists, name, exists->id);
1514
8.84k
}
1515
1516
void DetectEngineBufferTypeSupportsPacket(DetectEngineCtx *de_ctx, const char *name)
1517
0
{
1518
0
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1519
0
    BUG_ON(!exists);
1520
0
    exists->packet = true;
1521
0
    SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id);
1522
0
}
1523
1524
void DetectEngineBufferTypeSupportsMpm(DetectEngineCtx *de_ctx, const char *name)
1525
8.84k
{
1526
8.84k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1527
8.84k
    BUG_ON(!exists);
1528
8.84k
    exists->mpm = true;
1529
8.84k
    SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id);
1530
8.84k
}
1531
1532
void DetectEngineBufferTypeSupportsTransformations(DetectEngineCtx *de_ctx, const char *name)
1533
8.84k
{
1534
8.84k
    DetectBufferType *exists = DetectEngineBufferTypeLookupByName(de_ctx, name);
1535
8.84k
    BUG_ON(!exists);
1536
8.84k
    exists->supports_transforms = true;
1537
8.84k
    SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
1538
8.84k
}
1539
1540
bool DetectEngineBufferTypeSupportsMultiInstanceGetById(const DetectEngineCtx *de_ctx, const int id)
1541
586k
{
1542
586k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1543
586k
    if (map == NULL)
1544
0
        return false;
1545
586k
    SCLogDebug("map %p id %d multi_instance? %s", map, id, BOOL2STR(map->multi_instance));
1546
586k
    return map->multi_instance;
1547
586k
}
1548
1549
bool DetectEngineBufferTypeSupportsPacketGetById(const DetectEngineCtx *de_ctx, const int id)
1550
573k
{
1551
573k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1552
573k
    if (map == NULL)
1553
0
        return false;
1554
573k
    SCLogDebug("map %p id %d packet? %d", map, id, map->packet);
1555
573k
    return map->packet;
1556
573k
}
1557
1558
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
1559
907k
{
1560
907k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1561
907k
    if (map == NULL)
1562
257k
        return false;
1563
650k
    SCLogDebug("map %p id %d mpm? %d", map, id, map->mpm);
1564
650k
    return map->mpm;
1565
907k
}
1566
1567
bool DetectEngineBufferTypeSupportsFramesGetById(const DetectEngineCtx *de_ctx, const int id)
1568
561k
{
1569
561k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1570
561k
    if (map == NULL)
1571
0
        return false;
1572
561k
    SCLogDebug("map %p id %d frame? %d", map, id, map->frame);
1573
561k
    return map->frame;
1574
561k
}
1575
1576
void DetectBufferTypeRegisterSetupCallback(const char *name,
1577
        void (*SetupCallback)(const DetectEngineCtx *, Signature *))
1578
909
{
1579
909
    BUG_ON(g_buffer_type_reg_closed);
1580
909
    DetectBufferTypeRegister(name);
1581
909
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1582
909
    BUG_ON(!exists);
1583
909
    exists->SetupCallback = SetupCallback;
1584
909
}
1585
1586
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
1587
1.31M
{
1588
1.31M
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1589
1.31M
    if (map && map->SetupCallback) {
1590
138k
        map->SetupCallback(de_ctx, s);
1591
138k
    }
1592
1.31M
}
1593
1594
void DetectBufferTypeRegisterValidateCallback(
1595
        const char *name, bool (*ValidateCallback)(const Signature *, const char **sigerror,
1596
                                  const DetectBufferType *))
1597
1.22k
{
1598
1.22k
    BUG_ON(g_buffer_type_reg_closed);
1599
1.22k
    DetectBufferTypeRegister(name);
1600
1.22k
    DetectBufferType *exists = DetectBufferTypeLookupByName(name);
1601
1.22k
    BUG_ON(!exists);
1602
1.22k
    exists->ValidateCallback = ValidateCallback;
1603
1.22k
}
1604
1605
bool DetectEngineBufferRunValidateCallback(
1606
        const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
1607
594k
{
1608
594k
    const DetectBufferType *map = DetectEngineBufferTypeGetById(de_ctx, id);
1609
    // only run validation if the buffer is not transformed
1610
594k
    if (map && map->ValidateCallback && map->transforms.cnt == 0) {
1611
154k
        return map->ValidateCallback(s, sigerror, map);
1612
154k
    }
1613
440k
    return true;
1614
594k
}
1615
1616
bool DetectBufferIsPresent(const Signature *s, const uint32_t buf_id)
1617
0
{
1618
0
    for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
1619
0
        if (buf_id == s->init_data->buffers[i].id) {
1620
0
            return true;
1621
0
        }
1622
0
    }
1623
0
    return false;
1624
0
}
1625
1626
/** \brief Check content byte array compatibility with transforms
1627
 *
1628
 *  The "content" array is presented to the transforms so that each
1629
 *  transform may validate that it's compatible with the transform.
1630
 *
1631
 *  When a transform indicates the byte array is incompatible, none of the
1632
 *  subsequent transforms, if any, are invoked. This means the first validation
1633
 *  failure terminates the loop.
1634
 *
1635
 *  \param de_ctx Detection engine context.
1636
 *  \param sm_list The SM list id.
1637
 *  \param content The byte array being validated
1638
 *  \param namestr returns the name of the transform that is incompatible with
1639
 *  content.
1640
 *
1641
 *  \retval true (false) If any of the transforms indicate the byte array is
1642
 *  (is not) compatible.
1643
 **/
1644
bool DetectEngineBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list,
1645
        const uint8_t *content, uint16_t content_len, const char **namestr)
1646
315k
{
1647
315k
    const DetectBufferType *dbt = DetectEngineBufferTypeGetById(de_ctx, sm_list);
1648
315k
    BUG_ON(dbt == NULL);
1649
1650
441k
    for (int i = 0; i < dbt->transforms.cnt; i++) {
1651
130k
        const TransformData *t = &dbt->transforms.transforms[i];
1652
130k
        if (!sigmatch_table[t->transform].TransformValidate)
1653
98.8k
            continue;
1654
1655
31.2k
        if (sigmatch_table[t->transform].TransformValidate(content, content_len, t->options)) {
1656
26.8k
            continue;
1657
26.8k
        }
1658
1659
4.32k
        if (namestr) {
1660
4.32k
            *namestr = sigmatch_table[t->transform].name;
1661
4.32k
        }
1662
1663
4.32k
        return false;
1664
31.2k
    }
1665
1666
311k
    return true;
1667
315k
}
1668
1669
static void DetectBufferTypeSetupDetectEngine(DetectEngineCtx *de_ctx)
1670
114k
{
1671
114k
    const int size = g_buffer_type_id;
1672
114k
    BUG_ON(!(size > 0));
1673
1674
114k
    de_ctx->buffer_type_hash_name = HashListTableInit(256, DetectBufferTypeHashNameFunc,
1675
114k
            DetectBufferTypeCompareNameFunc, DetectBufferTypeFreeFunc);
1676
114k
    BUG_ON(de_ctx->buffer_type_hash_name == NULL);
1677
114k
    de_ctx->buffer_type_hash_id =
1678
114k
            HashListTableInit(256, DetectBufferTypeHashIdFunc, DetectBufferTypeCompareIdFunc,
1679
114k
                    NULL); // entries owned by buffer_type_hash_name
1680
114k
    BUG_ON(de_ctx->buffer_type_hash_id == NULL);
1681
114k
    de_ctx->buffer_type_id = g_buffer_type_id;
1682
1683
114k
    SCLogDebug("DETECT_SM_LIST_DYNAMIC_START %u", DETECT_SM_LIST_DYNAMIC_START);
1684
114k
    HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash);
1685
50.6M
    while (b) {
1686
50.4M
        DetectBufferType *map = HashListTableGetListData(b);
1687
1688
50.4M
        DetectBufferType *copy = SCCalloc(1, sizeof(*copy));
1689
50.4M
        BUG_ON(!copy);
1690
50.4M
        memcpy(copy, map, sizeof(*copy));
1691
50.4M
        int r = HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)copy, 0);
1692
50.4M
        BUG_ON(r != 0);
1693
50.4M
        r = HashListTableAdd(de_ctx->buffer_type_hash_id, (void *)copy, 0);
1694
50.4M
        BUG_ON(r != 0);
1695
1696
50.4M
        SCLogDebug("name %s id %d mpm %s packet %s -- %s. "
1697
50.4M
                   "Callbacks: Setup %p Validate %p",
1698
50.4M
                map->name, map->id, map->mpm ? "true" : "false", map->packet ? "true" : "false",
1699
50.4M
                map->description, map->SetupCallback, map->ValidateCallback);
1700
50.4M
        b = HashListTableGetListNext(b);
1701
50.4M
    }
1702
1703
114k
    PrefilterInit(de_ctx);
1704
114k
    DetectMpmInitializeAppMpms(de_ctx);
1705
114k
    DetectAppLayerInspectEngineCopyListToDetectCtx(de_ctx);
1706
114k
    DetectMpmInitializeFrameMpms(de_ctx);
1707
114k
    DetectFrameInspectEngineCopyListToDetectCtx(de_ctx);
1708
114k
    DetectMpmInitializePktMpms(de_ctx);
1709
114k
    DetectPktInspectEngineCopyListToDetectCtx(de_ctx);
1710
114k
}
1711
1712
static void DetectBufferTypeFreeDetectEngine(DetectEngineCtx *de_ctx)
1713
114k
{
1714
114k
    if (de_ctx) {
1715
114k
        if (de_ctx->buffer_type_hash_name)
1716
114k
            HashListTableFree(de_ctx->buffer_type_hash_name);
1717
114k
        if (de_ctx->buffer_type_hash_id)
1718
114k
            HashListTableFree(de_ctx->buffer_type_hash_id);
1719
1720
114k
        DetectEngineAppInspectionEngine *ilist = de_ctx->app_inspect_engines;
1721
76.4M
        while (ilist) {
1722
76.3M
            DetectEngineAppInspectionEngine *next = ilist->next;
1723
76.3M
            SCFree(ilist);
1724
76.3M
            ilist = next;
1725
76.3M
        }
1726
114k
        DetectBufferMpmRegistry *mlist = de_ctx->app_mpms_list;
1727
38.8M
        while (mlist) {
1728
38.7M
            DetectBufferMpmRegistry *next = mlist->next;
1729
38.7M
            SCFree(mlist);
1730
38.7M
            mlist = next;
1731
38.7M
        }
1732
114k
        DetectEnginePktInspectionEngine *plist = de_ctx->pkt_inspect_engines;
1733
1.42M
        while (plist) {
1734
1.31M
            DetectEnginePktInspectionEngine *next = plist->next;
1735
1.31M
            SCFree(plist);
1736
1.31M
            plist = next;
1737
1.31M
        }
1738
114k
        DetectBufferMpmRegistry *pmlist = de_ctx->pkt_mpms_list;
1739
1.42M
        while (pmlist) {
1740
1.31M
            DetectBufferMpmRegistry *next = pmlist->next;
1741
1.31M
            SCFree(pmlist);
1742
1.31M
            pmlist = next;
1743
1.31M
        }
1744
114k
        DetectEngineFrameInspectionEngine *framelist = de_ctx->frame_inspect_engines;
1745
124k
        while (framelist) {
1746
10.2k
            DetectEngineFrameInspectionEngine *next = framelist->next;
1747
10.2k
            SCFree(framelist);
1748
10.2k
            framelist = next;
1749
10.2k
        }
1750
114k
        DetectBufferMpmRegistry *framemlist = de_ctx->frame_mpms_list;
1751
124k
        while (framemlist) {
1752
10.2k
            DetectBufferMpmRegistry *next = framemlist->next;
1753
10.2k
            SCFree(framemlist);
1754
10.2k
            framemlist = next;
1755
10.2k
        }
1756
114k
        PrefilterDeinit(de_ctx);
1757
114k
    }
1758
114k
}
1759
1760
void DetectBufferTypeCloseRegistration(void)
1761
79
{
1762
79
    BUG_ON(g_buffer_type_hash == NULL);
1763
1764
79
    g_buffer_type_reg_closed = 1;
1765
79
}
1766
1767
int DetectEngineBufferTypeGetByIdTransforms(
1768
        DetectEngineCtx *de_ctx, const int id, TransformData *transforms, int transform_cnt)
1769
108k
{
1770
108k
    const DetectBufferType *base_map = DetectEngineBufferTypeGetById(de_ctx, id);
1771
108k
    if (!base_map) {
1772
0
        return -1;
1773
0
    }
1774
108k
    if (!base_map->supports_transforms) {
1775
0
        SCLogError("buffer '%s' does not support transformations", base_map->name);
1776
0
        return -1;
1777
0
    }
1778
1779
108k
    SCLogDebug("base_map %s", base_map->name);
1780
1781
108k
    DetectEngineTransforms t;
1782
108k
    memset(&t, 0, sizeof(t));
1783
246k
    for (int i = 0; i < transform_cnt; i++) {
1784
137k
        t.transforms[i] = transforms[i];
1785
137k
    }
1786
108k
    t.cnt = transform_cnt;
1787
1788
108k
    DetectBufferType lookup_map;
1789
108k
    memset(&lookup_map, 0, sizeof(lookup_map));
1790
108k
    strlcpy(lookup_map.name, base_map->name, sizeof(lookup_map.name));
1791
108k
    lookup_map.transforms = t;
1792
1793
    /* Add transform identity data from transforms */
1794
108k
    if (t.cnt) {
1795
108k
        DetectBufferAddTransformData(&lookup_map);
1796
108k
    }
1797
108k
    DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash_name, &lookup_map, 0);
1798
1799
108k
    SCLogDebug("res %p", res);
1800
108k
    if (res != NULL) {
1801
36.8k
        return res->id;
1802
36.8k
    }
1803
1804
72.0k
    DetectBufferType *map = SCCalloc(1, sizeof(*map));
1805
72.0k
    if (map == NULL)
1806
0
        return -1;
1807
1808
72.0k
    strlcpy(map->name, base_map->name, sizeof(map->name));
1809
72.0k
    map->id = de_ctx->buffer_type_id++;
1810
72.0k
    map->parent_id = base_map->id;
1811
72.0k
    map->transforms = t;
1812
72.0k
    map->mpm = base_map->mpm;
1813
72.0k
    map->packet = base_map->packet;
1814
72.0k
    map->frame = base_map->frame;
1815
72.0k
    map->SetupCallback = base_map->SetupCallback;
1816
72.0k
    map->ValidateCallback = base_map->ValidateCallback;
1817
72.0k
    if (map->frame) {
1818
709
        DetectFrameMpmRegisterByParentId(de_ctx, map->id, map->parent_id, &map->transforms);
1819
71.3k
    } else if (map->packet) {
1820
6.52k
        DetectPktMpmRegisterByParentId(de_ctx,
1821
6.52k
                map->id, map->parent_id, &map->transforms);
1822
64.8k
    } else {
1823
64.8k
        DetectAppLayerMpmRegisterByParentId(de_ctx,
1824
64.8k
                map->id, map->parent_id, &map->transforms);
1825
64.8k
    }
1826
1827
72.0k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_name, (void *)map, 0) != 0);
1828
72.0k
    BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash_id, (void *)map, 0) != 0);
1829
72.0k
    SCLogDebug("buffer %s registered with id %d, parent %d", map->name, map->id, map->parent_id);
1830
1831
72.0k
    if (map->frame) {
1832
709
        DetectFrameInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
1833
71.3k
    } else if (map->packet) {
1834
6.52k
        DetectPktInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
1835
64.8k
    } else {
1836
64.8k
        DetectAppLayerInspectEngineCopy(de_ctx, map->parent_id, map->id, &map->transforms);
1837
64.8k
    }
1838
72.0k
    return map->id;
1839
72.0k
}
1840
1841
/* returns false if no match, true if match */
1842
static int DetectEngineInspectRulePacketMatches(
1843
    DetectEngineThreadCtx *det_ctx,
1844
    const DetectEnginePktInspectionEngine *engine,
1845
    const Signature *s,
1846
    Packet *p, uint8_t *_alert_flags)
1847
849k
{
1848
849k
    SCEnter();
1849
1850
    /* run the packet match functions */
1851
849k
    KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
1852
849k
    const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
1853
1854
849k
    SCLogDebug("running match functions, sm %p", smd);
1855
872k
    while (1) {
1856
872k
        KEYWORD_PROFILING_START;
1857
872k
        if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) <= 0) {
1858
686k
            KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
1859
686k
            SCLogDebug("no match");
1860
686k
            return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1861
686k
        }
1862
186k
        KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
1863
186k
        if (smd->is_last) {
1864
163k
            SCLogDebug("match and is_last");
1865
163k
            break;
1866
163k
        }
1867
22.9k
        smd++;
1868
22.9k
    }
1869
163k
    return DETECT_ENGINE_INSPECT_SIG_MATCH;
1870
849k
}
1871
1872
static int DetectEngineInspectRulePayloadMatches(
1873
     DetectEngineThreadCtx *det_ctx,
1874
     const DetectEnginePktInspectionEngine *engine,
1875
     const Signature *s, Packet *p, uint8_t *alert_flags)
1876
671k
{
1877
671k
    SCEnter();
1878
1879
671k
    DetectEngineCtx *de_ctx = det_ctx->de_ctx;
1880
1881
671k
    KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH);
1882
    /* if we have stream msgs, inspect against those first,
1883
     * but not for a "dsize" signature */
1884
671k
    if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1885
651k
        int pmatch = 0;
1886
651k
        if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
1887
156k
            pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, p);
1888
156k
            if (pmatch) {
1889
94.3k
                *alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH;
1890
94.3k
            }
1891
156k
        }
1892
        /* no match? then inspect packet payload */
1893
651k
        if (pmatch == 0) {
1894
556k
            SCLogDebug("no match in stream, fall back to packet payload");
1895
1896
            /* skip if we don't have to inspect the packet and segment was
1897
             * added to stream */
1898
556k
            if (!(s->flags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) {
1899
314k
                return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1900
314k
            }
1901
242k
            if (s->flags & SIG_FLAG_REQUIRE_STREAM_ONLY) {
1902
0
                SCLogDebug("SIG_FLAG_REQUIRE_STREAM_ONLY, so no match");
1903
0
                return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1904
0
            }
1905
242k
            if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1906
94.2k
                return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1907
94.2k
            }
1908
242k
        }
1909
651k
    } else {
1910
20.1k
        if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1911
14.6k
            return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
1912
14.6k
        }
1913
20.1k
    }
1914
248k
    return DETECT_ENGINE_INSPECT_SIG_MATCH;
1915
671k
}
1916
1917
bool DetectEnginePktInspectionRun(ThreadVars *tv,
1918
        DetectEngineThreadCtx *det_ctx, const Signature *s,
1919
        Flow *f, Packet *p,
1920
        uint8_t *alert_flags)
1921
1.90M
{
1922
1.90M
    SCEnter();
1923
1924
2.33M
    for (DetectEnginePktInspectionEngine *e = s->pkt_inspect; e != NULL; e = e->next) {
1925
1.57M
        if (e->v1.Callback(det_ctx, e, s, p, alert_flags) != DETECT_ENGINE_INSPECT_SIG_MATCH) {
1926
1.14M
            SCLogDebug("sid %u: e %p Callback returned no match", s->id, e);
1927
1.14M
            return false;
1928
1.14M
        }
1929
433k
        SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
1930
433k
    }
1931
1932
761k
    SCLogDebug("sid %u: returning true", s->id);
1933
761k
    return true;
1934
1.90M
}
1935
1936
/**
1937
 * \param data pointer to SigMatchData. Allowed to be NULL.
1938
 */
1939
static int DetectEnginePktInspectionAppend(Signature *s, InspectionBufferPktInspectFunc Callback,
1940
        SigMatchData *data, const int list_id)
1941
89.8k
{
1942
89.8k
    DetectEnginePktInspectionEngine *e = SCCalloc(1, sizeof(*e));
1943
89.8k
    if (e == NULL)
1944
0
        return -1;
1945
1946
89.8k
    e->mpm = s->init_data->mpm_sm_list == list_id;
1947
89.8k
    DEBUG_VALIDATE_BUG_ON(list_id < 0 || list_id > UINT16_MAX);
1948
89.8k
    e->sm_list = (uint16_t)list_id;
1949
89.8k
    e->sm_list_base = (uint16_t)list_id;
1950
89.8k
    e->v1.Callback = Callback;
1951
89.8k
    e->smd = data;
1952
1953
89.8k
    if (s->pkt_inspect == NULL) {
1954
83.9k
        s->pkt_inspect = e;
1955
83.9k
    } else {
1956
5.84k
        DetectEnginePktInspectionEngine *a = s->pkt_inspect;
1957
7.77k
        while (a->next != NULL) {
1958
1.93k
            a = a->next;
1959
1.93k
        }
1960
5.84k
        a->next = e;
1961
5.84k
    }
1962
89.8k
    return 0;
1963
89.8k
}
1964
1965
int DetectEnginePktInspectionSetup(Signature *s)
1966
161k
{
1967
    /* only handle PMATCH here if we're not an app inspect rule */
1968
161k
    if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) {
1969
33.1k
        if (DetectEnginePktInspectionAppend(
1970
33.1k
                    s, DetectEngineInspectRulePayloadMatches, NULL, DETECT_SM_LIST_PMATCH) < 0)
1971
0
            return -1;
1972
33.1k
        SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id);
1973
33.1k
    }
1974
1975
161k
    if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
1976
56.6k
        if (DetectEnginePktInspectionAppend(
1977
56.6k
                    s, DetectEngineInspectRulePacketMatches, NULL, DETECT_SM_LIST_MATCH) < 0)
1978
0
            return -1;
1979
56.6k
        SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id);
1980
56.6k
    }
1981
1982
161k
    return 0;
1983
161k
}
1984
1985
/* code to control the main thread to do a reload */
1986
1987
enum DetectEngineSyncState {
1988
    IDLE,   /**< ready to start a reload */
1989
    RELOAD, /**< command main thread to do the reload */
1990
};
1991
1992
1993
typedef struct DetectEngineSyncer_ {
1994
    SCMutex m;
1995
    enum DetectEngineSyncState state;
1996
} DetectEngineSyncer;
1997
1998
static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE };
1999
2000
/* tell main to start reloading */
2001
int DetectEngineReloadStart(void)
2002
0
{
2003
0
    int r = 0;
2004
0
    SCMutexLock(&detect_sync.m);
2005
0
    if (detect_sync.state == IDLE) {
2006
0
        detect_sync.state = RELOAD;
2007
0
    } else {
2008
0
        r = -1;
2009
0
    }
2010
0
    SCMutexUnlock(&detect_sync.m);
2011
0
    return r;
2012
0
}
2013
2014
/* main thread checks this to see if it should start */
2015
int DetectEngineReloadIsStart(void)
2016
0
{
2017
0
    int r = 0;
2018
0
    SCMutexLock(&detect_sync.m);
2019
0
    if (detect_sync.state == RELOAD) {
2020
0
        r = 1;
2021
0
    }
2022
0
    SCMutexUnlock(&detect_sync.m);
2023
0
    return r;
2024
0
}
2025
2026
/* main thread sets done when it's done */
2027
void DetectEngineReloadSetIdle(void)
2028
0
{
2029
0
    SCMutexLock(&detect_sync.m);
2030
0
    detect_sync.state = IDLE;
2031
0
    SCMutexUnlock(&detect_sync.m);
2032
0
}
2033
2034
/* caller loops this until it returns 1 */
2035
int DetectEngineReloadIsIdle(void)
2036
0
{
2037
0
    int r = 0;
2038
0
    SCMutexLock(&detect_sync.m);
2039
0
    if (detect_sync.state == IDLE) {
2040
0
        r = 1;
2041
0
    }
2042
0
    SCMutexUnlock(&detect_sync.m);
2043
0
    return r;
2044
0
}
2045
2046
/** \brief Do the content inspection & validation for a signature
2047
 *
2048
 *  \param de_ctx Detection engine context
2049
 *  \param det_ctx Detection engine thread context
2050
 *  \param s Signature to inspect
2051
 *  \param sm SigMatch to inspect
2052
 *  \param f Flow
2053
 *  \param flags app layer flags
2054
 *  \param state App layer state
2055
 *
2056
 *  \retval 0 no match
2057
 *  \retval 1 match
2058
 */
2059
uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2060
        const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
2061
        uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
2062
73.3k
{
2063
73.3k
    SigMatchData *smd = engine->smd;
2064
73.3k
    SCLogDebug("running match functions, sm %p", smd);
2065
73.3k
    if (smd != NULL) {
2066
73.7k
        while (1) {
2067
73.7k
            int match = 0;
2068
73.7k
            KEYWORD_PROFILING_START;
2069
73.7k
            match = sigmatch_table[smd->type].
2070
73.7k
                AppLayerTxMatch(det_ctx, f, flags, alstate, txv, s, smd->ctx);
2071
73.7k
            KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1));
2072
73.7k
            if (match == 0)
2073
56.4k
                return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2074
17.3k
            if (match == 2) {
2075
0
                return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
2076
0
            }
2077
2078
17.3k
            if (smd->is_last)
2079
16.9k
                break;
2080
372
            smd++;
2081
372
        }
2082
73.3k
    }
2083
2084
16.9k
    return DETECT_ENGINE_INSPECT_SIG_MATCH;
2085
73.3k
}
2086
2087
/**
2088
 * \brief Do the content inspection & validation for a signature
2089
 *
2090
 * \param de_ctx Detection engine context
2091
 * \param det_ctx Detection engine thread context
2092
 * \param s Signature to inspect
2093
 * \param f Flow
2094
 * \param flags app layer flags
2095
 * \param state App layer state
2096
 *
2097
 * \retval 0 no match.
2098
 * \retval 1 match.
2099
 * \retval 2 Sig can't match.
2100
 */
2101
uint8_t DetectEngineInspectBufferSingle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2102
        const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags,
2103
        void *alstate, void *txv, uint64_t tx_id)
2104
3.03k
{
2105
3.03k
    const int list_id = engine->sm_list;
2106
3.03k
    SCLogDebug("running inspect on %d", list_id);
2107
2108
3.03k
    const bool eof =
2109
3.03k
            (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress);
2110
2111
3.03k
    SCLogDebug("list %d mpm? %s transforms %p", engine->sm_list, engine->mpm ? "true" : "false",
2112
3.03k
            engine->v2.transforms);
2113
2114
    /* if prefilter didn't already run, we need to consider transformations */
2115
3.03k
    const DetectEngineTransforms *transforms = NULL;
2116
3.03k
    if (!engine->mpm) {
2117
424
        transforms = engine->v2.transforms;
2118
424
    }
2119
2120
3.03k
    const InspectionBuffer *buffer = DetectGetSingleData(
2121
3.03k
            det_ctx, transforms, f, flags, txv, list_id, engine->v2.GetDataSingle);
2122
3.03k
    if (unlikely(buffer == NULL)) {
2123
351
        if (eof && engine->match_on_null) {
2124
0
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
2125
0
        }
2126
351
        return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2127
351
    }
2128
2129
2.68k
    const uint32_t data_len = buffer->inspect_len;
2130
2.68k
    const uint8_t *data = buffer->inspect;
2131
2.68k
    const uint64_t offset = buffer->inspect_offset;
2132
2133
2.68k
    uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0;
2134
2.68k
    ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0);
2135
2.68k
    ci_flags |= buffer->flags;
2136
2137
    /* Inspect all the uricontents fetched on each
2138
     * transaction at the app layer */
2139
2.68k
    const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, data,
2140
2.68k
            data_len, offset, ci_flags, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
2141
2.68k
    if (match) {
2142
2.65k
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
2143
2.65k
    } else {
2144
33
        return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH : DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2145
33
    }
2146
2.68k
}
2147
2148
/**
2149
 * \brief Do the content inspection & validation for a signature
2150
 *
2151
 * \param de_ctx Detection engine context
2152
 * \param det_ctx Detection engine thread context
2153
 * \param s Signature to inspect
2154
 * \param f Flow
2155
 * \param flags app layer flags
2156
 * \param state App layer state
2157
 *
2158
 * \retval 0 no match.
2159
 * \retval 1 match.
2160
 * \retval 2 Sig can't match.
2161
 */
2162
uint8_t DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
2163
        const DetectEngineAppInspectionEngine *engine, const Signature *s, Flow *f, uint8_t flags,
2164
        void *alstate, void *txv, uint64_t tx_id)
2165
30.8k
{
2166
30.8k
    const int list_id = engine->sm_list;
2167
30.8k
    SCLogDebug("running inspect on %d", list_id);
2168
2169
30.8k
    const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress);
2170
2171
30.8k
    SCLogDebug("list %d mpm? %s transforms %p",
2172
30.8k
            engine->sm_list, engine->mpm ? "true" : "false", engine->v2.transforms);
2173
2174
    /* if prefilter didn't already run, we need to consider transformations */
2175
30.8k
    const DetectEngineTransforms *transforms = NULL;
2176
30.8k
    if (!engine->mpm) {
2177
24.9k
        transforms = engine->v2.transforms;
2178
24.9k
    }
2179
2180
30.8k
    const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms,
2181
30.8k
            f, flags, txv, list_id);
2182
30.8k
    if (unlikely(buffer == NULL)) {
2183
6.74k
        if (eof && engine->match_on_null) {
2184
0
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
2185
0
        }
2186
6.74k
        return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH :
2187
6.74k
                     DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2188
6.74k
    }
2189
2190
24.1k
    const uint32_t data_len = buffer->inspect_len;
2191
24.1k
    const uint8_t *data = buffer->inspect;
2192
24.1k
    const uint64_t offset = buffer->inspect_offset;
2193
2194
24.1k
    uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0;
2195
24.1k
    ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0);
2196
24.1k
    ci_flags |= buffer->flags;
2197
2198
    /* Inspect all the uricontents fetched on each
2199
     * transaction at the app layer */
2200
24.1k
    const bool match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f, data,
2201
24.1k
            data_len, offset, ci_flags, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
2202
24.1k
    if (match) {
2203
13.1k
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
2204
13.1k
    } else {
2205
10.9k
        return eof ? DETECT_ENGINE_INSPECT_SIG_CANT_MATCH :
2206
10.9k
                     DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2207
10.9k
    }
2208
24.1k
}
2209
2210
// wrapper for both DetectAppLayerInspectEngineRegister and DetectAppLayerMpmRegister
2211
// with cast of callback function
2212
void DetectAppLayerMultiRegister(const char *name, AppProto alproto, uint32_t dir, int progress,
2213
        InspectionMultiBufferGetDataPtr GetData, int priority)
2214
2.96k
{
2215
2.96k
    AppLayerInspectEngineRegisterInternal(name, alproto, dir, progress,
2216
2.96k
            DetectEngineInspectMultiBufferGeneric, NULL, NULL, GetData);
2217
2.96k
    DetectAppLayerMpmMultiRegister(
2218
2.96k
            name, dir, priority, PrefilterMultiGenericMpmRegister, GetData, alproto, progress);
2219
2.96k
}
2220
2221
InspectionBuffer *DetectGetSingleData(struct DetectEngineThreadCtx_ *det_ctx,
2222
        const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv,
2223
        const int list_id, InspectionSingleBufferGetDataPtr GetBuf)
2224
7.70k
{
2225
7.70k
    InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
2226
7.70k
    if (buffer->inspect == NULL) {
2227
5.09k
        const uint8_t *b = NULL;
2228
5.09k
        uint32_t b_len = 0;
2229
2230
5.09k
        if (!GetBuf(txv, flow_flags, &b, &b_len))
2231
1.86k
            return NULL;
2232
2233
3.22k
        InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms);
2234
3.22k
    }
2235
5.84k
    return buffer;
2236
7.70k
}
2237
2238
InspectionBuffer *DetectGetMultiData(struct DetectEngineThreadCtx_ *det_ctx,
2239
        const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv,
2240
        const int list_id, uint32_t index, InspectionMultiBufferGetDataPtr GetBuf)
2241
240k
{
2242
240k
    InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, index);
2243
240k
    if (buffer == NULL) {
2244
0
        return NULL;
2245
0
    }
2246
240k
    if (buffer->initialized) {
2247
2.53k
        return buffer;
2248
2.53k
    }
2249
2250
238k
    const uint8_t *data = NULL;
2251
238k
    uint32_t data_len = 0;
2252
2253
238k
    if (!GetBuf(det_ctx, txv, flow_flags, index, &data, &data_len)) {
2254
118k
        InspectionBufferSetupMultiEmpty(buffer);
2255
118k
        return NULL;
2256
118k
    }
2257
119k
    InspectionBufferSetupMulti(det_ctx, buffer, transforms, data, data_len);
2258
119k
    buffer->flags = DETECT_CI_FLAGS_SINGLE;
2259
119k
    return buffer;
2260
238k
}
2261
2262
uint8_t DetectEngineInspectMultiBufferGeneric(DetectEngineCtx *de_ctx,
2263
        DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine,
2264
        const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
2265
108k
{
2266
108k
    uint32_t local_id = 0;
2267
108k
    const DetectEngineTransforms *transforms = NULL;
2268
108k
    if (!engine->mpm) {
2269
106k
        transforms = engine->v2.transforms;
2270
106k
    }
2271
2272
215k
    do {
2273
215k
        InspectionBuffer *buffer = DetectGetMultiData(det_ctx, transforms, f, flags, txv,
2274
215k
                engine->sm_list, local_id, engine->v2.GetMultiData);
2275
2276
215k
        if (buffer == NULL || buffer->inspect == NULL)
2277
106k
            break;
2278
2279
        // The GetData functions set buffer->flags to DETECT_CI_FLAGS_SINGLE
2280
        // This is not meant for streaming buffers
2281
109k
        const bool match = DetectEngineContentInspectionBuffer(de_ctx, det_ctx, s, engine->smd,
2282
109k
                NULL, f, buffer, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
2283
109k
        if (match) {
2284
2.45k
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
2285
2.45k
        }
2286
106k
        local_id++;
2287
106k
    } while (1);
2288
106k
    if (local_id == 0) {
2289
        // That means we did not get even one buffer value from the multi-buffer
2290
97
        const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) >
2291
97
                          engine->progress);
2292
97
        if (eof && engine->match_on_null) {
2293
39
            return DETECT_ENGINE_INSPECT_SIG_MATCH;
2294
39
        }
2295
97
    }
2296
106k
    return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2297
106k
}
2298
2299
/**
2300
 * \brief Do the content inspection & validation for a signature
2301
 *
2302
 * \param de_ctx Detection engine context
2303
 * \param det_ctx Detection engine thread context
2304
 * \param s Signature to inspect
2305
 * \param p Packet
2306
 *
2307
 * \retval 0 no match.
2308
 * \retval 1 match.
2309
 */
2310
int DetectEngineInspectPktBufferGeneric(
2311
        DetectEngineThreadCtx *det_ctx,
2312
        const DetectEnginePktInspectionEngine *engine,
2313
        const Signature *s, Packet *p, uint8_t *_alert_flags)
2314
56.2k
{
2315
56.2k
    const int list_id = engine->sm_list;
2316
56.2k
    SCLogDebug("running inspect on %d", list_id);
2317
2318
56.2k
    SCLogDebug("list %d transforms %p",
2319
56.2k
            engine->sm_list, engine->v1.transforms);
2320
2321
    /* if prefilter didn't already run, we need to consider transformations */
2322
56.2k
    const DetectEngineTransforms *transforms = NULL;
2323
56.2k
    if (!engine->mpm) {
2324
34.1k
        transforms = engine->v1.transforms;
2325
34.1k
    }
2326
2327
56.2k
    const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p,
2328
56.2k
            list_id);
2329
56.2k
    if (unlikely(buffer == NULL)) {
2330
3.66k
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2331
3.66k
    }
2332
2333
52.5k
    uint8_t ci_flags = DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END;
2334
52.5k
    ci_flags |= buffer->flags;
2335
2336
    /* Inspect all the uricontents fetched on each
2337
     * transaction at the app layer */
2338
52.5k
    const bool match = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx, s, engine->smd, p,
2339
52.5k
            p->flow, buffer->inspect, buffer->inspect_len, 0, ci_flags,
2340
52.5k
            DETECT_ENGINE_CONTENT_INSPECTION_MODE_HEADER);
2341
52.5k
    if (match) {
2342
21.9k
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
2343
30.5k
    } else {
2344
30.5k
        return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
2345
30.5k
    }
2346
52.5k
}
2347
2348
/** \internal
2349
 *  \brief inject a pseudo packet into each detect thread
2350
 *      -that doesn't use the new det_ctx yet
2351
 *      -*or*, if the thread should flush its output logs.
2352
 */
2353
static void InjectPackets(
2354
        ThreadVars **detect_tvs, DetectEngineThreadCtx **new_det_ctx, int no_of_detect_tvs)
2355
0
{
2356
    /* inject a fake packet if the detect thread that needs it. This function
2357
     * is called if
2358
     *  - A thread isn't using a DE ctx and should
2359
     *  - Or, it should process a pseudo packet and flush its output logs.
2360
     * to speed the process. */
2361
0
    for (int i = 0; i < no_of_detect_tvs; i++) {
2362
0
        if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
2363
0
            if (detect_tvs[i]->inq != NULL) {
2364
0
                Packet *p = PacketGetFromAlloc();
2365
0
                if (p != NULL) {
2366
0
                    p->flags |= PKT_PSEUDO_STREAM_END;
2367
0
                    PKT_SET_SRC(p, PKT_SRC_DETECT_RELOAD_FLUSH);
2368
0
                    PacketQueue *q = detect_tvs[i]->inq->pq;
2369
0
                    SCMutexLock(&q->mutex_q);
2370
0
                    PacketEnqueue(q, p);
2371
0
                    SCCondSignal(&q->cond_q);
2372
0
                    SCMutexUnlock(&q->mutex_q);
2373
0
                }
2374
0
            }
2375
0
        }
2376
0
    }
2377
0
}
2378
2379
/** \internal
2380
 *  \brief Update detect threads with new detect engine
2381
 *
2382
 *  Atomically update each detect thread with a new thread context
2383
 *  that is associated to the new detection engine(s).
2384
 *
2385
 *  If called in unix socket mode, it's possible that we don't have
2386
 *  detect threads yet.
2387
 *
2388
 *  \retval -1 error
2389
 *  \retval 0 no detection threads
2390
 *  \retval 1 successful reload
2391
 */
2392
static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
2393
17.5k
{
2394
17.5k
    SCEnter();
2395
17.5k
    uint32_t i = 0;
2396
2397
    /* count detect threads in use */
2398
17.5k
    uint32_t no_of_detect_tvs = TmThreadCountThreadsByTmmFlags(TM_FLAG_FLOWWORKER_TM);
2399
    /* can be zero in unix socket mode */
2400
17.5k
    if (no_of_detect_tvs == 0) {
2401
17.5k
        return 0;
2402
17.5k
    }
2403
2404
    /* prepare swap structures */
2405
0
    DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
2406
0
    DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
2407
0
    ThreadVars *detect_tvs[no_of_detect_tvs];
2408
0
    memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
2409
0
    memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
2410
0
    memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *)));
2411
2412
    /* start the process of swapping detect threads ctxs */
2413
2414
    /* get reference to tv's and setup new_det_ctx array */
2415
0
    SCMutexLock(&tv_root_lock);
2416
0
    for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
2417
0
        if ((tv->tmm_flags & TM_FLAG_FLOWWORKER_TM) == 0) {
2418
0
            continue;
2419
0
        }
2420
0
        for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
2421
0
            TmModule *tm = TmModuleGetById(s->tm_id);
2422
0
            if (!(tm->flags & TM_FLAG_FLOWWORKER_TM)) {
2423
0
                continue;
2424
0
            }
2425
2426
0
            if (suricata_ctl_flags != 0) {
2427
0
                SCMutexUnlock(&tv_root_lock);
2428
0
                goto error;
2429
0
            }
2430
2431
0
            old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(s->slot_data));
2432
0
            detect_tvs[i] = tv;
2433
2434
0
            new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
2435
0
            if (new_det_ctx[i] == NULL) {
2436
0
                SCLogError("Detect engine thread init "
2437
0
                           "failure in live rule swap.  Let's get out of here");
2438
0
                SCMutexUnlock(&tv_root_lock);
2439
0
                goto error;
2440
0
            }
2441
0
            SCLogDebug("live rule swap created new det_ctx - %p and de_ctx "
2442
0
                       "- %p\n", new_det_ctx[i], new_de_ctx);
2443
0
            i++;
2444
0
            break;
2445
0
        }
2446
0
    }
2447
0
    BUG_ON(i != no_of_detect_tvs);
2448
2449
    /* atomically replace the det_ctx data */
2450
0
    i = 0;
2451
0
    for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
2452
0
        if ((tv->tmm_flags & TM_FLAG_FLOWWORKER_TM) == 0) {
2453
0
            continue;
2454
0
        }
2455
0
        for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
2456
0
            TmModule *tm = TmModuleGetById(s->tm_id);
2457
0
            if (!(tm->flags & TM_FLAG_FLOWWORKER_TM)) {
2458
0
                continue;
2459
0
            }
2460
0
            SCLogDebug("swapping new det_ctx - %p with older one - %p",
2461
0
                       new_det_ctx[i], SC_ATOMIC_GET(s->slot_data));
2462
0
            FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(s->slot_data), new_det_ctx[i++]);
2463
0
            break;
2464
0
        }
2465
0
    }
2466
0
    SCMutexUnlock(&tv_root_lock);
2467
2468
    /* threads now all have new data, however they may not have started using
2469
     * it and may still use the old data */
2470
2471
0
    SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, "
2472
0
               "along with the new de_ctx", no_of_detect_tvs);
2473
2474
0
    InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs);
2475
2476
    /* loop waiting for detect threads to switch to the new det_ctx. Try to
2477
     * wake up capture if needed (break loop). */
2478
0
    uint32_t threads_done = 0;
2479
0
retry:
2480
0
    for (i = 0; i < no_of_detect_tvs; i++) {
2481
0
        if (suricata_ctl_flags != 0) {
2482
0
            threads_done = no_of_detect_tvs;
2483
0
            break;
2484
0
        }
2485
0
        SleepMsec(1);
2486
0
        if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) == 1) {
2487
0
            SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]);
2488
0
            threads_done++;
2489
0
        } else {
2490
0
            TmThreadsCaptureBreakLoop(detect_tvs[i]);
2491
0
        }
2492
0
    }
2493
0
    if (threads_done < no_of_detect_tvs) {
2494
0
        threads_done = 0;
2495
0
        SleepMsec(250);
2496
0
        goto retry;
2497
0
    }
2498
2499
    /* this is to make sure that if someone initiated shutdown during a live
2500
     * rule swap, the live rule swap won't clean up the old det_ctx and
2501
     * de_ctx, till all detect threads have stopped working and sitting
2502
     * silently after setting RUNNING_DONE flag and while waiting for
2503
     * THV_DEINIT flag */
2504
0
    if (i != no_of_detect_tvs) { // not all threads we swapped
2505
0
        for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
2506
0
            if ((tv->tmm_flags & TM_FLAG_FLOWWORKER_TM) == 0) {
2507
0
                continue;
2508
0
            }
2509
2510
0
            while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) {
2511
0
                SleepUsec(100);
2512
0
            }
2513
0
        }
2514
0
    }
2515
2516
    /* free all the ctxs */
2517
0
    for (i = 0; i < no_of_detect_tvs; i++) {
2518
0
        SCLogDebug("Freeing old_det_ctx - %p used by detect",
2519
0
                   old_det_ctx[i]);
2520
0
        DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
2521
0
    }
2522
2523
0
    SRepReloadComplete();
2524
2525
0
    return 1;
2526
2527
0
 error:
2528
0
    for (i = 0; i < no_of_detect_tvs; i++) {
2529
0
        if (new_det_ctx[i] != NULL)
2530
0
            DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]);
2531
0
    }
2532
0
    return -1;
2533
0
}
2534
2535
bool DetectEngineMpmCachingEnabled(void)
2536
0
{
2537
0
    int sgh_mpm_caching = 0;
2538
0
    if (SCConfGetBool("detect.sgh-mpm-caching", &sgh_mpm_caching) != 1) {
2539
0
        return false;
2540
0
    }
2541
0
    return (bool)sgh_mpm_caching;
2542
0
}
2543
2544
const char *DetectEngineMpmCachingGetPath(void)
2545
0
{
2546
0
    if (DetectEngineMpmCachingEnabled() == false) {
2547
0
        return NULL;
2548
0
    }
2549
2550
0
    char yamlpath[] = "detect.sgh-mpm-caching-path";
2551
0
    const char *strval = NULL;
2552
0
    if (SCConfGet(yamlpath, &strval) == 1 && strval != NULL) {
2553
0
        return strval;
2554
0
    }
2555
2556
0
    static bool notified = false;
2557
0
    if (!notified) {
2558
0
        SCLogInfo("%s has no path specified, using %s", yamlpath, SGH_CACHE_DIR);
2559
0
        notified = true;
2560
0
    }
2561
0
    return SGH_CACHE_DIR;
2562
0
}
2563
2564
void DetectEngineMpmCacheService(uint32_t op_flags)
2565
82.2k
{
2566
82.2k
    DetectEngineCtx *de_ctx = DetectEngineGetCurrent();
2567
82.2k
    if (!de_ctx) {
2568
0
        return;
2569
0
    }
2570
2571
82.2k
    if (!de_ctx->mpm_cfg || !de_ctx->mpm_cfg->cache_dir_path) {
2572
82.2k
        goto error;
2573
82.2k
    }
2574
2575
0
    if (mpm_table[de_ctx->mpm_matcher].CacheStatsInit != NULL) {
2576
0
        de_ctx->mpm_cfg->cache_stats = mpm_table[de_ctx->mpm_matcher].CacheStatsInit();
2577
0
        if (de_ctx->mpm_cfg->cache_stats == NULL) {
2578
0
            goto error;
2579
0
        }
2580
0
    }
2581
2582
0
    if (op_flags & DETECT_ENGINE_MPM_CACHE_OP_SAVE) {
2583
0
        if (mpm_table[de_ctx->mpm_matcher].CacheRuleset != NULL) {
2584
0
            mpm_table[de_ctx->mpm_matcher].CacheRuleset(de_ctx->mpm_cfg);
2585
0
        }
2586
0
    }
2587
2588
0
    if (op_flags & DETECT_ENGINE_MPM_CACHE_OP_PRUNE) {
2589
0
        if (mpm_table[de_ctx->mpm_matcher].CachePrune != NULL) {
2590
0
            mpm_table[de_ctx->mpm_matcher].CachePrune(de_ctx->mpm_cfg);
2591
0
        }
2592
0
    }
2593
2594
0
    if (mpm_table[de_ctx->mpm_matcher].CacheStatsPrint != NULL) {
2595
0
        mpm_table[de_ctx->mpm_matcher].CacheStatsPrint(de_ctx->mpm_cfg->cache_stats);
2596
0
    }
2597
2598
0
    if (mpm_table[de_ctx->mpm_matcher].CacheStatsDeinit != NULL) {
2599
0
        mpm_table[de_ctx->mpm_matcher].CacheStatsDeinit(de_ctx->mpm_cfg->cache_stats);
2600
0
        de_ctx->mpm_cfg->cache_stats = NULL;
2601
0
    }
2602
2603
82.2k
error:
2604
82.2k
    DetectEngineDeReference(&de_ctx);
2605
82.2k
}
2606
2607
static DetectEngineCtx *DetectEngineCtxInitReal(
2608
        enum DetectEngineType type, const char *prefix, uint32_t tenant_id)
2609
114k
{
2610
114k
    DetectEngineCtx *de_ctx = SCCalloc(1, sizeof(DetectEngineCtx));
2611
114k
    if (unlikely(de_ctx == NULL))
2612
0
        goto error;
2613
2614
114k
    memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
2615
114k
    TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
2616
114k
    de_ctx->sigerror = NULL;
2617
114k
    de_ctx->type = type;
2618
114k
    de_ctx->filemagic_thread_ctx_id = -1;
2619
114k
    de_ctx->tenant_id = tenant_id;
2620
2621
114k
    de_ctx->mpm_matcher = PatternMatchDefaultMatcher();
2622
114k
    de_ctx->spm_matcher = SinglePatternMatchDefaultMatcher();
2623
2624
114k
    if (mpm_table[de_ctx->mpm_matcher].ConfigInit) {
2625
0
        de_ctx->mpm_cfg = mpm_table[de_ctx->mpm_matcher].ConfigInit();
2626
0
        if (de_ctx->mpm_cfg == NULL) {
2627
0
            goto error;
2628
0
        }
2629
2630
0
        if (DetectEngineMpmCachingEnabled() && mpm_table[de_ctx->mpm_matcher].ConfigCacheDirSet) {
2631
0
            mpm_table[de_ctx->mpm_matcher].ConfigCacheDirSet(
2632
0
                    de_ctx->mpm_cfg, DetectEngineMpmCachingGetPath());
2633
2634
0
            if (mpm_table[de_ctx->mpm_matcher].CachePrune) {
2635
0
                if (SCConfGetTime("detect.sgh-mpm-caching-max-age",
2636
0
                            &de_ctx->mpm_cfg->cache_max_age_seconds) != 1) {
2637
0
                    de_ctx->mpm_cfg->cache_max_age_seconds = 7ULL * 24ULL * 60ULL * 60ULL;
2638
0
                }
2639
0
            }
2640
0
        }
2641
0
    }
2642
2643
114k
    if (type == DETECT_ENGINE_TYPE_DD_STUB || type == DETECT_ENGINE_TYPE_MT_STUB) {
2644
0
        de_ctx->version = DetectEngineGetVersion();
2645
0
        SCLogDebug("stub %u with version %u", type, de_ctx->version);
2646
0
        return de_ctx;
2647
0
    }
2648
2649
114k
    if (prefix != NULL) {
2650
0
        strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix));
2651
0
    }
2652
2653
114k
    int failure_fatal = 0;
2654
114k
    if (SCConfGetBool("engine.init-failure-fatal", (int *)&failure_fatal) != 1) {
2655
114k
        SCLogDebug("ConfGetBool could not load the value.");
2656
114k
    }
2657
114k
    de_ctx->failure_fatal = (failure_fatal == 1);
2658
2659
114k
    SCLogConfig("pattern matchers: MPM: %s, SPM: %s", mpm_table[de_ctx->mpm_matcher].name,
2660
114k
            spm_table[de_ctx->spm_matcher].name);
2661
114k
    de_ctx->spm_global_thread_ctx = SpmInitGlobalThreadCtx(de_ctx->spm_matcher);
2662
114k
    if (de_ctx->spm_global_thread_ctx == NULL) {
2663
0
        SCLogDebug("Unable to alloc SpmGlobalThreadCtx.");
2664
0
        goto error;
2665
0
    }
2666
2667
114k
    de_ctx->sm_types_prefilter = SCCalloc(DETECT_TBLSIZE, sizeof(bool));
2668
114k
    if (de_ctx->sm_types_prefilter == NULL) {
2669
0
        goto error;
2670
0
    }
2671
114k
    de_ctx->sm_types_silent_error = SCCalloc(DETECT_TBLSIZE, sizeof(bool));
2672
114k
    if (de_ctx->sm_types_silent_error == NULL) {
2673
0
        goto error;
2674
0
    }
2675
114k
    if (DetectEngineCtxLoadConf(de_ctx) == -1) {
2676
0
        goto error;
2677
0
    }
2678
2679
114k
    SigGroupHeadHashInit(de_ctx);
2680
114k
    MpmStoreInit(de_ctx);
2681
114k
    DetectParseDupSigHashInit(de_ctx);
2682
114k
    DetectAddressMapInit(de_ctx);
2683
114k
    DetectMetadataHashInit(de_ctx);
2684
114k
    DetectBufferTypeSetupDetectEngine(de_ctx);
2685
114k
    DetectEngineInitializeFastPatternList(de_ctx);
2686
2687
    /* init iprep... ignore errors for now */
2688
114k
    (void)SRepInit(de_ctx);
2689
2690
114k
    SCClassSCConfInit(de_ctx);
2691
114k
    if (!SCClassConfLoadClassificationConfigFile(de_ctx, NULL)) {
2692
114k
        if (SCRunmodeGet() == RUNMODE_CONF_TEST)
2693
0
            goto error;
2694
114k
    }
2695
2696
114k
    if (ActionInitConfig() < 0) {
2697
0
        goto error;
2698
0
    }
2699
114k
    SCReferenceSCConfInit(de_ctx);
2700
114k
    if (SCRConfLoadReferenceConfigFile(de_ctx, NULL) < 0) {
2701
114k
        if (SCRunmodeGet() == RUNMODE_CONF_TEST)
2702
0
            goto error;
2703
114k
    }
2704
2705
114k
    de_ctx->version = DetectEngineGetVersion();
2706
114k
    SCLogDebug("dectx with version %u", de_ctx->version);
2707
114k
    return de_ctx;
2708
0
error:
2709
0
    if (de_ctx != NULL) {
2710
0
        DetectEngineCtxFree(de_ctx);
2711
0
    }
2712
0
    return NULL;
2713
114k
}
2714
2715
DetectEngineCtx *DetectEngineCtxInitStubForMT(void)
2716
0
{
2717
0
    return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_MT_STUB, NULL, 0);
2718
0
}
2719
2720
DetectEngineCtx *DetectEngineCtxInitStubForDD(void)
2721
0
{
2722
0
    return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_DD_STUB, NULL, 0);
2723
0
}
2724
2725
DetectEngineCtx *DetectEngineCtxInit(void)
2726
114k
{
2727
114k
    return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, NULL, 0);
2728
114k
}
2729
2730
DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix, uint32_t tenant_id)
2731
82.2k
{
2732
82.2k
    if (prefix == NULL || strlen(prefix) == 0)
2733
82.2k
        return DetectEngineCtxInit();
2734
0
    else
2735
0
        return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, prefix, tenant_id);
2736
82.2k
}
2737
2738
static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
2739
114k
{
2740
114k
    HashListTableFree(de_ctx->keyword_hash);
2741
114k
}
2742
2743
static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
2744
114k
{
2745
114k
    SigString *item = NULL;
2746
114k
    SigString *sitem;
2747
2748
4.62M
    TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
2749
4.62M
        SCFree(item->filename);
2750
4.62M
        SCFree(item->sig_str);
2751
4.62M
        if (item->sig_error) {
2752
10.6k
            SCFree(item->sig_error);
2753
10.6k
        }
2754
4.62M
        TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
2755
4.62M
        SCFree(item);
2756
4.62M
    }
2757
114k
}
2758
2759
/**
2760
 * \brief Free a DetectEngineCtx::
2761
 *
2762
 * \param de_ctx DetectEngineCtx:: to be freed
2763
 */
2764
void DetectEngineCtxFree(DetectEngineCtx *de_ctx)
2765
114k
{
2766
2767
114k
    if (de_ctx == NULL)
2768
0
        return;
2769
2770
#ifdef PROFILE_RULES
2771
    if (de_ctx->profile_ctx != NULL) {
2772
        SCProfilingRuleDestroyCtx(de_ctx->profile_ctx);
2773
        de_ctx->profile_ctx = NULL;
2774
    }
2775
#endif
2776
#ifdef PROFILING
2777
    if (de_ctx->profile_keyword_ctx != NULL) {
2778
        SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx);
2779
//        de_ctx->profile_keyword_ctx = NULL;
2780
    }
2781
    if (de_ctx->profile_sgh_ctx != NULL) {
2782
        SCProfilingSghDestroyCtx(de_ctx);
2783
    }
2784
    SCProfilingPrefilterDestroyCtx(de_ctx);
2785
#endif
2786
2787
114k
    if (mpm_table[de_ctx->mpm_matcher].ConfigDeinit) {
2788
0
        mpm_table[de_ctx->mpm_matcher].ConfigDeinit(&de_ctx->mpm_cfg);
2789
0
    }
2790
    /* Normally the hashes are freed elsewhere, but
2791
     * to be sure look at them again here.
2792
     */
2793
114k
    SigGroupHeadHashFree(de_ctx);
2794
114k
    MpmStoreFree(de_ctx);
2795
114k
    DetectParseDupSigHashFree(de_ctx);
2796
114k
    SCSigSignatureOrderingModuleCleanup(de_ctx);
2797
114k
    SigCleanSignatures(de_ctx);
2798
114k
    if (de_ctx->sig_array)
2799
98.5k
        SCFree(de_ctx->sig_array);
2800
2801
114k
    if (de_ctx->filedata_config)
2802
5.08k
        SCFree(de_ctx->filedata_config);
2803
2804
114k
    DetectEngineFreeFastPatternList(de_ctx);
2805
114k
    SCClassConfDeInitContext(de_ctx);
2806
114k
    SCRConfDeInitContext(de_ctx);
2807
2808
114k
    SigGroupCleanup(de_ctx);
2809
2810
114k
    SpmDestroyGlobalThreadCtx(de_ctx->spm_global_thread_ctx);
2811
114k
    SCFree(de_ctx->sm_types_prefilter);
2812
114k
    SCFree(de_ctx->sm_types_silent_error);
2813
2814
114k
    MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx);
2815
2816
114k
    DetectEngineCtxFreeThreadKeywordData(de_ctx);
2817
114k
    SRepDestroy(de_ctx);
2818
114k
    DetectEngineCtxFreeFailedSigs(de_ctx);
2819
2820
114k
    DetectAddressMapFree(de_ctx);
2821
114k
    DetectMetadataHashFree(de_ctx);
2822
2823
    /* if we have a config prefix, remove the config from the tree */
2824
114k
    if (strlen(de_ctx->config_prefix) > 0) {
2825
        /* remove config */
2826
0
        SCConfNode *node = SCConfGetNode(de_ctx->config_prefix);
2827
0
        if (node != NULL) {
2828
0
            SCConfNodeRemove(node); /* frees node */
2829
0
        }
2830
#if 0
2831
        SCConfDump();
2832
#endif
2833
0
    }
2834
2835
114k
    DetectPortCleanupList(de_ctx, de_ctx->tcp_priorityports);
2836
114k
    DetectPortCleanupList(de_ctx, de_ctx->udp_priorityports);
2837
2838
114k
    DetectBufferTypeFreeDetectEngine(de_ctx);
2839
114k
    SCClassConfDeinit(de_ctx);
2840
114k
    SCReferenceConfDeinit(de_ctx);
2841
2842
114k
    if (de_ctx->tenant_path) {
2843
0
        SCFree(de_ctx->tenant_path);
2844
0
    }
2845
2846
114k
    if (de_ctx->requirements) {
2847
1.43k
        SCDetectRequiresStatusFree(de_ctx->requirements);
2848
1.43k
    }
2849
2850
114k
    if (de_ctx->non_pf_engine_names) {
2851
45.8k
        HashTableFree(de_ctx->non_pf_engine_names);
2852
45.8k
    }
2853
114k
    if (de_ctx->fw_policies) {
2854
0
        for (uint32_t i = 0; i < DETECT_FIREWALL_POLICY_SIZE; i++) {
2855
0
            if (de_ctx->fw_policies->pkt_policy_signatures[i]) {
2856
0
                SCFree(de_ctx->fw_policies->pkt_policy_signatures[i]->msg);
2857
0
                SCFree(de_ctx->fw_policies->pkt_policy_signatures[i]);
2858
0
            }
2859
0
        }
2860
0
        HashTableFree(de_ctx->fw_policies->policy_signatures);
2861
0
    }
2862
114k
    SCFree(de_ctx->fw_policies);
2863
114k
    SCFree(de_ctx);
2864
    //DetectAddressGroupPrintMemory();
2865
    //DetectSigGroupPrintMemory();
2866
    //DetectPortPrintMemory();
2867
114k
}
2868
2869
/** \brief  Function that load DetectEngineCtx config for grouping sigs
2870
 *          used by the engine
2871
 *  \retval 0 if no config provided, 1 if config was provided
2872
 *          and loaded successfully
2873
 */
2874
static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx)
2875
114k
{
2876
114k
    uint8_t profile = ENGINE_PROFILE_MEDIUM;
2877
114k
    const char *max_uniq_toclient_groups_str = NULL;
2878
114k
    const char *max_uniq_toserver_groups_str = NULL;
2879
114k
    const char *sgh_mpm_context = NULL;
2880
114k
    const char *de_ctx_profile = NULL;
2881
2882
114k
    (void)SCConfGet("detect.profile", &de_ctx_profile);
2883
114k
    (void)SCConfGet("detect.sgh-mpm-context", &sgh_mpm_context);
2884
2885
114k
    SCConfNode *de_ctx_custom = SCConfGetNode("detect-engine");
2886
114k
    SCConfNode *opt = NULL;
2887
2888
114k
    if (de_ctx_custom != NULL) {
2889
0
        TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2890
0
            if (de_ctx_profile == NULL) {
2891
0
                if (opt->val && strcmp(opt->val, "profile") == 0) {
2892
0
                    de_ctx_profile = opt->head.tqh_first->val;
2893
0
                }
2894
0
            }
2895
2896
0
            if (sgh_mpm_context == NULL) {
2897
0
                if (opt->val && strcmp(opt->val, "sgh-mpm-context") == 0) {
2898
0
                    sgh_mpm_context = opt->head.tqh_first->val;
2899
0
                }
2900
0
            }
2901
0
        }
2902
0
    }
2903
2904
114k
    if (de_ctx_profile != NULL) {
2905
0
        if (strcmp(de_ctx_profile, "low") == 0 ||
2906
0
            strcmp(de_ctx_profile, "lowest") == 0) {        // legacy
2907
0
            profile = ENGINE_PROFILE_LOW;
2908
0
        } else if (strcmp(de_ctx_profile, "medium") == 0) {
2909
0
            profile = ENGINE_PROFILE_MEDIUM;
2910
0
        } else if (strcmp(de_ctx_profile, "high") == 0 ||
2911
0
                   strcmp(de_ctx_profile, "highest") == 0) { // legacy
2912
0
            profile = ENGINE_PROFILE_HIGH;
2913
0
        } else if (strcmp(de_ctx_profile, "custom") == 0) {
2914
0
            profile = ENGINE_PROFILE_CUSTOM;
2915
0
        } else {
2916
0
            SCLogError("invalid value for detect.profile: '%s'. "
2917
0
                       "Valid options: low, medium, high and custom.",
2918
0
                    de_ctx_profile);
2919
0
            return -1;
2920
0
        }
2921
2922
0
        SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
2923
114k
    } else {
2924
114k
        SCLogDebug("Profile for detection engine groups not provided "
2925
114k
                   "at suricata.yaml. Using default (\"medium\").");
2926
114k
    }
2927
2928
    /* detect-engine.sgh-mpm-context option parsing */
2929
114k
    if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) {
2930
        /* for now, since we still haven't implemented any intelligence into
2931
         * understanding the patterns and distributing mpm_ctx across sgh */
2932
114k
        if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_KS ||
2933
114k
                de_ctx->mpm_matcher == MPM_HS) {
2934
114k
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE;
2935
114k
        } else {
2936
0
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2937
0
        }
2938
114k
    } else {
2939
0
        if (strcmp(sgh_mpm_context, "single") == 0) {
2940
0
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE;
2941
0
        } else if (strcmp(sgh_mpm_context, "full") == 0) {
2942
0
            de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2943
0
        } else {
2944
0
            SCLogError("You have supplied an "
2945
0
                       "invalid conf value for detect-engine.sgh-mpm-context-"
2946
0
                       "%s",
2947
0
                    sgh_mpm_context);
2948
0
            exit(EXIT_FAILURE);
2949
0
        }
2950
0
    }
2951
2952
114k
    if (RunmodeIsUnittests()) {
2953
0
        de_ctx->sgh_mpm_ctx_cnf = ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL;
2954
0
    }
2955
2956
    /* parse profile custom-values */
2957
114k
    opt = NULL;
2958
114k
    switch (profile) {
2959
0
        case ENGINE_PROFILE_LOW:
2960
0
            de_ctx->max_uniq_toclient_groups = 15;
2961
0
            de_ctx->max_uniq_toserver_groups = 25;
2962
0
            break;
2963
2964
0
        case ENGINE_PROFILE_HIGH:
2965
0
            de_ctx->max_uniq_toclient_groups = 75;
2966
0
            de_ctx->max_uniq_toserver_groups = 75;
2967
0
            break;
2968
2969
0
        case ENGINE_PROFILE_CUSTOM:
2970
0
            (void)SCConfGet("detect.custom-values.toclient-groups", &max_uniq_toclient_groups_str);
2971
0
            (void)SCConfGet("detect.custom-values.toserver-groups", &max_uniq_toserver_groups_str);
2972
2973
0
            if (de_ctx_custom != NULL) {
2974
0
                TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2975
0
                    if (opt->val && strcmp(opt->val, "custom-values") == 0) {
2976
0
                        if (max_uniq_toclient_groups_str == NULL) {
2977
0
                            max_uniq_toclient_groups_str = (char *)SCConfNodeLookupChildValue(
2978
0
                                    opt->head.tqh_first, "toclient-sp-groups");
2979
0
                        }
2980
0
                        if (max_uniq_toclient_groups_str == NULL) {
2981
0
                            max_uniq_toclient_groups_str = (char *)SCConfNodeLookupChildValue(
2982
0
                                    opt->head.tqh_first, "toclient-groups");
2983
0
                        }
2984
0
                        if (max_uniq_toserver_groups_str == NULL) {
2985
0
                            max_uniq_toserver_groups_str = (char *)SCConfNodeLookupChildValue(
2986
0
                                    opt->head.tqh_first, "toserver-dp-groups");
2987
0
                        }
2988
0
                        if (max_uniq_toserver_groups_str == NULL) {
2989
0
                            max_uniq_toserver_groups_str = (char *)SCConfNodeLookupChildValue(
2990
0
                                    opt->head.tqh_first, "toserver-groups");
2991
0
                        }
2992
0
                    }
2993
0
                }
2994
0
            }
2995
0
            if (max_uniq_toclient_groups_str != NULL) {
2996
0
                if (StringParseUint16(&de_ctx->max_uniq_toclient_groups, 10,
2997
0
                            (uint16_t)strlen(max_uniq_toclient_groups_str),
2998
0
                            (const char *)max_uniq_toclient_groups_str) <= 0) {
2999
0
                    de_ctx->max_uniq_toclient_groups = 20;
3000
3001
0
                    SCLogWarning("parsing '%s' for "
3002
0
                                 "toclient-groups failed, using %u",
3003
0
                            max_uniq_toclient_groups_str, de_ctx->max_uniq_toclient_groups);
3004
0
                }
3005
0
            } else {
3006
0
                de_ctx->max_uniq_toclient_groups = 20;
3007
0
            }
3008
0
            SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups);
3009
3010
0
            if (max_uniq_toserver_groups_str != NULL) {
3011
0
                if (StringParseUint16(&de_ctx->max_uniq_toserver_groups, 10,
3012
0
                            (uint16_t)strlen(max_uniq_toserver_groups_str),
3013
0
                            (const char *)max_uniq_toserver_groups_str) <= 0) {
3014
0
                    de_ctx->max_uniq_toserver_groups = 40;
3015
3016
0
                    SCLogWarning("parsing '%s' for "
3017
0
                                 "toserver-groups failed, using %u",
3018
0
                            max_uniq_toserver_groups_str, de_ctx->max_uniq_toserver_groups);
3019
0
                }
3020
0
            } else {
3021
0
                de_ctx->max_uniq_toserver_groups = 40;
3022
0
            }
3023
0
            SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups);
3024
0
            break;
3025
3026
        /* Default (or no config provided) is profile medium */
3027
114k
        case ENGINE_PROFILE_MEDIUM:
3028
114k
        case ENGINE_PROFILE_UNKNOWN:
3029
114k
        default:
3030
114k
            de_ctx->max_uniq_toclient_groups = 20;
3031
114k
            de_ctx->max_uniq_toserver_groups = 40;
3032
114k
            break;
3033
114k
    }
3034
3035
114k
    intmax_t value = 0;
3036
114k
    de_ctx->inspection_recursion_limit = DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT;
3037
114k
    if (SCConfGetInt("detect.inspection-recursion-limit", &value) == 1) {
3038
112k
        if (value >= 0 && value <= INT_MAX) {
3039
112k
            de_ctx->inspection_recursion_limit = (int)value;
3040
112k
        }
3041
3042
    /* fall back to old config parsing */
3043
112k
    } else {
3044
2.53k
        SCConfNode *insp_recursion_limit_node = NULL;
3045
2.53k
        char *insp_recursion_limit = NULL;
3046
3047
2.53k
        if (de_ctx_custom != NULL) {
3048
0
            opt = NULL;
3049
0
            TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
3050
0
                if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0)
3051
0
                    continue;
3052
3053
0
                insp_recursion_limit_node = SCConfNodeLookupChild(opt, opt->val);
3054
0
                if (insp_recursion_limit_node == NULL) {
3055
0
                    SCLogError("Error retrieving conf "
3056
0
                               "entry for detect-engine:inspection-recursion-limit");
3057
0
                    break;
3058
0
                }
3059
0
                insp_recursion_limit = insp_recursion_limit_node->val;
3060
0
                SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s",
3061
0
                        insp_recursion_limit_node->name, insp_recursion_limit_node->val);
3062
0
                break;
3063
0
            }
3064
3065
0
            if (insp_recursion_limit != NULL) {
3066
0
                if (StringParseInt32(&de_ctx->inspection_recursion_limit, 10,
3067
0
                                     0, (const char *)insp_recursion_limit) < 0) {
3068
0
                    SCLogWarning("Invalid value for "
3069
0
                                 "detect-engine.inspection-recursion-limit: %s "
3070
0
                                 "resetting to %d",
3071
0
                            insp_recursion_limit, DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
3072
0
                    de_ctx->inspection_recursion_limit =
3073
0
                        DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT;
3074
0
                }
3075
0
            }
3076
0
        }
3077
2.53k
    }
3078
3079
114k
    if (de_ctx->inspection_recursion_limit == 0)
3080
112k
        de_ctx->inspection_recursion_limit = -1;
3081
3082
114k
    SCLogDebug("de_ctx->inspection_recursion_limit: %d",
3083
114k
               de_ctx->inspection_recursion_limit);
3084
3085
    // default value is 4
3086
114k
    de_ctx->guess_applayer_log_limit = 4;
3087
114k
    if (SCConfGetInt("detect.stream-tx-log-limit", &value) == 1) {
3088
0
        if (value >= 0 && value <= UINT8_MAX) {
3089
0
            de_ctx->guess_applayer_log_limit = (uint8_t)value;
3090
0
        } else {
3091
0
            SCLogWarning("Invalid value for detect-engine.stream-tx-log-limit: must be between 0 "
3092
0
                         "and 255, will default to 4");
3093
0
        }
3094
0
    }
3095
114k
    int guess_applayer = 0;
3096
114k
    if ((SCConfGetBool("detect.guess-applayer-tx", &guess_applayer)) == 1) {
3097
0
        if (guess_applayer == 1) {
3098
0
            de_ctx->guess_applayer = true;
3099
0
        }
3100
0
    }
3101
3102
    /* parse port grouping priority settings */
3103
3104
114k
    const char *ports = NULL;
3105
114k
    (void)SCConfGet("detect.grouping.tcp-priority-ports", &ports);
3106
114k
    if (ports) {
3107
0
        SCLogConfig("grouping: tcp-priority-ports %s", ports);
3108
114k
    } else {
3109
114k
        (void)SCConfGet("detect.grouping.tcp-whitelist", &ports);
3110
114k
        if (ports) {
3111
0
            SCLogConfig(
3112
0
                    "grouping: tcp-priority-ports from legacy 'tcp-whitelist' setting: %s", ports);
3113
114k
        } else {
3114
114k
            ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080";
3115
114k
            SCLogConfig("grouping: tcp-priority-ports (default) %s", ports);
3116
114k
        }
3117
114k
    }
3118
114k
    if (DetectPortParse(de_ctx, &de_ctx->tcp_priorityports, ports) != 0) {
3119
0
        SCLogWarning("'%s' is not a valid value "
3120
0
                     "for detect.grouping.tcp-priority-ports",
3121
0
                ports);
3122
0
    }
3123
114k
    DetectPort *x = de_ctx->tcp_priorityports;
3124
1.37M
    for ( ; x != NULL;  x = x->next) {
3125
1.26M
        if (x->port != x->port2) {
3126
0
            SCLogWarning("'%s' is not a valid value "
3127
0
                         "for detect.grouping.tcp-priority-ports: only single ports allowed",
3128
0
                    ports);
3129
0
            DetectPortCleanupList(de_ctx, de_ctx->tcp_priorityports);
3130
0
            de_ctx->tcp_priorityports = NULL;
3131
0
            break;
3132
0
        }
3133
1.26M
    }
3134
3135
114k
    ports = NULL;
3136
114k
    (void)SCConfGet("detect.grouping.udp-priority-ports", &ports);
3137
114k
    if (ports) {
3138
0
        SCLogConfig("grouping: udp-priority-ports %s", ports);
3139
114k
    } else {
3140
114k
        (void)SCConfGet("detect.grouping.udp-whitelist", &ports);
3141
114k
        if (ports) {
3142
0
            SCLogConfig(
3143
0
                    "grouping: udp-priority-ports from legacy 'udp-whitelist' setting: %s", ports);
3144
114k
        } else {
3145
114k
            ports = "53, 135, 5060";
3146
114k
            SCLogConfig("grouping: udp-priority-ports (default) %s", ports);
3147
114k
        }
3148
114k
    }
3149
114k
    if (DetectPortParse(de_ctx, &de_ctx->udp_priorityports, ports) != 0) {
3150
0
        SCLogWarning("'%s' is not a valid value "
3151
0
                     "for detect.grouping.udp-priority-ports",
3152
0
                ports);
3153
0
    }
3154
458k
    for (x = de_ctx->udp_priorityports; x != NULL; x = x->next) {
3155
344k
        if (x->port != x->port2) {
3156
0
            SCLogWarning("'%s' is not a valid value "
3157
0
                         "for detect.grouping.udp-priority-ports: only single ports allowed",
3158
0
                    ports);
3159
0
            DetectPortCleanupList(de_ctx, de_ctx->udp_priorityports);
3160
0
            de_ctx->udp_priorityports = NULL;
3161
0
            break;
3162
0
        }
3163
344k
    }
3164
3165
114k
    de_ctx->prefilter_setting = DETECT_PREFILTER_MPM;
3166
114k
    const char *pf_setting = NULL;
3167
114k
    if (SCConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) {
3168
0
        if (strcasecmp(pf_setting, "mpm") == 0) {
3169
0
            de_ctx->prefilter_setting = DETECT_PREFILTER_MPM;
3170
0
        } else if (strcasecmp(pf_setting, "auto") == 0) {
3171
0
            de_ctx->prefilter_setting = DETECT_PREFILTER_AUTO;
3172
0
        }
3173
0
    }
3174
114k
    switch (de_ctx->prefilter_setting) {
3175
114k
        case DETECT_PREFILTER_MPM:
3176
114k
            SCLogConfig("prefilter engines: MPM");
3177
114k
            break;
3178
0
        case DETECT_PREFILTER_AUTO:
3179
0
            SCLogConfig("prefilter engines: MPM and keywords");
3180
0
            break;
3181
114k
    }
3182
3183
114k
    return 0;
3184
114k
}
3185
3186
void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx)
3187
114k
{
3188
114k
    de_ctx->signum = 0;
3189
114k
}
3190
3191
static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
3192
84.8k
{
3193
84.8k
    const DetectEngineMasterCtx *master = &g_master_de_ctx;
3194
3195
84.8k
    if (master->keyword_id > 0) {
3196
        // coverity[suspicious_sizeof : FALSE]
3197
84.8k
        det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *));
3198
84.8k
        if (det_ctx->global_keyword_ctxs_array == NULL) {
3199
0
            SCLogError("setting up thread local detect ctx");
3200
0
            return TM_ECODE_FAILED;
3201
0
        }
3202
84.8k
        det_ctx->global_keyword_ctxs_size = master->keyword_id;
3203
3204
84.8k
        const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3205
2.17M
        while (item) {
3206
2.08M
            det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data);
3207
2.08M
            if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) {
3208
0
                SCLogError("setting up thread local detect ctx "
3209
0
                           "for keyword \"%s\" failed",
3210
0
                        item->name);
3211
0
                return TM_ECODE_FAILED;
3212
0
            }
3213
2.08M
            item = item->next;
3214
2.08M
        }
3215
84.8k
    }
3216
84.8k
    return TM_ECODE_OK;
3217
84.8k
}
3218
3219
static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
3220
84.8k
{
3221
84.8k
    if (det_ctx->global_keyword_ctxs_array == NULL ||
3222
84.8k
        det_ctx->global_keyword_ctxs_size == 0) {
3223
0
        return;
3224
0
    }
3225
3226
84.8k
    const DetectEngineMasterCtx *master = &g_master_de_ctx;
3227
84.8k
    if (master->keyword_id > 0) {
3228
84.8k
        const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3229
2.16M
        while (item) {
3230
2.08M
            if (det_ctx->global_keyword_ctxs_array[item->id] != NULL)
3231
2.08M
                item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]);
3232
3233
2.08M
            item = item->next;
3234
2.08M
        }
3235
84.8k
        det_ctx->global_keyword_ctxs_size = 0;
3236
84.8k
        SCFree(det_ctx->global_keyword_ctxs_array);
3237
84.8k
        det_ctx->global_keyword_ctxs_array = NULL;
3238
84.8k
    }
3239
84.8k
}
3240
3241
static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
3242
84.8k
{
3243
84.8k
    if (de_ctx->keyword_id > 0) {
3244
        // coverity[suspicious_sizeof : FALSE]
3245
9.75k
        det_ctx->keyword_ctxs_array = SCCalloc(de_ctx->keyword_id, sizeof(void *));
3246
9.75k
        if (det_ctx->keyword_ctxs_array == NULL) {
3247
0
            SCLogError("setting up thread local detect ctx");
3248
0
            return TM_ECODE_FAILED;
3249
0
        }
3250
3251
9.75k
        det_ctx->keyword_ctxs_size = de_ctx->keyword_id;
3252
3253
9.75k
        HashListTableBucket *hb = HashListTableGetListHead(de_ctx->keyword_hash);
3254
29.6k
        for (; hb != NULL; hb = HashListTableGetListNext(hb)) {
3255
19.8k
            DetectEngineThreadKeywordCtxItem *item = HashListTableGetListData(hb);
3256
3257
19.8k
            det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data);
3258
19.8k
            if (det_ctx->keyword_ctxs_array[item->id] == NULL) {
3259
0
                SCLogError("setting up thread local detect ctx "
3260
0
                           "for keyword \"%s\" failed",
3261
0
                        item->name);
3262
0
                return TM_ECODE_FAILED;
3263
0
            }
3264
19.8k
        }
3265
9.75k
    }
3266
84.8k
    return TM_ECODE_OK;
3267
84.8k
}
3268
3269
static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
3270
84.8k
{
3271
84.8k
    if (de_ctx->keyword_id > 0) {
3272
9.75k
        HashListTableBucket *hb = HashListTableGetListHead(de_ctx->keyword_hash);
3273
29.6k
        for (; hb != NULL; hb = HashListTableGetListNext(hb)) {
3274
19.8k
            DetectEngineThreadKeywordCtxItem *item = HashListTableGetListData(hb);
3275
3276
19.8k
            if (det_ctx->keyword_ctxs_array[item->id] != NULL)
3277
19.8k
                item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
3278
19.8k
        }
3279
9.75k
        det_ctx->keyword_ctxs_size = 0;
3280
9.75k
        SCFree(det_ctx->keyword_ctxs_array);
3281
9.75k
        det_ctx->keyword_ctxs_array = NULL;
3282
9.75k
    }
3283
84.8k
}
3284
3285
/** NOTE: master MUST be locked before calling this */
3286
static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
3287
0
{
3288
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3289
3290
0
    DetectEngineTenantMapping *map_array = NULL;
3291
0
    uint32_t map_array_size = 0;
3292
0
    uint32_t map_cnt = 0;
3293
0
    uint32_t max_tenant_id = 0;
3294
0
    DetectEngineCtx *list = master->list;
3295
3296
0
    if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
3297
0
        SCLogError("no tenant selector set: "
3298
0
                   "set using multi-detect.selector");
3299
0
        return TM_ECODE_FAILED;
3300
0
    }
3301
3302
0
    uint32_t tcnt = 0;
3303
0
    while (list) {
3304
0
        if (list->tenant_id > max_tenant_id)
3305
0
            max_tenant_id = list->tenant_id;
3306
3307
0
        list = list->next;
3308
0
        tcnt++;
3309
0
    }
3310
3311
0
    HashTable *mt_det_ctxs_hash =
3312
0
            HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
3313
0
    if (mt_det_ctxs_hash == NULL) {
3314
0
        goto error;
3315
0
    }
3316
3317
0
    if (tcnt == 0) {
3318
0
        SCLogInfo("no tenants left, or none registered yet");
3319
0
    } else {
3320
0
        max_tenant_id++;
3321
3322
0
        DetectEngineTenantMapping *map = master->tenant_mapping_list;
3323
0
        while (map) {
3324
0
            map_cnt++;
3325
0
            map = map->next;
3326
0
        }
3327
3328
0
        if (map_cnt > 0) {
3329
0
            map_array_size = map_cnt + 1;
3330
3331
0
            map_array = SCCalloc(map_array_size, sizeof(*map_array));
3332
0
            if (map_array == NULL)
3333
0
                goto error;
3334
3335
            /* fill the array */
3336
0
            map_cnt = 0;
3337
0
            map = master->tenant_mapping_list;
3338
0
            while (map) {
3339
0
                if (map_cnt >= map_array_size) {
3340
0
                    goto error;
3341
0
                }
3342
0
                map_array[map_cnt].traffic_id = map->traffic_id;
3343
0
                map_array[map_cnt].tenant_id = map->tenant_id;
3344
0
                map_cnt++;
3345
0
                map = map->next;
3346
0
            }
3347
3348
0
        }
3349
3350
        /* set up hash for tenant lookup */
3351
0
        list = master->list;
3352
0
        while (list) {
3353
0
            SCLogDebug("tenant-id %u", list->tenant_id);
3354
0
            if (list->tenant_id != 0) {
3355
0
                DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
3356
0
                if (mt_det_ctx == NULL)
3357
0
                    goto error;
3358
0
                if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) {
3359
0
                    goto error;
3360
0
                }
3361
0
            }
3362
0
            list = list->next;
3363
0
        }
3364
0
    }
3365
3366
0
    det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
3367
0
    mt_det_ctxs_hash = NULL;
3368
3369
0
    det_ctx->mt_det_ctxs_cnt = max_tenant_id;
3370
3371
0
    det_ctx->tenant_array = map_array;
3372
0
    det_ctx->tenant_array_size = map_array_size;
3373
3374
0
    switch (master->tenant_selector) {
3375
0
        case TENANT_SELECTOR_UNKNOWN:
3376
0
            SCLogDebug("TENANT_SELECTOR_UNKNOWN");
3377
0
            break;
3378
0
        case TENANT_SELECTOR_VLAN:
3379
0
            det_ctx->TenantGetId = DetectEngineTenantGetIdFromVlanId;
3380
0
            SCLogDebug("TENANT_SELECTOR_VLAN");
3381
0
            break;
3382
0
        case TENANT_SELECTOR_LIVEDEV:
3383
0
            det_ctx->TenantGetId = DetectEngineTenantGetIdFromLivedev;
3384
0
            SCLogDebug("TENANT_SELECTOR_LIVEDEV");
3385
0
            break;
3386
0
        case TENANT_SELECTOR_DIRECT:
3387
0
            det_ctx->TenantGetId = DetectEngineTenantGetIdFromPcap;
3388
0
            SCLogDebug("TENANT_SELECTOR_DIRECT");
3389
0
            break;
3390
0
    }
3391
3392
0
    return TM_ECODE_OK;
3393
0
error:
3394
0
    if (map_array != NULL)
3395
0
        SCFree(map_array);
3396
0
    if (mt_det_ctxs_hash != NULL)
3397
0
        HashTableFree(mt_det_ctxs_hash);
3398
3399
0
    return TM_ECODE_FAILED;
3400
0
}
3401
3402
/** \internal
3403
 *  \brief Helper for DetectThread setup functions
3404
 */
3405
static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
3406
17.5k
{
3407
17.5k
    PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher);
3408
3409
17.5k
    PmqSetup(&det_ctx->pmq);
3410
3411
17.5k
    det_ctx->spm_thread_ctx = SpmMakeThreadCtx(de_ctx->spm_global_thread_ctx);
3412
17.5k
    if (det_ctx->spm_thread_ctx == NULL) {
3413
0
        return TM_ECODE_FAILED;
3414
0
    }
3415
3416
    /* DeState */
3417
17.5k
    if (de_ctx->sig_array_len > 0) {
3418
1.60k
        det_ctx->match_array_len = de_ctx->sig_array_len;
3419
1.60k
        det_ctx->match_array = SCCalloc(det_ctx->match_array_len, sizeof(Signature *));
3420
1.60k
        if (det_ctx->match_array == NULL) {
3421
0
            return TM_ECODE_FAILED;
3422
0
        }
3423
3424
1.60k
        RuleMatchCandidateTxArrayInit(det_ctx, de_ctx->sig_array_len);
3425
1.60k
    }
3426
3427
    /* Alert processing queue */
3428
17.5k
    AlertQueueInit(det_ctx);
3429
3430
    /* byte_extract storage */
3431
17.5k
    det_ctx->byte_values = SCMalloc(sizeof(*det_ctx->byte_values) *
3432
17.5k
                                  (de_ctx->byte_extract_max_local_id + 1));
3433
17.5k
    if (det_ctx->byte_values == NULL) {
3434
0
        return TM_ECODE_FAILED;
3435
0
    }
3436
3437
    /* Allocate space for base64 decoded data. */
3438
17.5k
    if (de_ctx->base64_decode_max_len) {
3439
44
        det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len);
3440
44
        if (det_ctx->base64_decoded == NULL) {
3441
0
            return TM_ECODE_FAILED;
3442
0
        }
3443
44
        det_ctx->base64_decoded_len = 0;
3444
44
    }
3445
3446
17.5k
    det_ctx->inspect.buffers_size = de_ctx->buffer_type_id;
3447
17.5k
    det_ctx->inspect.buffers = SCCalloc(det_ctx->inspect.buffers_size, sizeof(InspectionBuffer));
3448
17.5k
    if (det_ctx->inspect.buffers == NULL) {
3449
0
        return TM_ECODE_FAILED;
3450
0
    }
3451
17.5k
    det_ctx->inspect.to_clear_queue = SCCalloc(det_ctx->inspect.buffers_size, sizeof(uint32_t));
3452
17.5k
    if (det_ctx->inspect.to_clear_queue == NULL) {
3453
0
        return TM_ECODE_FAILED;
3454
0
    }
3455
17.5k
    det_ctx->inspect.to_clear_idx = 0;
3456
3457
17.5k
    det_ctx->multi_inspect.buffers_size = de_ctx->buffer_type_id;
3458
17.5k
    det_ctx->multi_inspect.buffers = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(InspectionBufferMultipleForList));
3459
17.5k
    if (det_ctx->multi_inspect.buffers == NULL) {
3460
0
        return TM_ECODE_FAILED;
3461
0
    }
3462
17.5k
    det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t));
3463
17.5k
    if (det_ctx->multi_inspect.to_clear_queue == NULL) {
3464
0
        return TM_ECODE_FAILED;
3465
0
    }
3466
17.5k
    det_ctx->multi_inspect.to_clear_idx = 0;
3467
3468
3469
17.5k
    DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
3470
17.5k
    DetectEngineThreadCtxInitGlobalKeywords(det_ctx);
3471
#ifdef PROFILE_RULES
3472
    SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx);
3473
#endif
3474
#ifdef PROFILING
3475
    SCProfilingKeywordThreadSetup(de_ctx->profile_keyword_ctx, det_ctx);
3476
    SCProfilingPrefilterThreadSetup(de_ctx->profile_prefilter_ctx, det_ctx);
3477
    SCProfilingSghThreadSetup(de_ctx->profile_sgh_ctx, det_ctx);
3478
#endif
3479
17.5k
    SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect);
3480
3481
17.5k
    if (ThresholdCacheThreadInit(det_ctx) != 0)
3482
0
        return TM_ECODE_FAILED;
3483
17.5k
    return TM_ECODE_OK;
3484
17.5k
}
3485
3486
/** \brief initialize thread specific detection engine context
3487
 *
3488
 *  \note there is a special case when using delayed detect. In this case the
3489
 *        function is called twice per thread. The first time the rules are not
3490
 *        yet loaded. de_ctx->delayed_detect_initialized will be 0. The 2nd
3491
 *        time they will be loaded. de_ctx->delayed_detect_initialized will be 1.
3492
 *        This is needed to do the per thread counter registration before the
3493
 *        packet runtime starts. In delayed detect mode, the first call will
3494
 *        return a NULL ptr through the data ptr.
3495
 *
3496
 *  \param tv ThreadVars for this thread
3497
 *  \param initdata pointer to de_ctx
3498
 *  \param data[out] pointer to store our thread detection ctx
3499
 *
3500
 *  \retval TM_ECODE_OK if all went well
3501
 *  \retval TM_ECODE_FAILED on serious errors
3502
 */
3503
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
3504
2.53k
{
3505
2.53k
    DetectEngineThreadCtx *det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx));
3506
2.53k
    if (unlikely(det_ctx == NULL))
3507
0
        return TM_ECODE_FAILED;
3508
3509
2.53k
    det_ctx->tv = tv;
3510
2.53k
    det_ctx->de_ctx = DetectEngineGetCurrent();
3511
2.53k
    if (det_ctx->de_ctx == NULL) {
3512
#ifdef UNITTESTS
3513
        if (RunmodeIsUnittests()) {
3514
            det_ctx->de_ctx = (DetectEngineCtx *)initdata;
3515
        } else {
3516
            DetectEngineThreadCtxDeinit(tv, det_ctx);
3517
            return TM_ECODE_FAILED;
3518
        }
3519
#else
3520
0
        DetectEngineThreadCtxDeinit(tv, det_ctx);
3521
0
        return TM_ECODE_FAILED;
3522
0
#endif
3523
0
    }
3524
3525
2.53k
    if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3526
0
        det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
3527
2.53k
    {
3528
2.53k
        if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
3529
0
            DetectEngineThreadCtxDeinit(tv, det_ctx);
3530
0
            return TM_ECODE_FAILED;
3531
0
        }
3532
2.53k
    }
3533
3534
    /** alert counter setup */
3535
2.53k
    det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
3536
2.53k
    det_ctx->counter_alerts_overflow = StatsRegisterCounter("detect.alert_queue_overflow", tv);
3537
2.53k
    det_ctx->counter_alerts_suppressed = StatsRegisterCounter("detect.alerts_suppressed", tv);
3538
2.53k
    if (EngineModeIsFirewall()) {
3539
0
        det_ctx->counter_firewall_discarded_alerts =
3540
0
                StatsRegisterCounter("firewall.discarded_alerts", tv);
3541
0
    }
3542
3543
    /* Register counter for Lua rule errors. */
3544
2.53k
    det_ctx->lua_rule_errors = StatsRegisterCounter("detect.lua.errors", tv);
3545
3546
    /* Register a counter for Lua blocked function attempts. */
3547
2.53k
    det_ctx->lua_blocked_function_errors =
3548
2.53k
            StatsRegisterCounter("detect.lua.blocked_function_errors", tv);
3549
3550
    /* Register a counter for Lua instruction limit errors. */
3551
2.53k
    det_ctx->lua_instruction_limit_errors =
3552
2.53k
            StatsRegisterCounter("detect.lua.instruction_limit_errors", tv);
3553
3554
    /* Register a counter for Lua memory limit errors. */
3555
2.53k
    det_ctx->lua_memory_limit_errors = StatsRegisterCounter("detect.lua.memory_limit_errors", tv);
3556
3557
2.53k
    det_ctx->json_content = NULL;
3558
2.53k
    det_ctx->json_content_capacity = 0;
3559
2.53k
    det_ctx->json_content_len = 0;
3560
3561
#ifdef PROFILING
3562
    det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
3563
    det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
3564
#endif
3565
3566
2.53k
    if (DetectEngineMultiTenantEnabled()) {
3567
0
        DetectEngineMasterCtx *master = &g_master_de_ctx;
3568
0
        SCMutexLock(&master->lock);
3569
0
        if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
3570
0
            DetectEngineThreadCtxDeinit(tv, det_ctx);
3571
0
            SCMutexUnlock(&master->lock);
3572
0
            return TM_ECODE_FAILED;
3573
0
        }
3574
0
        SCMutexUnlock(&master->lock);
3575
0
    }
3576
3577
    /* pass thread data back to caller */
3578
2.53k
    *data = (void *)det_ctx;
3579
3580
2.53k
    return TM_ECODE_OK;
3581
2.53k
}
3582
3583
/**
3584
 * \internal
3585
 * \brief initialize a det_ctx for reload cases
3586
 * \param new_de_ctx the new detection engine
3587
 * \param mt flag to indicate if MT should be set up for this det_ctx
3588
 *           this should only be done for the 'root' det_ctx
3589
 *
3590
 * \retval det_ctx detection engine thread ctx or NULL in case of error
3591
 */
3592
DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
3593
        ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
3594
82.2k
{
3595
82.2k
    DetectEngineThreadCtx *det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx));
3596
82.2k
    if (unlikely(det_ctx == NULL))
3597
0
        return NULL;
3598
3599
82.2k
    det_ctx->tenant_id = new_de_ctx->tenant_id;
3600
82.2k
    det_ctx->tv = tv;
3601
82.2k
    det_ctx->de_ctx = DetectEngineReference(new_de_ctx);
3602
82.2k
    if (det_ctx->de_ctx == NULL) {
3603
0
        SCFree(det_ctx);
3604
0
        return NULL;
3605
0
    }
3606
3607
    /* most of the init happens here */
3608
82.2k
    if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3609
0
        det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
3610
82.2k
    {
3611
82.2k
        if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
3612
0
            DetectEngineDeReference(&det_ctx->de_ctx);
3613
0
            SCFree(det_ctx);
3614
0
            return NULL;
3615
0
        }
3616
82.2k
    }
3617
3618
    /** alert counter setup */
3619
82.2k
    det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
3620
82.2k
    det_ctx->counter_alerts_overflow = StatsRegisterCounter("detect.alert_queue_overflow", tv);
3621
82.2k
    det_ctx->counter_alerts_suppressed = StatsRegisterCounter("detect.alerts_suppressed", tv);
3622
82.2k
    if (EngineModeIsFirewall()) {
3623
0
        det_ctx->counter_firewall_discarded_alerts =
3624
0
                StatsRegisterCounter("firewall.discarded_alerts", tv);
3625
0
    }
3626
#ifdef PROFILING
3627
    det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
3628
    det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
3629
#endif
3630
3631
82.2k
    if (mt && DetectEngineMultiTenantEnabledWithLock()) {
3632
0
        if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
3633
0
            DetectEngineDeReference(&det_ctx->de_ctx);
3634
0
            SCFree(det_ctx);
3635
0
            return NULL;
3636
0
        }
3637
0
    }
3638
3639
82.2k
    return det_ctx;
3640
82.2k
}
3641
3642
static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
3643
17.5k
{
3644
#if  DEBUG
3645
    SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt);
3646
3647
    SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size);
3648
    SCLogDebug("STREAM  MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size);
3649
3650
    SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size);
3651
    SCLogDebug("STREAM  SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size);
3652
#endif
3653
3654
17.5k
    if (det_ctx->tenant_array != NULL) {
3655
0
        SCFree(det_ctx->tenant_array);
3656
0
        det_ctx->tenant_array = NULL;
3657
0
    }
3658
3659
#ifdef PROFILE_RULES
3660
    SCProfilingRuleThreadCleanup(det_ctx);
3661
#endif
3662
#ifdef PROFILING
3663
    SCProfilingKeywordThreadCleanup(det_ctx);
3664
    SCProfilingPrefilterThreadCleanup(det_ctx);
3665
    SCProfilingSghThreadCleanup(det_ctx);
3666
#endif
3667
3668
    /** \todo get rid of this static */
3669
17.5k
    if (det_ctx->de_ctx != NULL) {
3670
17.5k
        PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
3671
17.5k
    }
3672
3673
17.5k
    PmqFree(&det_ctx->pmq);
3674
3675
17.5k
    if (det_ctx->spm_thread_ctx != NULL) {
3676
17.5k
        SpmDestroyThreadCtx(det_ctx->spm_thread_ctx);
3677
17.5k
    }
3678
17.5k
    if (det_ctx->match_array != NULL)
3679
1.60k
        SCFree(det_ctx->match_array);
3680
3681
17.5k
    RuleMatchCandidateTxArrayFree(det_ctx);
3682
3683
17.5k
    AlertQueueFree(det_ctx);
3684
3685
17.5k
    if (det_ctx->post_rule_work_queue.q)
3686
0
        SCFree(det_ctx->post_rule_work_queue.q);
3687
3688
17.5k
    if (det_ctx->byte_values != NULL)
3689
17.5k
        SCFree(det_ctx->byte_values);
3690
3691
    /* Decoded base64 data. */
3692
17.5k
    if (det_ctx->base64_decoded != NULL) {
3693
44
        SCFree(det_ctx->base64_decoded);
3694
44
    }
3695
3696
17.5k
    if (det_ctx->inspect.buffers) {
3697
7.30M
        for (uint32_t i = 0; i < det_ctx->inspect.buffers_size; i++) {
3698
7.28M
            InspectionBufferFree(&det_ctx->inspect.buffers[i]);
3699
7.28M
        }
3700
17.5k
        SCFree(det_ctx->inspect.buffers);
3701
17.5k
    }
3702
17.5k
    if (det_ctx->inspect.to_clear_queue) {
3703
17.5k
        SCFree(det_ctx->inspect.to_clear_queue);
3704
17.5k
    }
3705
17.5k
    if (det_ctx->multi_inspect.buffers) {
3706
7.30M
        for (uint32_t i = 0; i < det_ctx->multi_inspect.buffers_size; i++) {
3707
7.28M
            InspectionBufferMultipleForList *fb = &det_ctx->multi_inspect.buffers[i];
3708
7.28M
            for (uint32_t x = 0; x < fb->size; x++) {
3709
2
                InspectionBufferFree(&fb->inspection_buffers[x]);
3710
2
            }
3711
7.28M
            SCFree(fb->inspection_buffers);
3712
7.28M
        }
3713
17.5k
        SCFree(det_ctx->multi_inspect.buffers);
3714
17.5k
    }
3715
17.5k
    if (det_ctx->multi_inspect.to_clear_queue) {
3716
17.5k
        SCFree(det_ctx->multi_inspect.to_clear_queue);
3717
17.5k
    }
3718
3719
17.5k
    DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx);
3720
17.5k
    if (det_ctx->de_ctx != NULL) {
3721
17.5k
        DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
3722
#ifdef UNITTESTS
3723
        if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0)
3724
            DetectEngineDeReference(&det_ctx->de_ctx);
3725
#else
3726
17.5k
        DetectEngineDeReference(&det_ctx->de_ctx);
3727
17.5k
#endif
3728
17.5k
    }
3729
3730
17.5k
    if (det_ctx->json_content) {
3731
0
        SCFree(det_ctx->json_content);
3732
0
        det_ctx->json_content = NULL;
3733
0
        det_ctx->json_content_capacity = 0;
3734
0
    }
3735
3736
17.5k
    AppLayerDecoderEventsFreeEvents(&det_ctx->decoder_events);
3737
17.5k
    PrefilterPktNonPFStatsDump();
3738
17.5k
    SCFree(det_ctx);
3739
17.5k
}
3740
3741
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
3742
84.8k
{
3743
84.8k
    DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
3744
3745
84.8k
    if (det_ctx == NULL) {
3746
0
        SCLogWarning("argument \"data\" NULL");
3747
0
        return TM_ECODE_OK;
3748
0
    }
3749
3750
84.8k
    if (det_ctx->mt_det_ctxs_hash != NULL) {
3751
0
        HashTableFree(det_ctx->mt_det_ctxs_hash);
3752
0
        det_ctx->mt_det_ctxs_hash = NULL;
3753
0
    }
3754
84.8k
    DetectEngineThreadCtxFree(det_ctx);
3755
3756
84.8k
    return TM_ECODE_OK;
3757
84.8k
}
3758
3759
static uint32_t DetectKeywordCtxHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3760
824k
{
3761
824k
    DetectEngineThreadKeywordCtxItem *ctx = data;
3762
824k
    const char *name = ctx->name;
3763
824k
    uint64_t hash =
3764
824k
            StringHashDjb2((const uint8_t *)name, (uint32_t)strlen(name)) + (ptrdiff_t)ctx->data;
3765
824k
    hash %= ht->array_size;
3766
824k
    return (uint32_t)hash;
3767
824k
}
3768
3769
static char DetectKeywordCtxCompareFunc(void *data1, uint16_t len1, void *data2, uint16_t len2)
3770
414k
{
3771
414k
    DetectEngineThreadKeywordCtxItem *ctx1 = data1;
3772
414k
    DetectEngineThreadKeywordCtxItem *ctx2 = data2;
3773
414k
    const char *name1 = ctx1->name;
3774
414k
    const char *name2 = ctx2->name;
3775
414k
    return (strcmp(name1, name2) == 0 && ctx1->data == ctx2->data);
3776
414k
}
3777
3778
static void DetectKeywordCtxFreeFunc(void *ptr)
3779
385k
{
3780
385k
    SCFree(ptr);
3781
385k
}
3782
3783
/** \brief Register Thread keyword context Funcs
3784
 *
3785
 *  \param de_ctx detection engine to register in
3786
 *  \param name keyword name for error printing
3787
 *  \param InitFunc function ptr
3788
 *  \param data keyword init data to pass to Func. Can be NULL.
3789
 *  \param FreeFunc function ptr
3790
 *  \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct)
3791
 *
3792
 *  \retval id for retrieval of ctx at runtime
3793
 *  \retval -1 on error
3794
 *
3795
 *  \note make sure "data" remains valid and it free'd elsewhere. It's
3796
 *        recommended to store it in the keywords global ctx so that
3797
 *        it's freed when the de_ctx is freed.
3798
 */
3799
int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode)
3800
385k
{
3801
385k
    BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL);
3802
3803
385k
    if (de_ctx->keyword_hash == NULL) {
3804
22.8k
        de_ctx->keyword_hash = HashListTableInit(4096, // TODO
3805
22.8k
                DetectKeywordCtxHashFunc, DetectKeywordCtxCompareFunc, DetectKeywordCtxFreeFunc);
3806
22.8k
        BUG_ON(de_ctx->keyword_hash == NULL);
3807
22.8k
    }
3808
3809
385k
    if (mode) {
3810
0
        DetectEngineThreadKeywordCtxItem search = { .data = data, .name = name };
3811
3812
0
        DetectEngineThreadKeywordCtxItem *item =
3813
0
                HashListTableLookup(de_ctx->keyword_hash, (void *)&search, 0);
3814
0
        if (item)
3815
0
            return item->id;
3816
3817
        /* fall through */
3818
0
    }
3819
3820
385k
    DetectEngineThreadKeywordCtxItem *item = SCCalloc(1, sizeof(DetectEngineThreadKeywordCtxItem));
3821
385k
    if (unlikely(item == NULL))
3822
0
        return -1;
3823
3824
385k
    item->InitFunc = InitFunc;
3825
385k
    item->FreeFunc = FreeFunc;
3826
385k
    item->data = data;
3827
385k
    item->name = name;
3828
385k
    item->id = de_ctx->keyword_id++;
3829
3830
385k
    if (HashListTableAdd(de_ctx->keyword_hash, (void *)item, 0) < 0) {
3831
0
        SCFree(item);
3832
0
        return -1;
3833
0
    }
3834
385k
    return item->id;
3835
385k
}
3836
3837
/** \brief Remove Thread keyword context registration
3838
 *
3839
 *  \param de_ctx detection engine to deregister from
3840
 *  \param det_ctx detection engine thread context to deregister from
3841
 *  \param data keyword init data to pass to Func. Can be NULL.
3842
 *  \param name keyword name for error printing
3843
 *
3844
 *  \retval 1 Item unregistered
3845
 *  \retval 0 otherwise
3846
 *
3847
 *  \note make sure "data" remains valid and it free'd elsewhere. It's
3848
 *        recommended to store it in the keywords global ctx so that
3849
 *        it's freed when the de_ctx is freed.
3850
 */
3851
int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *de_ctx, void *data, const char *name)
3852
476k
{
3853
    /* might happen if we call this before a call to *Register* */
3854
476k
    if (de_ctx->keyword_hash == NULL)
3855
38.8k
        return 1;
3856
438k
    DetectEngineThreadKeywordCtxItem remove = { .data = data, .name = name };
3857
438k
    if (HashListTableRemove(de_ctx->keyword_hash, (void *)&remove, 0) == 0)
3858
385k
        return 1;
3859
52.2k
    return 0;
3860
438k
}
3861
/** \brief Retrieve thread local keyword ctx by id
3862
 *
3863
 *  \param det_ctx detection engine thread ctx to retrieve the ctx from
3864
 *  \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3865
 *            keyword init.
3866
 *
3867
 *  \retval ctx or NULL on error
3868
 */
3869
void *DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
3870
254k
{
3871
254k
    if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL)
3872
0
        return NULL;
3873
3874
254k
    return det_ctx->keyword_ctxs_array[id];
3875
254k
}
3876
3877
3878
/** \brief Register Thread keyword context Funcs (Global)
3879
 *
3880
 *  IDs stay static over reloads and between tenants
3881
 *
3882
 *  \param name keyword name for error printing
3883
 *  \param InitFunc function ptr
3884
 *  \param FreeFunc function ptr
3885
 *
3886
 *  \retval id for retrieval of ctx at runtime
3887
 *  \retval -1 on error
3888
 */
3889
int DetectRegisterThreadCtxGlobalFuncs(const char *name,
3890
        void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *))
3891
897
{
3892
897
    int id;
3893
897
    BUG_ON(InitFunc == NULL || FreeFunc == NULL);
3894
3895
897
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3896
3897
    /* if already registered, return existing id */
3898
897
    DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
3899
10.7k
    while (item != NULL) {
3900
9.86k
        if (strcmp(name, item->name) == 0) {
3901
0
            id = item->id;
3902
0
            return id;
3903
0
        }
3904
3905
9.86k
        item = item->next;
3906
9.86k
    }
3907
3908
897
    item = SCCalloc(1, sizeof(*item));
3909
897
    if (unlikely(item == NULL)) {
3910
0
        return -1;
3911
0
    }
3912
897
    item->InitFunc = InitFunc;
3913
897
    item->FreeFunc = FreeFunc;
3914
897
    item->name = name;
3915
897
    item->data = data;
3916
3917
897
    item->next = master->keyword_list;
3918
897
    master->keyword_list = item;
3919
897
    item->id = master->keyword_id++;
3920
3921
897
    id = item->id;
3922
897
    return id;
3923
897
}
3924
3925
/** \brief Retrieve thread local keyword ctx by id
3926
 *
3927
 *  \param det_ctx detection engine thread ctx to retrieve the ctx from
3928
 *  \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3929
 *            keyword init.
3930
 *
3931
 *  \retval ctx or NULL on error
3932
 */
3933
void *DetectThreadCtxGetGlobalKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
3934
0
{
3935
0
    if (id < 0 || id > det_ctx->global_keyword_ctxs_size ||
3936
0
        det_ctx->global_keyword_ctxs_array == NULL) {
3937
0
        return NULL;
3938
0
    }
3939
3940
0
    return det_ctx->global_keyword_ctxs_array[id];
3941
0
}
3942
3943
/** \brief Check if detection is enabled
3944
 *  \retval bool true or false */
3945
int DetectEngineEnabled(void)
3946
4
{
3947
4
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3948
4
    SCMutexLock(&master->lock);
3949
3950
4
    if (master->list == NULL) {
3951
0
        SCMutexUnlock(&master->lock);
3952
0
        return 0;
3953
0
    }
3954
3955
4
    SCMutexUnlock(&master->lock);
3956
4
    return 1;
3957
4
}
3958
3959
uint32_t DetectEngineGetVersion(void)
3960
114k
{
3961
114k
    uint32_t version;
3962
114k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3963
114k
    SCMutexLock(&master->lock);
3964
114k
    version = master->version;
3965
114k
    SCMutexUnlock(&master->lock);
3966
114k
    return version;
3967
114k
}
3968
3969
void DetectEngineBumpVersion(void)
3970
82.2k
{
3971
82.2k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3972
82.2k
    SCMutexLock(&master->lock);
3973
82.2k
    master->version++;
3974
82.2k
    SCLogDebug("master version now %u", master->version);
3975
82.2k
    SCMutexUnlock(&master->lock);
3976
82.2k
}
3977
3978
DetectEngineCtx *DetectEngineGetCurrent(void)
3979
249k
{
3980
249k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
3981
249k
    SCMutexLock(&master->lock);
3982
3983
249k
    DetectEngineCtx *de_ctx = master->list;
3984
249k
    while (de_ctx) {
3985
249k
        if (de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3986
0
            de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB ||
3987
0
            de_ctx->type == DETECT_ENGINE_TYPE_MT_STUB)
3988
249k
        {
3989
249k
            de_ctx->ref_cnt++;
3990
249k
            SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt);
3991
249k
            SCMutexUnlock(&master->lock);
3992
249k
            return de_ctx;
3993
249k
        }
3994
0
        de_ctx = de_ctx->next;
3995
0
    }
3996
3997
0
    SCMutexUnlock(&master->lock);
3998
0
    return NULL;
3999
249k
}
4000
4001
DetectEngineCtx *DetectEngineReference(DetectEngineCtx *de_ctx)
4002
82.2k
{
4003
82.2k
    if (de_ctx == NULL)
4004
0
        return NULL;
4005
82.2k
    de_ctx->ref_cnt++;
4006
82.2k
    return de_ctx;
4007
82.2k
}
4008
4009
static bool DetectEngineMultiTenantEnabledWithLock(void)
4010
183k
{
4011
183k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4012
183k
    return master->multi_tenant_enabled;
4013
183k
}
4014
4015
bool DetectEngineMultiTenantEnabled(void)
4016
101k
{
4017
101k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4018
101k
    SCMutexLock(&master->lock);
4019
101k
    bool enabled = DetectEngineMultiTenantEnabledWithLock();
4020
101k
    SCMutexUnlock(&master->lock);
4021
101k
    return enabled;
4022
101k
}
4023
4024
/** \internal
4025
 *  \brief load a tenant from a yaml file
4026
 *
4027
 *  \param tenant_id the tenant id by which the config is known
4028
 *  \param filename full path of a yaml file
4029
 *  \param loader_id id of loader thread or -1
4030
 *
4031
 *  \retval 0 ok
4032
 *  \retval -1 failed
4033
 */
4034
static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id)
4035
0
{
4036
0
    DetectEngineCtx *de_ctx = NULL;
4037
0
    char prefix[64];
4038
4039
0
    snprintf(prefix, sizeof(prefix), "multi-detect.%u", tenant_id);
4040
4041
0
    SCStat st;
4042
0
    if (SCStatFn(filename, &st) != 0) {
4043
0
        SCLogError("failed to stat file %s", filename);
4044
0
        goto error;
4045
0
    }
4046
4047
0
    de_ctx = DetectEngineGetByTenantId(tenant_id);
4048
0
    if (de_ctx != NULL) {
4049
0
        SCLogError("tenant %u already registered", tenant_id);
4050
0
        DetectEngineDeReference(&de_ctx);
4051
0
        goto error;
4052
0
    }
4053
4054
0
    SCConfNode *node = SCConfGetNode(prefix);
4055
0
    if (node == NULL) {
4056
0
        SCLogError("failed to properly setup yaml %s", filename);
4057
0
        goto error;
4058
0
    }
4059
4060
0
    de_ctx = DetectEngineCtxInitWithPrefix(prefix, tenant_id);
4061
0
    if (de_ctx == NULL) {
4062
0
        SCLogError("initializing detection engine "
4063
0
                   "context failed.");
4064
0
        goto error;
4065
0
    }
4066
0
    SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
4067
4068
0
    de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
4069
0
    de_ctx->tenant_id = tenant_id;
4070
0
    de_ctx->loader_id = loader_id;
4071
0
    de_ctx->tenant_path = SCStrdup(filename);
4072
0
    if (de_ctx->tenant_path == NULL) {
4073
0
        SCLogError("Failed to duplicate path");
4074
0
        goto error;
4075
0
    }
4076
4077
0
    if (SigLoadSignatures(de_ctx, NULL, false) < 0) {
4078
0
        SCLogError("Loading signatures failed.");
4079
0
        goto error;
4080
0
    }
4081
4082
0
    DetectEngineAddToMaster(de_ctx);
4083
4084
0
    return 0;
4085
4086
0
error:
4087
0
    if (de_ctx != NULL) {
4088
0
        DetectEngineCtxFree(de_ctx);
4089
0
    }
4090
0
    return -1;
4091
0
}
4092
4093
static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt)
4094
0
{
4095
0
    DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
4096
0
    if (old_de_ctx == NULL) {
4097
0
        SCLogError("tenant detect engine not found");
4098
0
        return -1;
4099
0
    }
4100
4101
0
    if (filename == NULL)
4102
0
        filename = old_de_ctx->tenant_path;
4103
4104
0
    char prefix[64];
4105
0
    snprintf(prefix, sizeof(prefix), "multi-detect.%u.reload.%d", tenant_id, reload_cnt);
4106
0
    reload_cnt++;
4107
0
    SCLogDebug("prefix %s", prefix);
4108
4109
0
    if (SCConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
4110
0
        SCLogError("failed to load yaml");
4111
0
        goto error;
4112
0
    }
4113
4114
0
    SCConfNode *node = SCConfGetNode(prefix);
4115
0
    if (node == NULL) {
4116
0
        SCLogError("failed to properly setup yaml %s", filename);
4117
0
        goto error;
4118
0
    }
4119
4120
0
    DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix, tenant_id);
4121
0
    if (new_de_ctx == NULL) {
4122
0
        SCLogError("initializing detection engine "
4123
0
                   "context failed.");
4124
0
        goto error;
4125
0
    }
4126
0
    SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix);
4127
4128
0
    new_de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
4129
0
    new_de_ctx->tenant_id = tenant_id;
4130
0
    new_de_ctx->loader_id = old_de_ctx->loader_id;
4131
0
    new_de_ctx->tenant_path = SCStrdup(filename);
4132
0
    if (new_de_ctx->tenant_path == NULL) {
4133
0
        SCLogError("Failed to duplicate path");
4134
0
        goto new_de_ctx_error;
4135
0
    }
4136
4137
0
    if (SigLoadSignatures(new_de_ctx, NULL, false) < 0) {
4138
0
        SCLogError("Loading signatures failed.");
4139
0
        goto new_de_ctx_error;
4140
0
    }
4141
4142
0
    DetectEngineAddToMaster(new_de_ctx);
4143
4144
    /* move to free list */
4145
0
    DetectEngineMoveToFreeList(old_de_ctx);
4146
0
    DetectEngineDeReference(&old_de_ctx);
4147
0
    return 0;
4148
4149
0
new_de_ctx_error:
4150
0
    DetectEngineCtxFree(new_de_ctx);
4151
4152
0
error:
4153
0
    DetectEngineDeReference(&old_de_ctx);
4154
0
    return -1;
4155
0
}
4156
4157
4158
typedef struct TenantLoaderCtx_ {
4159
    uint32_t tenant_id;
4160
    int reload_cnt; /**< used by reload */
4161
    char *yaml;     /**< heap alloc'd copy of file path for the yaml */
4162
} TenantLoaderCtx;
4163
4164
static void DetectLoaderFreeTenant(void *ctx)
4165
0
{
4166
0
    TenantLoaderCtx *t = (TenantLoaderCtx *)ctx;
4167
0
    if (t->yaml != NULL) {
4168
0
        SCFree(t->yaml);
4169
0
    }
4170
0
    SCFree(t);
4171
0
}
4172
4173
static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
4174
0
{
4175
0
    TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
4176
4177
0
    SCLogDebug("loader %d", loader_id);
4178
0
    if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
4179
0
        return -1;
4180
0
    }
4181
0
    return 0;
4182
0
}
4183
4184
static int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml)
4185
0
{
4186
0
    TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
4187
0
    if (t == NULL)
4188
0
        return -ENOMEM;
4189
4190
0
    t->tenant_id = tenant_id;
4191
0
    t->yaml = SCStrdup(yaml);
4192
0
    if (t->yaml == NULL) {
4193
0
        SCFree(t);
4194
0
        return -ENOMEM;
4195
0
    }
4196
4197
0
    return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t, DetectLoaderFreeTenant);
4198
0
}
4199
4200
static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id)
4201
0
{
4202
0
    TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
4203
4204
0
    SCLogDebug("loader_id %d", loader_id);
4205
4206
0
    if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) {
4207
0
        return -1;
4208
0
    }
4209
0
    return 0;
4210
0
}
4211
4212
static int DetectLoaderSetupReloadTenants(const int reload_cnt)
4213
0
{
4214
0
    int ret = 0;
4215
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4216
0
    SCMutexLock(&master->lock);
4217
4218
0
    DetectEngineCtx *de_ctx = master->list;
4219
0
    while (de_ctx) {
4220
0
        if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT) {
4221
0
            TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
4222
0
            if (t == NULL) {
4223
0
                ret = -1;
4224
0
                goto error;
4225
0
            }
4226
0
            t->tenant_id = de_ctx->tenant_id;
4227
0
            t->reload_cnt = reload_cnt;
4228
0
            int loader_id = de_ctx->loader_id;
4229
4230
0
            int r = DetectLoaderQueueTask(
4231
0
                    loader_id, DetectLoaderFuncReloadTenant, t, DetectLoaderFreeTenant);
4232
0
            if (r < 0) {
4233
0
                ret = -2;
4234
0
                goto error;
4235
0
            }
4236
0
        }
4237
4238
0
        de_ctx = de_ctx->next;
4239
0
    }
4240
0
error:
4241
0
    SCMutexUnlock(&master->lock);
4242
0
    return ret;
4243
0
}
4244
4245
static int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt)
4246
0
{
4247
0
    DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
4248
0
    if (old_de_ctx == NULL)
4249
0
        return -ENOENT;
4250
0
    int loader_id = old_de_ctx->loader_id;
4251
0
    DetectEngineDeReference(&old_de_ctx);
4252
4253
0
    TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
4254
0
    if (t == NULL)
4255
0
        return -ENOMEM;
4256
4257
0
    t->tenant_id = tenant_id;
4258
0
    if (yaml != NULL) {
4259
0
        t->yaml = SCStrdup(yaml);
4260
0
        if (t->yaml == NULL) {
4261
0
            SCFree(t);
4262
0
            return -ENOMEM;
4263
0
        }
4264
0
    }
4265
0
    t->reload_cnt = reload_cnt;
4266
4267
0
    SCLogDebug("loader_id %d", loader_id);
4268
4269
0
    return DetectLoaderQueueTask(
4270
0
            loader_id, DetectLoaderFuncReloadTenant, t, DetectLoaderFreeTenant);
4271
0
}
4272
4273
/** \brief Load a tenant and wait for loading to complete
4274
 */
4275
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
4276
0
{
4277
0
    int r = DetectLoaderSetupLoadTenant(tenant_id, yaml);
4278
0
    if (r < 0)
4279
0
        return r;
4280
4281
0
    if (DetectLoadersSync() != 0)
4282
0
        return -1;
4283
4284
0
    return 0;
4285
0
}
4286
4287
/** \brief Reload a tenant and wait for loading to complete
4288
 */
4289
int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
4290
0
{
4291
0
    int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt);
4292
0
    if (r < 0)
4293
0
        return r;
4294
4295
0
    if (DetectLoadersSync() != 0)
4296
0
        return -1;
4297
4298
0
    return 0;
4299
0
}
4300
4301
/** \brief Reload all tenants and wait for loading to complete
4302
 */
4303
int DetectEngineReloadTenantsBlocking(const int reload_cnt)
4304
0
{
4305
0
    int r = DetectLoaderSetupReloadTenants(reload_cnt);
4306
0
    if (r < 0)
4307
0
        return r;
4308
4309
0
    if (DetectLoadersSync() != 0)
4310
0
        return -1;
4311
4312
0
    return 0;
4313
0
}
4314
4315
static int DetectEngineMultiTenantSetupLoadLivedevMappings(
4316
        const SCConfNode *mappings_root_node, bool failure_fatal)
4317
0
{
4318
0
    SCConfNode *mapping_node = NULL;
4319
4320
0
    int mapping_cnt = 0;
4321
0
    if (mappings_root_node != NULL) {
4322
0
        TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
4323
0
            SCConfNode *tenant_id_node = SCConfNodeLookupChild(mapping_node, "tenant-id");
4324
0
            if (tenant_id_node == NULL)
4325
0
                goto bad_mapping;
4326
0
            SCConfNode *device_node = SCConfNodeLookupChild(mapping_node, "device");
4327
0
            if (device_node == NULL)
4328
0
                goto bad_mapping;
4329
4330
0
            uint32_t tenant_id = 0;
4331
0
            if (StringParseUint32(&tenant_id, 10, (uint16_t)strlen(tenant_id_node->val),
4332
0
                        tenant_id_node->val) < 0) {
4333
0
                SCLogError("tenant-id  "
4334
0
                           "of %s is invalid",
4335
0
                        tenant_id_node->val);
4336
0
                goto bad_mapping;
4337
0
            }
4338
4339
0
            const char *dev = device_node->val;
4340
0
            LiveDevice *ld = LiveGetDevice(dev);
4341
0
            if (ld == NULL) {
4342
0
                SCLogWarning("device %s not found", dev);
4343
0
                goto bad_mapping;
4344
0
            }
4345
4346
0
            if (ld->tenant_id_set) {
4347
0
                SCLogWarning("device %s already mapped to tenant-id %u", dev, ld->tenant_id);
4348
0
                goto bad_mapping;
4349
0
            }
4350
4351
0
            ld->tenant_id = tenant_id;
4352
0
            ld->tenant_id_set = true;
4353
4354
0
            if (DetectEngineTenantRegisterLivedev(tenant_id, ld->id) != 0) {
4355
0
                goto error;
4356
0
            }
4357
4358
0
            SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
4359
0
            mapping_cnt++;
4360
0
            continue;
4361
4362
0
        bad_mapping:
4363
0
            if (failure_fatal)
4364
0
                goto error;
4365
0
        }
4366
0
    }
4367
0
    SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
4368
0
    return mapping_cnt;
4369
4370
0
error:
4371
0
    return 0;
4372
0
}
4373
4374
static int DetectEngineMultiTenantSetupLoadVlanMappings(
4375
        const SCConfNode *mappings_root_node, bool failure_fatal)
4376
0
{
4377
0
    SCConfNode *mapping_node = NULL;
4378
4379
0
    int mapping_cnt = 0;
4380
0
    if (mappings_root_node != NULL) {
4381
0
        TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
4382
0
            SCConfNode *tenant_id_node = SCConfNodeLookupChild(mapping_node, "tenant-id");
4383
0
            if (tenant_id_node == NULL)
4384
0
                goto bad_mapping;
4385
0
            SCConfNode *vlan_id_node = SCConfNodeLookupChild(mapping_node, "vlan-id");
4386
0
            if (vlan_id_node == NULL)
4387
0
                goto bad_mapping;
4388
4389
0
            uint32_t tenant_id = 0;
4390
0
            if (StringParseUint32(&tenant_id, 10, (uint16_t)strlen(tenant_id_node->val),
4391
0
                        tenant_id_node->val) < 0) {
4392
0
                SCLogError("tenant-id  "
4393
0
                           "of %s is invalid",
4394
0
                        tenant_id_node->val);
4395
0
                goto bad_mapping;
4396
0
            }
4397
4398
0
            uint16_t vlan_id = 0;
4399
0
            if (StringParseUint16(
4400
0
                        &vlan_id, 10, (uint16_t)strlen(vlan_id_node->val), vlan_id_node->val) < 0) {
4401
0
                SCLogError("vlan-id  "
4402
0
                           "of %s is invalid",
4403
0
                        vlan_id_node->val);
4404
0
                goto bad_mapping;
4405
0
            }
4406
0
            if (vlan_id == 0 || vlan_id >= 4095) {
4407
0
                SCLogError("vlan-id  "
4408
0
                           "of %s is invalid. Valid range 1-4094.",
4409
0
                        vlan_id_node->val);
4410
0
                goto bad_mapping;
4411
0
            }
4412
4413
0
            if (DetectEngineTenantRegisterVlanId(tenant_id, vlan_id) != 0) {
4414
0
                goto error;
4415
0
            }
4416
0
            SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
4417
0
            mapping_cnt++;
4418
0
            continue;
4419
4420
0
        bad_mapping:
4421
0
            if (failure_fatal)
4422
0
                goto error;
4423
0
        }
4424
0
    }
4425
0
    return mapping_cnt;
4426
4427
0
error:
4428
0
    return 0;
4429
0
}
4430
4431
/**
4432
 *  \brief setup multi-detect / multi-tenancy
4433
 *
4434
 *  See if MT is enabled. If so, setup the selector, tenants and mappings.
4435
 *  Tenants and mappings are optional, and can also dynamically be added
4436
 *  and removed from the unix socket.
4437
 */
4438
int DetectEngineMultiTenantSetup(const bool unix_socket)
4439
2
{
4440
2
    enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN;
4441
2
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4442
2
    int failure_fatal = 0;
4443
2
    (void)SCConfGetBool("engine.init-failure-fatal", &failure_fatal);
4444
4445
2
    int enabled = 0;
4446
2
    (void)SCConfGetBool("multi-detect.enabled", &enabled);
4447
2
    if (enabled == 1) {
4448
0
        DetectLoadersInit();
4449
0
        TmModuleDetectLoaderRegister();
4450
0
        DetectLoaderThreadSpawn();
4451
0
        TmThreadContinueDetectLoaderThreads();
4452
4453
0
        SCMutexLock(&master->lock);
4454
0
        master->multi_tenant_enabled = 1;
4455
4456
0
        const char *handler = NULL;
4457
0
        if (SCConfGetNonNull("multi-detect.selector", &handler) == 1) {
4458
0
            SCLogConfig("multi-tenant selector type %s", handler);
4459
4460
0
            if (strcmp(handler, "vlan") == 0) {
4461
0
                tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
4462
4463
0
                int vlanbool = 0;
4464
0
                if ((SCConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
4465
0
                    SCLogError("vlan tracking is disabled, "
4466
0
                               "can't use multi-detect selector 'vlan'");
4467
0
                    SCMutexUnlock(&master->lock);
4468
0
                    goto error;
4469
0
                }
4470
4471
0
            } else if (strcmp(handler, "direct") == 0) {
4472
0
                tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
4473
0
            } else if (strcmp(handler, "device") == 0) {
4474
0
                tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
4475
0
                if (EngineModeIsIPS()) {
4476
0
                    SCLogWarning("multi-tenant 'device' mode not supported for IPS");
4477
0
                    SCMutexUnlock(&master->lock);
4478
0
                    goto error;
4479
0
                }
4480
4481
0
            } else {
4482
0
                SCLogError("unknown value %s "
4483
0
                           "multi-detect.selector",
4484
0
                        handler);
4485
0
                SCMutexUnlock(&master->lock);
4486
0
                goto error;
4487
0
            }
4488
0
        }
4489
0
        SCMutexUnlock(&master->lock);
4490
0
        SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler);
4491
4492
        /* traffic -- tenant mappings */
4493
0
        SCConfNode *mappings_root_node = SCConfGetNode("multi-detect.mappings");
4494
4495
0
        if (tenant_selector == TENANT_SELECTOR_VLAN) {
4496
0
            int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
4497
0
                    failure_fatal);
4498
0
            if (mapping_cnt == 0) {
4499
                /* no mappings are valid when we're in unix socket mode,
4500
                 * they can be added on the fly. Otherwise warn/error
4501
                 * depending on failure_fatal */
4502
4503
0
                if (unix_socket) {
4504
0
                    SCLogNotice("no tenant traffic mappings defined, "
4505
0
                            "tenants won't be used until mappings are added");
4506
0
                } else {
4507
0
                    if (failure_fatal) {
4508
0
                        SCLogError("no multi-detect mappings defined");
4509
0
                        goto error;
4510
0
                    } else {
4511
0
                        SCLogWarning("no multi-detect mappings defined");
4512
0
                    }
4513
0
                }
4514
0
            }
4515
0
        } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
4516
0
            int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
4517
0
                    failure_fatal);
4518
0
            if (mapping_cnt == 0) {
4519
0
                if (failure_fatal) {
4520
0
                    SCLogError("no multi-detect mappings defined");
4521
0
                    goto error;
4522
0
                } else {
4523
0
                    SCLogWarning("no multi-detect mappings defined");
4524
0
                }
4525
0
            }
4526
0
        }
4527
4528
        /* tenants */
4529
0
        SCConfNode *tenants_root_node = SCConfGetNode("multi-detect.tenants");
4530
0
        SCConfNode *tenant_node = NULL;
4531
4532
0
        if (tenants_root_node != NULL) {
4533
0
            const char *path = NULL;
4534
0
            SCConfNode *path_node = SCConfGetNode("multi-detect.config-path");
4535
0
            if (path_node) {
4536
0
                path = path_node->val;
4537
0
                SCLogConfig("tenants config path: %s", path);
4538
0
            }
4539
4540
0
            TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
4541
0
                SCConfNode *id_node = SCConfNodeLookupChild(tenant_node, "id");
4542
0
                if (id_node == NULL) {
4543
0
                    goto bad_tenant;
4544
0
                }
4545
0
                SCConfNode *yaml_node = SCConfNodeLookupChild(tenant_node, "yaml");
4546
0
                if (yaml_node == NULL) {
4547
0
                    goto bad_tenant;
4548
0
                }
4549
4550
0
                uint32_t tenant_id = 0;
4551
0
                if (StringParseUint32(
4552
0
                            &tenant_id, 10, (uint16_t)strlen(id_node->val), id_node->val) < 0) {
4553
0
                    SCLogError("tenant_id  "
4554
0
                               "of %s is invalid",
4555
0
                            id_node->val);
4556
0
                    goto bad_tenant;
4557
0
                }
4558
0
                SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val);
4559
4560
0
                char yaml_path[PATH_MAX] = "";
4561
0
                if (path) {
4562
0
                    PathMerge(yaml_path, PATH_MAX, path, yaml_node->val);
4563
0
                } else {
4564
0
                    strlcpy(yaml_path, yaml_node->val, sizeof(yaml_path));
4565
0
                }
4566
0
                SCLogDebug("tenant path: %s", yaml_path);
4567
4568
                /* setup the yaml in this loop so that it's not done by the loader
4569
                 * threads. SCConfYamlLoadFileWithPrefix is not thread safe. */
4570
0
                char prefix[64];
4571
0
                snprintf(prefix, sizeof(prefix), "multi-detect.%u", tenant_id);
4572
0
                if (SCConfYamlLoadFileWithPrefix(yaml_path, prefix) != 0) {
4573
0
                    SCLogError("failed to load yaml %s", yaml_path);
4574
0
                    goto bad_tenant;
4575
0
                }
4576
4577
0
                int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_path);
4578
0
                if (r < 0) {
4579
                    /* error logged already */
4580
0
                    goto bad_tenant;
4581
0
                }
4582
0
                continue;
4583
4584
0
            bad_tenant:
4585
0
                if (failure_fatal)
4586
0
                    goto error;
4587
0
            }
4588
0
        }
4589
4590
        /* wait for our loaders to complete their tasks */
4591
0
        if (DetectLoadersSync() != 0) {
4592
0
            goto error;
4593
0
        }
4594
4595
0
        VarNameStoreActivate();
4596
4597
2
    } else {
4598
2
        SCLogDebug("multi-detect not enabled (multi tenancy)");
4599
2
    }
4600
2
    return 0;
4601
0
error:
4602
0
    return -1;
4603
2
}
4604
4605
static uint32_t DetectEngineTenantGetIdFromVlanId(const void *ctx, const Packet *p)
4606
0
{
4607
0
    const DetectEngineThreadCtx *det_ctx = ctx;
4608
0
    uint32_t x = 0;
4609
0
    uint32_t vlan_id = 0;
4610
4611
0
    if (p->vlan_idx == 0)
4612
0
        return 0;
4613
4614
0
    vlan_id = p->vlan_id[0];
4615
4616
0
    if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0)
4617
0
        return 0;
4618
4619
    /* not very efficient, but for now we're targeting only limited amounts.
4620
     * Can use hash/tree approach later. */
4621
0
    for (x = 0; x < det_ctx->tenant_array_size; x++) {
4622
0
        if (det_ctx->tenant_array[x].traffic_id == vlan_id)
4623
0
            return det_ctx->tenant_array[x].tenant_id;
4624
0
    }
4625
4626
0
    return 0;
4627
0
}
4628
4629
static uint32_t DetectEngineTenantGetIdFromLivedev(const void *ctx, const Packet *p)
4630
0
{
4631
0
    const DetectEngineThreadCtx *det_ctx = ctx;
4632
0
    const LiveDevice *ld = p->livedev;
4633
4634
0
    if (ld == NULL || det_ctx == NULL)
4635
0
        return 0;
4636
4637
0
    SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
4638
0
    return ld->tenant_id;
4639
0
}
4640
4641
static int DetectEngineTenantRegisterSelector(
4642
        enum DetectEngineTenantSelectors selector, uint32_t tenant_id, uint32_t traffic_id)
4643
0
{
4644
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4645
0
    SCMutexLock(&master->lock);
4646
4647
0
    if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) {
4648
0
        SCLogInfo("conflicting selector already set");
4649
0
        SCMutexUnlock(&master->lock);
4650
0
        return -1;
4651
0
    }
4652
4653
0
    DetectEngineTenantMapping *m = master->tenant_mapping_list;
4654
0
    while (m) {
4655
0
        if (m->traffic_id == traffic_id) {
4656
0
            SCLogInfo("traffic id already registered");
4657
0
            SCMutexUnlock(&master->lock);
4658
0
            return -1;
4659
0
        }
4660
0
        m = m->next;
4661
0
    }
4662
4663
0
    DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map));
4664
0
    if (map == NULL) {
4665
0
        SCLogInfo("memory fail");
4666
0
        SCMutexUnlock(&master->lock);
4667
0
        return -1;
4668
0
    }
4669
0
    map->traffic_id = traffic_id;
4670
0
    map->tenant_id = tenant_id;
4671
4672
0
    map->next = master->tenant_mapping_list;
4673
0
    master->tenant_mapping_list = map;
4674
4675
0
    master->tenant_selector = selector;
4676
4677
0
    SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
4678
0
    SCMutexUnlock(&master->lock);
4679
0
    return 0;
4680
0
}
4681
4682
static int DetectEngineTenantUnregisterSelector(
4683
        enum DetectEngineTenantSelectors selector, uint32_t tenant_id, uint32_t traffic_id)
4684
0
{
4685
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4686
0
    SCMutexLock(&master->lock);
4687
4688
0
    if (master->tenant_mapping_list == NULL) {
4689
0
        SCMutexUnlock(&master->lock);
4690
0
        return -1;
4691
0
    }
4692
4693
0
    DetectEngineTenantMapping *prev = NULL;
4694
0
    DetectEngineTenantMapping *map = master->tenant_mapping_list;
4695
0
    while (map) {
4696
0
        if (map->traffic_id == traffic_id &&
4697
0
            map->tenant_id == tenant_id)
4698
0
        {
4699
0
            if (prev != NULL)
4700
0
                prev->next = map->next;
4701
0
            else
4702
0
                master->tenant_mapping_list = map->next;
4703
4704
0
            map->next = NULL;
4705
0
            SCFree(map);
4706
0
            SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id);
4707
0
            SCMutexUnlock(&master->lock);
4708
0
            return 0;
4709
0
        }
4710
0
        prev = map;
4711
0
        map = map->next;
4712
0
    }
4713
4714
0
    SCMutexUnlock(&master->lock);
4715
0
    return -1;
4716
0
}
4717
4718
int DetectEngineTenantRegisterLivedev(uint32_t tenant_id, int device_id)
4719
0
{
4720
0
    return DetectEngineTenantRegisterSelector(
4721
0
            TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
4722
0
}
4723
4724
int DetectEngineTenantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
4725
0
{
4726
0
    return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
4727
0
}
4728
4729
int DetectEngineTenantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
4730
0
{
4731
0
    return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
4732
0
}
4733
4734
int DetectEngineTenantRegisterPcapFile(uint32_t tenant_id)
4735
0
{
4736
0
    SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
4737
0
    return DetectEngineTenantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
4738
0
}
4739
4740
int DetectEngineTenantUnregisterPcapFile(uint32_t tenant_id)
4741
0
{
4742
0
    SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
4743
0
    return DetectEngineTenantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
4744
0
}
4745
4746
static uint32_t DetectEngineTenantGetIdFromPcap(const void *ctx, const Packet *p)
4747
0
{
4748
0
    return p->pcap_v.tenant_id;
4749
0
}
4750
4751
DetectEngineCtx *DetectEngineGetByTenantId(uint32_t tenant_id)
4752
0
{
4753
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4754
0
    SCMutexLock(&master->lock);
4755
4756
0
    if (master->list == NULL) {
4757
0
        SCMutexUnlock(&master->lock);
4758
0
        return NULL;
4759
0
    }
4760
4761
0
    DetectEngineCtx *de_ctx = master->list;
4762
0
    while (de_ctx) {
4763
0
        if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT &&
4764
0
                de_ctx->tenant_id == tenant_id)
4765
0
        {
4766
0
            de_ctx->ref_cnt++;
4767
0
            break;
4768
0
        }
4769
4770
0
        de_ctx = de_ctx->next;
4771
0
    }
4772
4773
0
    SCMutexUnlock(&master->lock);
4774
0
    return de_ctx;
4775
0
}
4776
4777
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
4778
249k
{
4779
249k
    DEBUG_VALIDATE_BUG_ON((*de_ctx)->ref_cnt == 0);
4780
249k
    (*de_ctx)->ref_cnt--;
4781
249k
    *de_ctx = NULL;
4782
249k
}
4783
4784
static int DetectEngineAddToList(DetectEngineCtx *instance)
4785
82.2k
{
4786
82.2k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4787
4788
82.2k
    if (instance == NULL)
4789
0
        return -1;
4790
4791
82.2k
    if (master->list == NULL) {
4792
6
        master->list = instance;
4793
82.2k
    } else {
4794
82.2k
        instance->next = master->list;
4795
82.2k
        master->list = instance;
4796
82.2k
    }
4797
4798
82.2k
    return 0;
4799
82.2k
}
4800
4801
int DetectEngineAddToMaster(DetectEngineCtx *de_ctx)
4802
82.2k
{
4803
82.2k
    int r;
4804
4805
82.2k
    if (de_ctx == NULL)
4806
0
        return -1;
4807
4808
82.2k
    SCLogDebug("adding de_ctx %p to master", de_ctx);
4809
4810
82.2k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4811
82.2k
    SCMutexLock(&master->lock);
4812
82.2k
    r = DetectEngineAddToList(de_ctx);
4813
82.2k
    SCMutexUnlock(&master->lock);
4814
82.2k
    return r;
4815
82.2k
}
4816
4817
static int DetectEngineMoveToFreeListNoLock(DetectEngineMasterCtx *master, DetectEngineCtx *de_ctx)
4818
82.2k
{
4819
82.2k
    DetectEngineCtx *instance = master->list;
4820
82.2k
    if (instance == NULL) {
4821
0
        return -1;
4822
0
    }
4823
4824
    /* remove from active list */
4825
82.2k
    if (instance == de_ctx) {
4826
0
        master->list = instance->next;
4827
82.2k
    } else {
4828
82.2k
        DetectEngineCtx *prev = instance;
4829
82.2k
        instance = instance->next; /* already checked first element */
4830
4831
82.2k
        while (instance) {
4832
82.2k
            DetectEngineCtx *next = instance->next;
4833
4834
82.2k
            if (instance == de_ctx) {
4835
82.2k
                prev->next = instance->next;
4836
82.2k
                break;
4837
82.2k
            }
4838
4839
0
            prev = instance;
4840
0
            instance = next;
4841
0
        }
4842
82.2k
        if (instance == NULL) {
4843
0
            return -1;
4844
0
        }
4845
82.2k
    }
4846
4847
    /* instance is now detached from list */
4848
82.2k
    instance->next = NULL;
4849
4850
    /* add to free list */
4851
82.2k
    if (master->free_list == NULL) {
4852
4
        master->free_list = instance;
4853
82.2k
    } else {
4854
82.2k
        instance->next = master->free_list;
4855
82.2k
        master->free_list = instance;
4856
82.2k
    }
4857
82.2k
    SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt);
4858
82.2k
    return 0;
4859
82.2k
}
4860
4861
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
4862
82.2k
{
4863
82.2k
    int ret = 0;
4864
82.2k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4865
82.2k
    SCMutexLock(&master->lock);
4866
82.2k
    ret = DetectEngineMoveToFreeListNoLock(master, de_ctx);
4867
82.2k
    SCMutexUnlock(&master->lock);
4868
82.2k
    return ret;
4869
82.2k
}
4870
4871
void DetectEnginePruneFreeList(void)
4872
82.2k
{
4873
82.2k
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4874
82.2k
    SCMutexLock(&master->lock);
4875
4876
82.2k
    DetectEngineCtx *prev = NULL;
4877
82.2k
    DetectEngineCtx *instance = master->free_list;
4878
246k
    while (instance) {
4879
164k
        DetectEngineCtx *next = instance->next;
4880
4881
164k
        SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
4882
4883
164k
        if (instance->ref_cnt == 0) {
4884
82.2k
            if (prev == NULL) {
4885
0
                master->free_list = next;
4886
82.2k
            } else {
4887
82.2k
                prev->next = next;
4888
82.2k
            }
4889
4890
82.2k
            SCLogDebug("freeing detect engine %p", instance);
4891
82.2k
            DetectEngineCtxFree(instance);
4892
82.2k
            instance = NULL;
4893
82.2k
        }
4894
4895
164k
        prev = instance;
4896
164k
        instance = next;
4897
164k
    }
4898
82.2k
    SCMutexUnlock(&master->lock);
4899
82.2k
}
4900
4901
void DetectEngineClearMaster(void)
4902
0
{
4903
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
4904
0
    SCMutexLock(&master->lock);
4905
4906
0
    DetectEngineCtx *instance = master->list;
4907
0
    while (instance) {
4908
0
        DetectEngineCtx *next = instance->next;
4909
0
        DEBUG_VALIDATE_BUG_ON(instance->ref_cnt);
4910
0
        SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
4911
0
        instance->ref_cnt = 0;
4912
0
        DetectEngineMoveToFreeListNoLock(master, instance);
4913
0
        instance = next;
4914
0
    }
4915
0
    SCMutexUnlock(&master->lock);
4916
0
    DetectEnginePruneFreeList();
4917
0
}
4918
4919
static int reloads = 0;
4920
4921
/** \brief Reload the detection engine
4922
 *
4923
 *  \param filename YAML file to load for the detect config
4924
 *
4925
 *  \retval -1 error
4926
 *  \retval 0 ok
4927
 */
4928
int DetectEngineReload(const SCInstance *suri)
4929
82.2k
{
4930
82.2k
    DetectEngineCtx *new_de_ctx = NULL;
4931
82.2k
    DetectEngineCtx *old_de_ctx = NULL;
4932
4933
82.2k
    char prefix[128];
4934
82.2k
    memset(prefix, 0, sizeof(prefix));
4935
4936
82.2k
    SCLogNotice("rule reload starting");
4937
4938
82.2k
    if (suri->conf_filename != NULL) {
4939
0
        snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++);
4940
0
        SCLogConfig("Reloading %s", suri->conf_filename);
4941
0
        if (SCConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) {
4942
0
            SCLogError("failed to load yaml %s", suri->conf_filename);
4943
0
            return -1;
4944
0
        }
4945
4946
0
        SCConfNode *node = SCConfGetNode(prefix);
4947
0
        if (node == NULL) {
4948
0
            SCLogError("failed to properly setup yaml %s", suri->conf_filename);
4949
0
            return -1;
4950
0
        }
4951
4952
0
        if (suri->additional_configs) {
4953
0
            for (int i = 0; suri->additional_configs[i] != NULL; i++) {
4954
0
                SCLogConfig("Reloading %s", suri->additional_configs[i]);
4955
0
                SCConfYamlHandleInclude(node, suri->additional_configs[i]);
4956
0
            }
4957
0
        }
4958
4959
#if 0
4960
        SCConfDump();
4961
#endif
4962
0
    }
4963
4964
    /* get a reference to the current de_ctx */
4965
82.2k
    old_de_ctx = DetectEngineGetCurrent();
4966
82.2k
    if (old_de_ctx == NULL)
4967
0
        return -1;
4968
82.2k
    SCLogDebug("get ref to old_de_ctx %p", old_de_ctx);
4969
82.2k
    DatasetReload();
4970
4971
    /* only reload a regular 'normal' and 'delayed detect stub' detect engines */
4972
82.2k
    if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
4973
0
          old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB))
4974
0
    {
4975
0
        DetectEngineDeReference(&old_de_ctx);
4976
0
        SCLogNotice("rule reload complete");
4977
0
        return -1;
4978
0
    }
4979
4980
    /* get new detection engine */
4981
82.2k
    new_de_ctx = DetectEngineCtxInitWithPrefix(prefix, old_de_ctx->tenant_id);
4982
82.2k
    if (new_de_ctx == NULL) {
4983
0
        SCLogError("initializing detection engine "
4984
0
                   "context failed.");
4985
0
        DetectEngineDeReference(&old_de_ctx);
4986
0
        return -1;
4987
0
    }
4988
82.2k
    if (SigLoadSignatures(new_de_ctx,
4989
82.2k
                          suri->sig_file, suri->sig_file_exclusive) != 0) {
4990
0
        DetectEngineCtxFree(new_de_ctx);
4991
0
        DetectEngineDeReference(&old_de_ctx);
4992
0
        return -1;
4993
0
    }
4994
82.2k
    SCLogDebug("set up new_de_ctx %p", new_de_ctx);
4995
4996
    /* Copy over callbacks. */
4997
82.2k
    new_de_ctx->RateFilterCallback = old_de_ctx->RateFilterCallback;
4998
82.2k
    new_de_ctx->rate_filter_callback_arg = old_de_ctx->rate_filter_callback_arg;
4999
5000
    /* add to master */
5001
82.2k
    DetectEngineAddToMaster(new_de_ctx);
5002
5003
    /* move to old free list */
5004
82.2k
    DetectEngineMoveToFreeList(old_de_ctx);
5005
82.2k
    DetectEngineDeReference(&old_de_ctx);
5006
5007
82.2k
    SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx);
5008
    /* update the threads */
5009
82.2k
    DetectEngineReloadThreads(new_de_ctx);
5010
82.2k
    SCLogDebug("threads now run new_de_ctx %p", new_de_ctx);
5011
5012
    /* walk free list, freeing the old_de_ctx */
5013
82.2k
    DetectEnginePruneFreeList();
5014
5015
82.2k
    DatasetPostReloadCleanup();
5016
5017
82.2k
    DetectEngineBumpVersion();
5018
5019
82.2k
    SCLogDebug("old_de_ctx should have been freed");
5020
5021
82.2k
    DetectEngineMpmCacheService(DETECT_ENGINE_MPM_CACHE_OP_SAVE | DETECT_ENGINE_MPM_CACHE_OP_PRUNE);
5022
5023
82.2k
    SCLogNotice("rule reload complete");
5024
5025
82.2k
#ifdef HAVE_MALLOC_TRIM
5026
    /* The reload process potentially frees up large amounts of memory.
5027
     * Encourage the memory management system to reclaim as much as it
5028
     * can.
5029
     */
5030
82.2k
    malloc_trim(0);
5031
82.2k
#endif
5032
5033
82.2k
    return 0;
5034
82.2k
}
5035
5036
static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len)
5037
0
{
5038
0
    DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
5039
0
    return det_ctx->tenant_id % h->array_size;
5040
0
}
5041
5042
static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len)
5043
0
{
5044
0
    DetectEngineThreadCtx *det1 = (DetectEngineThreadCtx *)d1;
5045
0
    DetectEngineThreadCtx *det2 = (DetectEngineThreadCtx *)d2;
5046
0
    return (det1->tenant_id == det2->tenant_id);
5047
0
}
5048
5049
static void TenantIdFree(void *d)
5050
0
{
5051
0
    DetectEngineThreadCtxFree(d);
5052
0
}
5053
5054
int DetectEngineMTApply(void)
5055
0
{
5056
0
    DetectEngineMasterCtx *master = &g_master_de_ctx;
5057
0
    SCMutexLock(&master->lock);
5058
5059
0
    if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
5060
0
        SCLogInfo("error, no tenant selector");
5061
0
        SCMutexUnlock(&master->lock);
5062
0
        return -1;
5063
0
    }
5064
5065
0
    DetectEngineCtx *stub_de_ctx = NULL;
5066
0
    DetectEngineCtx *list = master->list;
5067
0
    for ( ; list != NULL; list = list->next) {
5068
0
        SCLogDebug("list %p tenant %u", list, list->tenant_id);
5069
5070
0
        if (list->type == DETECT_ENGINE_TYPE_NORMAL ||
5071
0
            list->type == DETECT_ENGINE_TYPE_MT_STUB ||
5072
0
            list->type == DETECT_ENGINE_TYPE_DD_STUB)
5073
0
        {
5074
0
            stub_de_ctx = list;
5075
0
            break;
5076
0
        }
5077
0
    }
5078
0
    if (stub_de_ctx == NULL) {
5079
0
        stub_de_ctx = DetectEngineCtxInitStubForMT();
5080
0
        if (stub_de_ctx == NULL) {
5081
0
            SCMutexUnlock(&master->lock);
5082
0
            return -1;
5083
0
        }
5084
5085
0
        if (master->list == NULL) {
5086
0
            master->list = stub_de_ctx;
5087
0
        } else {
5088
0
            stub_de_ctx->next = master->list;
5089
0
            master->list = stub_de_ctx;
5090
0
        }
5091
0
    }
5092
5093
    /* update the threads */
5094
0
    SCLogDebug("MT reload starting");
5095
0
    DetectEngineReloadThreads(stub_de_ctx);
5096
0
    SCLogDebug("MT reload done");
5097
5098
0
    SCMutexUnlock(&master->lock);
5099
5100
    /* walk free list, freeing the old_de_ctx */
5101
0
    DetectEnginePruneFreeList();
5102
    // needed for VarNameStoreFree
5103
0
    DetectEngineBumpVersion();
5104
5105
0
    SCLogDebug("old_de_ctx should have been freed");
5106
0
    return 0;
5107
0
}
5108
5109
static int g_parse_metadata = 0;
5110
5111
void DetectEngineSetParseMetadata(void)
5112
4
{
5113
4
    g_parse_metadata = 1;
5114
4
}
5115
5116
void DetectEngineUnsetParseMetadata(void)
5117
0
{
5118
0
    g_parse_metadata = 0;
5119
0
}
5120
5121
int DetectEngineMustParseMetadata(void)
5122
159k
{
5123
159k
    return g_parse_metadata;
5124
159k
}
5125
5126
const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
5127
0
{
5128
0
    switch (type) {
5129
0
        case DETECT_SM_LIST_MATCH:
5130
0
            return "packet";
5131
0
        case DETECT_SM_LIST_PMATCH:
5132
0
            return "packet/stream payload";
5133
5134
0
        case DETECT_SM_LIST_TMATCH:
5135
0
            return "tag";
5136
5137
0
        case DETECT_SM_LIST_BASE64_DATA:
5138
0
            return "base64_data";
5139
5140
0
        case DETECT_SM_LIST_POSTMATCH:
5141
0
            return "post-match";
5142
5143
0
        case DETECT_SM_LIST_SUPPRESS:
5144
0
            return "suppress";
5145
0
        case DETECT_SM_LIST_THRESHOLD:
5146
0
            return "threshold";
5147
5148
0
        case DETECT_SM_LIST_MAX:
5149
0
            return "max (internal)";
5150
0
    }
5151
0
    return "error";
5152
0
}
5153
5154
/* events api */
5155
void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
5156
1
{
5157
1
    AppLayerDecoderEventsSetEventRaw(&det_ctx->decoder_events, e);
5158
1
    det_ctx->events++;
5159
1
}
5160
5161
bool DetectMd5ValidateCallback(
5162
        const Signature *s, const char **sigerror, const DetectBufferType *map)
5163
9.00k
{
5164
21.9k
    for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
5165
18.6k
        if (s->init_data->buffers[x].id != (uint32_t)map->id)
5166
3.48k
            continue;
5167
15.2k
        const SigMatch *sm = s->init_data->buffers[x].head;
5168
34.7k
        for (; sm != NULL; sm = sm->next) {
5169
25.2k
            if (sm->type != DETECT_CONTENT)
5170
16.0k
                continue;
5171
5172
9.25k
            const DetectContentData *cd = (DetectContentData *)sm->ctx;
5173
9.25k
            if (cd->flags & DETECT_CONTENT_NOCASE) {
5174
235
                *sigerror = "md5-like keyword should not be used together with "
5175
235
                            "nocase, since the rule is automatically "
5176
235
                            "lowercased anyway which makes nocase redundant.";
5177
235
                SCLogWarning("rule %u: buffer %s: %s", s->id, map->name, *sigerror);
5178
235
            }
5179
5180
9.25k
            if (cd->content_len != SC_MD5_HEX_LEN) {
5181
5.07k
                *sigerror = "Invalid length for md5-like keyword (should "
5182
5.07k
                            "be 32 characters long). This rule will therefore "
5183
5.07k
                            "never match.";
5184
5.07k
                SCLogError("rule %u: buffer %s: %s", s->id, map->name, *sigerror);
5185
5.07k
                return false;
5186
5.07k
            }
5187
5188
118k
            for (size_t i = 0; i < cd->content_len; ++i) {
5189
114k
                if (!isxdigit(cd->content[i])) {
5190
690
                    *sigerror =
5191
690
                            "Invalid md5-like string (should be string of hexadecimal characters)."
5192
690
                            "This rule will therefore never match.";
5193
690
                    SCLogWarning("rule %u: buffer %s: %s", s->id, map->name, *sigerror);
5194
690
                    return false;
5195
690
                }
5196
114k
            }
5197
4.17k
        }
5198
15.2k
    }
5199
3.24k
    return true;
5200
9.00k
}
5201
5202
void SCDetectEngineRegisterRateFilterCallback(SCDetectRateFilterFunc fn, void *arg)
5203
0
{
5204
0
    DetectEngineCtx *de_ctx = DetectEngineGetCurrent();
5205
0
    de_ctx->RateFilterCallback = fn;
5206
0
    de_ctx->rate_filter_callback_arg = arg;
5207
0
    DetectEngineDeReference(&de_ctx);
5208
0
}
5209
5210
int DetectEngineThreadCtxGetJsonContext(DetectEngineThreadCtx *det_ctx)
5211
0
{
5212
0
    if (det_ctx->json_content_len > SIG_JSON_CONTENT_ARRAY_LEN - 1) {
5213
0
        SCLogDebug("json content length %u exceeds maximum %u", det_ctx->json_content_len,
5214
0
                SIG_JSON_CONTENT_ARRAY_LEN);
5215
0
        return -1;
5216
0
    }
5217
0
    if (det_ctx->json_content_len >= det_ctx->json_content_capacity) {
5218
0
        if (det_ctx->json_content_capacity == 0) {
5219
0
            det_ctx->json_content_capacity = 1;
5220
0
        } else {
5221
0
            det_ctx->json_content_capacity *= 2;
5222
0
        }
5223
0
        void *tmp = SCRealloc(
5224
0
                det_ctx->json_content, det_ctx->json_content_capacity * sizeof(SigJsonContent));
5225
0
        if (unlikely(tmp == NULL)) {
5226
0
            return -1;
5227
0
        }
5228
0
        SCLogDebug("reallocated json content array to %u items", det_ctx->json_content_capacity);
5229
0
        det_ctx->json_content = tmp;
5230
0
    }
5231
0
    return 0;
5232
0
}
5233
5234
/*************************************Unittest*********************************/
5235
5236
#ifdef UNITTESTS
5237
5238
static int DetectEngineInitYamlConf(const char *conf)
5239
{
5240
    SCConfCreateContextBackup();
5241
    SCConfInit();
5242
    return SCConfYamlLoadString(conf, strlen(conf));
5243
}
5244
5245
static void DetectEngineDeInitYamlConf(void)
5246
{
5247
    SCConfDeInit();
5248
    SCConfRestoreContextBackup();
5249
}
5250
5251
static int DetectEngineTest01(void)
5252
{
5253
    const char *conf =
5254
        "%YAML 1.1\n"
5255
        "---\n"
5256
        "detect-engine:\n"
5257
        "  - profile: medium\n"
5258
        "  - custom-values:\n"
5259
        "      toclient_src_groups: 2\n"
5260
        "      toclient_dst_groups: 2\n"
5261
        "      toclient_sp_groups: 2\n"
5262
        "      toclient_dp_groups: 3\n"
5263
        "      toserver_src_groups: 2\n"
5264
        "      toserver_dst_groups: 4\n"
5265
        "      toserver_sp_groups: 2\n"
5266
        "      toserver_dp_groups: 25\n"
5267
        "  - inspection-recursion-limit: 0\n";
5268
5269
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5270
5271
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5272
    FAIL_IF_NULL(de_ctx);
5273
5274
    FAIL_IF_NOT(de_ctx->inspection_recursion_limit == -1);
5275
5276
    DetectEngineCtxFree(de_ctx);
5277
5278
    DetectEngineDeInitYamlConf();
5279
5280
    PASS;
5281
}
5282
5283
static int DetectEngineTest02(void)
5284
{
5285
    const char *conf =
5286
        "%YAML 1.1\n"
5287
        "---\n"
5288
        "detect-engine:\n"
5289
        "  - profile: medium\n"
5290
        "  - custom-values:\n"
5291
        "      toclient_src_groups: 2\n"
5292
        "      toclient_dst_groups: 2\n"
5293
        "      toclient_sp_groups: 2\n"
5294
        "      toclient_dp_groups: 3\n"
5295
        "      toserver_src_groups: 2\n"
5296
        "      toserver_dst_groups: 4\n"
5297
        "      toserver_sp_groups: 2\n"
5298
        "      toserver_dp_groups: 25\n"
5299
        "  - inspection-recursion-limit:\n";
5300
5301
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5302
5303
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5304
    FAIL_IF_NULL(de_ctx);
5305
5306
    FAIL_IF_NOT(
5307
            de_ctx->inspection_recursion_limit == DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
5308
5309
    DetectEngineCtxFree(de_ctx);
5310
5311
    DetectEngineDeInitYamlConf();
5312
5313
    PASS;
5314
}
5315
5316
static int DetectEngineTest03(void)
5317
{
5318
    const char *conf =
5319
        "%YAML 1.1\n"
5320
        "---\n"
5321
        "detect-engine:\n"
5322
        "  - profile: medium\n"
5323
        "  - custom-values:\n"
5324
        "      toclient_src_groups: 2\n"
5325
        "      toclient_dst_groups: 2\n"
5326
        "      toclient_sp_groups: 2\n"
5327
        "      toclient_dp_groups: 3\n"
5328
        "      toserver_src_groups: 2\n"
5329
        "      toserver_dst_groups: 4\n"
5330
        "      toserver_sp_groups: 2\n"
5331
        "      toserver_dp_groups: 25\n";
5332
5333
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5334
5335
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5336
    FAIL_IF_NULL(de_ctx);
5337
5338
    FAIL_IF_NOT(
5339
            de_ctx->inspection_recursion_limit == DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT);
5340
5341
    DetectEngineCtxFree(de_ctx);
5342
5343
    DetectEngineDeInitYamlConf();
5344
5345
    PASS;
5346
}
5347
5348
static int DetectEngineTest04(void)
5349
{
5350
    const char *conf =
5351
        "%YAML 1.1\n"
5352
        "---\n"
5353
        "detect-engine:\n"
5354
        "  - profile: medium\n"
5355
        "  - custom-values:\n"
5356
        "      toclient_src_groups: 2\n"
5357
        "      toclient_dst_groups: 2\n"
5358
        "      toclient_sp_groups: 2\n"
5359
        "      toclient_dp_groups: 3\n"
5360
        "      toserver_src_groups: 2\n"
5361
        "      toserver_dst_groups: 4\n"
5362
        "      toserver_sp_groups: 2\n"
5363
        "      toserver_dp_groups: 25\n"
5364
        "  - inspection-recursion-limit: 10\n";
5365
5366
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5367
5368
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5369
    FAIL_IF_NULL(de_ctx);
5370
5371
    FAIL_IF_NOT(de_ctx->inspection_recursion_limit == 10);
5372
5373
    DetectEngineCtxFree(de_ctx);
5374
5375
    DetectEngineDeInitYamlConf();
5376
5377
    PASS;
5378
}
5379
5380
static int DetectEngineTest08(void)
5381
{
5382
    const char *conf =
5383
        "%YAML 1.1\n"
5384
        "---\n"
5385
        "detect-engine:\n"
5386
        "  - profile: custom\n"
5387
        "  - custom-values:\n"
5388
        "      toclient-groups: 23\n"
5389
        "      toserver-groups: 27\n";
5390
5391
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5392
5393
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5394
    FAIL_IF_NULL(de_ctx);
5395
5396
    FAIL_IF_NOT(de_ctx->max_uniq_toclient_groups == 23);
5397
    FAIL_IF_NOT(de_ctx->max_uniq_toserver_groups == 27);
5398
5399
    DetectEngineCtxFree(de_ctx);
5400
5401
    DetectEngineDeInitYamlConf();
5402
5403
    PASS;
5404
}
5405
5406
/** \test bug 892 bad values */
5407
static int DetectEngineTest09(void)
5408
{
5409
    const char *conf =
5410
        "%YAML 1.1\n"
5411
        "---\n"
5412
        "detect-engine:\n"
5413
        "  - profile: custom\n"
5414
        "  - custom-values:\n"
5415
        "      toclient-groups: BA\n"
5416
        "      toserver-groups: BA\n"
5417
        "  - inspection-recursion-limit: 10\n";
5418
5419
    FAIL_IF(DetectEngineInitYamlConf(conf) == -1);
5420
5421
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
5422
    FAIL_IF_NULL(de_ctx);
5423
5424
    FAIL_IF_NOT(de_ctx->max_uniq_toclient_groups == 20);
5425
    FAIL_IF_NOT(de_ctx->max_uniq_toserver_groups == 40);
5426
5427
    DetectEngineCtxFree(de_ctx);
5428
5429
    DetectEngineDeInitYamlConf();
5430
5431
    PASS;
5432
}
5433
5434
#endif
5435
5436
void DetectEngineRegisterTests(void)
5437
0
{
5438
#ifdef UNITTESTS
5439
    UtRegisterTest("DetectEngineTest01", DetectEngineTest01);
5440
    UtRegisterTest("DetectEngineTest02", DetectEngineTest02);
5441
    UtRegisterTest("DetectEngineTest03", DetectEngineTest03);
5442
    UtRegisterTest("DetectEngineTest04", DetectEngineTest04);
5443
    UtRegisterTest("DetectEngineTest08", DetectEngineTest08);
5444
    UtRegisterTest("DetectEngineTest09", DetectEngineTest09);
5445
#endif
5446
0
}