suricata
detect-engine-loader.c
Go to the documentation of this file.
1 /* Copyright (C) 2021-2023 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 "conf.h"
27 #include "detect.h"
28 #include "detect-parse.h"
29 
30 #include "runmodes.h"
31 #include "threads.h"
32 #include "threadvars.h"
33 #include "tm-threads.h"
34 #include "queue.h"
35 
36 #include "detect-engine.h"
37 #include "detect-engine-loader.h"
38 #include "detect-engine-build.h"
39 #include "detect-engine-analyzer.h"
40 #include "detect-engine-mpm.h"
41 #include "detect-engine-sigorder.h"
42 
43 #include "util-detect.h"
44 #include "util-threshold-config.h"
45 #include "util-path.h"
46 
47 #include "rust.h"
48 
49 #ifdef HAVE_GLOB_H
50 #include <glob.h>
51 #endif
52 
53 #include "app-layer-parser.h"
54 
55 extern int rule_reload;
56 extern int engine_analysis;
57 static bool fp_engine_analysis_set = false;
59 
60 static char *DetectLoadCompleteSigPathWithKey(
61  const DetectEngineCtx *de_ctx, const char *default_key, const char *sig_file)
62 {
63  const char *defaultpath = NULL;
64  char *path = NULL;
65  char varname[128];
66 
67  if (sig_file == NULL) {
68  SCLogError("invalid sig_file argument - NULL");
69  return NULL;
70  }
71 
72  /* If we have a configuration prefix, only use it if the primary configuration node
73  * is not marked as final, as that means it was provided on the command line with
74  * a --set. */
75  SCConfNode *default_rule_path = SCConfGetNode(default_key);
76  if ((!default_rule_path || !default_rule_path->final) && strlen(de_ctx->config_prefix) > 0) {
77  snprintf(varname, sizeof(varname), "%s.%s", de_ctx->config_prefix, default_key);
78  default_rule_path = SCConfGetNode(varname);
79  }
80  if (default_rule_path) {
81  defaultpath = default_rule_path->val;
82  }
83 
84  /* Path not specified */
85  if (PathIsRelative(sig_file)) {
86  if (defaultpath) {
87  path = PathMergeAlloc(defaultpath, sig_file);
88  if (unlikely(path == NULL))
89  return NULL;
90  } else {
91  path = SCStrdup(sig_file);
92  if (unlikely(path == NULL))
93  return NULL;
94  }
95  } else {
96  path = SCStrdup(sig_file);
97  if (unlikely(path == NULL))
98  return NULL;
99  }
100  return path;
101 }
102 
103 /**
104  * \brief Create the path if default-rule-path was specified
105  * \param sig_file The name of the file
106  * \retval str Pointer to the string path + sig_file
107  */
108 char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_file)
109 {
110  return DetectLoadCompleteSigPathWithKey(de_ctx, "default-rule-path", sig_file);
111 }
112 
113 /**
114  * \brief Load a file with signatures
115  * \param de_ctx Pointer to the detection engine context
116  * \param sig_file Filename to load signatures from
117  * \param goodsigs_tot Will store number of valid signatures in the file
118  * \param badsigs_tot Will store number of invalid signatures in the file
119  * \retval 0 on success, -1 on error
120  */
121 static int DetectLoadSigFile(DetectEngineCtx *de_ctx, const char *sig_file, int *goodsigs,
122  int *badsigs, int *skippedsigs, const bool firewall_rule)
123 {
124  int good = 0, bad = 0, skipped = 0;
125  char line[DETECT_MAX_RULE_SIZE] = "";
126  size_t offset = 0;
127  int lineno = 0, multiline = 0;
128 
129  (*goodsigs) = 0;
130  (*badsigs) = 0;
131  (*skippedsigs) = 0;
132 
133  FILE *fp = fopen(sig_file, "r");
134  if (fp == NULL) {
135  SCLogError("opening rule file %s:"
136  " %s.",
137  sig_file, strerror(errno));
138  return -1;
139  }
140 
141  while (1) {
142  /* help clang to understand offset can't get > sizeof(line), so the argument to
143  * fgets can't get negative. */
144  BUG_ON(offset >= sizeof(line));
145  char *res = fgets(line + offset, (int)(sizeof(line) - offset), fp);
146  if (res == NULL)
147  break;
148 
149  lineno++;
150  size_t len = strlen(line);
151 
152  /* ignore comments and empty lines */
153  if (line[0] == '\n' || line [0] == '\r' || line[0] == ' ' || line[0] == '#' || line[0] == '\t')
154  continue;
155 
156  /* Check for multiline rules. */
157  while (len > 0 && isspace((unsigned char)line[--len]));
158  if (line[len] == '\\') {
159  multiline++;
160  offset = len;
161  if (offset < sizeof(line) - 1) {
162  /* We have room for more. */
163  continue;
164  }
165  /* No more room in line buffer, continue, rule will fail
166  * to parse. */
167  }
168 
169  /* Check if we have a trailing newline, and remove it */
170  len = strlen(line);
171  if (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
172  line[len - 1] = '\0';
173  }
174 
175  /* Reset offset. */
176  offset = 0;
177 
178  de_ctx->rule_file = sig_file;
179  de_ctx->rule_line = lineno - multiline;
180 
181  Signature *sig = NULL;
182  if (firewall_rule)
183  sig = DetectFirewallRuleAppendNew(de_ctx, line);
184  else
185  sig = DetectEngineAppendSig(de_ctx, line);
186  if (sig != NULL) {
187  if (rule_engine_analysis_set || fp_engine_analysis_set) {
188  if (fp_engine_analysis_set) {
189  EngineAnalysisFP(de_ctx, sig, line);
190  }
192  EngineAnalysisRules(de_ctx, sig, line);
193  }
194  }
195  SCLogDebug("signature %"PRIu32" loaded", sig->id);
196  good++;
197  } else {
198  if (!de_ctx->sigerror_silent) {
199  SCLogError("error parsing signature \"%s\" from "
200  "file %s at line %" PRId32 "",
201  line, sig_file, lineno - multiline);
202 
203  if (!SigStringAppend(&de_ctx->sig_stat, sig_file, line, de_ctx->sigerror, (lineno - multiline))) {
204  SCLogError("Error adding sig \"%s\" from "
205  "file %s at line %" PRId32 "",
206  line, sig_file, lineno - multiline);
207  }
208  if (de_ctx->sigerror) {
209  de_ctx->sigerror = NULL;
210  }
211  }
213  EngineAnalysisRulesFailure(de_ctx, line, sig_file, lineno - multiline);
214  }
215  if (!de_ctx->sigerror_ok) {
216  bad++;
217  }
218  if (de_ctx->sigerror_requires) {
219  SCLogInfo("Skipping signature due to missing requirements: %s from file %s at line "
220  "%" PRId32,
221  line, sig_file, lineno - multiline);
222  skipped++;
223  }
224  }
225  multiline = 0;
226  }
227  fclose(fp);
228 
229  *goodsigs = good;
230  *badsigs = bad;
231  *skippedsigs = skipped;
232  return 0;
233 }
234 
235 /**
236  * \brief Expands wildcards and reads signatures from each matching file
237  * \param de_ctx Pointer to the detection engine context
238  * \param sig_file Filename (or pattern) holding signatures
239  * \retval -1 on error
240  */
241 static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, SigFileLoaderStat *st,
242  int *good_sigs, int *bad_sigs, int *skipped_sigs)
243 {
244  int r = 0;
245 
246  if (pattern == NULL) {
247  SCLogError("opening rule file null");
248  return -1;
249  }
250 
251 #ifdef HAVE_GLOB_H
252  glob_t files;
253  r = glob(pattern, 0, NULL, &files);
254 
255  if (r == GLOB_NOMATCH) {
256  SCLogWarning("No rule files match the pattern %s", pattern);
257  ++(st->bad_files);
258  ++(st->total_files);
259  return -1;
260  } else if (r != 0) {
261  SCLogError("error expanding template %s: %s", pattern, strerror(errno));
262  return -1;
263  }
264 
265  for (size_t i = 0; i < (size_t)files.gl_pathc; i++) {
266  char *fname = files.gl_pathv[i];
267  if (strcmp("/dev/null", fname) == 0)
268  continue;
269 #else
270  char *fname = pattern;
271  if (strcmp("/dev/null", fname) == 0)
272  return 0;
273 #endif
274  if (strlen(de_ctx->config_prefix) > 0) {
275  SCLogConfig("tenant id %d: Loading rule file: %s", de_ctx->tenant_id, fname);
276  } else {
277  SCLogConfig("Loading rule file: %s", fname);
278  }
279  r = DetectLoadSigFile(de_ctx, fname, good_sigs, bad_sigs, skipped_sigs, false);
280  if (r < 0) {
281  ++(st->bad_files);
282  }
283 
284  ++(st->total_files);
285 
286  st->good_sigs_total += *good_sigs;
287  st->bad_sigs_total += *bad_sigs;
288  st->skipped_sigs_total += *skipped_sigs;
289 
290 #ifdef HAVE_GLOB_H
291  }
292  globfree(&files);
293 #endif
294  return r;
295 }
296 
297 static int LoadFirewallRuleFiles(DetectEngineCtx *de_ctx)
298 {
300  SCLogError("initializing firewall policies failed");
301  return -1;
302  }
304  SCLogError("loading firewall policies failed");
305  return -1;
306  }
307 
309  int32_t good_sigs = 0;
310  int32_t bad_sigs = 0;
311  int32_t skipped_sigs = 0;
312 
313  SCLogDebug("fw: rule file full path \"%s\"", de_ctx->firewall_rule_file_exclusive);
314 
315  int ret = DetectLoadSigFile(de_ctx, de_ctx->firewall_rule_file_exclusive, &good_sigs,
316  &bad_sigs, &skipped_sigs, true);
317 
318  /* for now be as strict as possible */
319  if (ret != 0 || bad_sigs != 0 || skipped_sigs != 0) {
320  /* Some rules failed to load, just exit as
321  * errors would have already been logged. */
322  exit(EXIT_FAILURE);
323  }
324 
325  if (good_sigs == 0) {
326  SCLogNotice("fw: No rules loaded from %s.", de_ctx->firewall_rule_file_exclusive);
327  } else {
328  SCLogNotice("fw: %d rules loaded from %s.", good_sigs,
330  de_ctx->sig_stat.good_sigs_total += good_sigs;
331  }
332 
333  return 0;
334  }
335 
336  SCConfNode *default_fw_rule_path = SCConfGetNode("firewall.rule-path");
337  if (default_fw_rule_path == NULL) {
338  SCLogNotice("fw: firewall.rule-path not defined, skip loading firewall rules");
339  return 0;
340  }
341  SCConfNode *rule_files = SCConfGetNode("firewall.rule-files");
342  if (rule_files == NULL) {
343  SCLogNotice("fw: firewall.rule-files not defined, skip loading firewall rules");
344  return 0;
345  }
346 
347  SCConfNode *file = NULL;
348  TAILQ_FOREACH (file, &rule_files->head, next) {
349  int32_t good_sigs = 0;
350  int32_t bad_sigs = 0;
351  int32_t skipped_sigs = 0;
352 
353  char *sfile = DetectLoadCompleteSigPathWithKey(de_ctx, "firewall.rule-path", file->val);
354  SCLogNotice("fw: rule file full path \"%s\"", sfile);
355 
356  int ret = DetectLoadSigFile(de_ctx, sfile, &good_sigs, &bad_sigs, &skipped_sigs, true);
357  SCFree(sfile);
358 
359  /* for now be as strict as possible */
360  if (ret != 0 || bad_sigs != 0 || skipped_sigs != 0) {
361  /* Some rules failed to load, just exit as
362  * errors would have already been logged. */
363  exit(EXIT_FAILURE);
364  }
365 
366  if (good_sigs == 0) {
367  SCLogNotice("fw: No rules loaded from %s.", file->val);
368  } else {
369  SCLogNotice("fw: %d rules loaded from %s.", good_sigs, file->val);
370  de_ctx->sig_stat.good_sigs_total += good_sigs;
371  }
372  }
373  return 0;
374 }
375 
376 /**
377  * \brief Load signatures
378  * \param de_ctx Pointer to the detection engine context
379  * \param sig_file Filename (or pattern) holding signatures
380  * \param sig_file_exclusive File passed in 'sig_file' should be loaded exclusively.
381  * \retval -1 on error
382  */
383 int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, bool sig_file_exclusive)
384 {
385  SCEnter();
386 
387  SCConfNode *rule_files;
388  SCConfNode *file = NULL;
389  SigFileLoaderStat *sig_stat = &de_ctx->sig_stat;
390  int ret = 0;
391  char *sfile = NULL;
392  char varname[128] = "rule-files";
393  int good_sigs = 0;
394  int bad_sigs = 0;
395  int skipped_sigs = 0;
396 
397  if (strlen(de_ctx->config_prefix) > 0) {
398  snprintf(varname, sizeof(varname), "%s.rule-files", de_ctx->config_prefix);
399  }
400 
402  SetupEngineAnalysis(de_ctx, &fp_engine_analysis_set, &rule_engine_analysis_set);
403  }
404 
406  if (LoadFirewallRuleFiles(de_ctx) < 0) {
407  if (de_ctx->fw_policies == NULL || de_ctx->failure_fatal) {
408  exit(EXIT_FAILURE);
409  }
410  ret = -1;
411  goto end;
412  }
413 
414  /* skip regular rules if we used a exclusive firewall rule file */
415  if (!sig_file_exclusive && de_ctx->firewall_rule_file_exclusive) {
416  ret = 0;
417  goto skip_regular_rules;
418  }
419  }
420 
421  /* ok, let's load signature files from the general config */
422  if (!(sig_file != NULL && sig_file_exclusive)) {
423  rule_files = SCConfGetNode(varname);
424  if (rule_files != NULL) {
425  if (!SCConfNodeIsSequence(rule_files)) {
426  SCLogWarning("Invalid rule-files configuration section: "
427  "expected a list of filenames.");
428  } else {
429  TAILQ_FOREACH(file, &rule_files->head, next) {
430  sfile = DetectLoadCompleteSigPath(de_ctx, file->val);
431  good_sigs = bad_sigs = skipped_sigs = 0;
432  ret = ProcessSigFiles(
433  de_ctx, sfile, sig_stat, &good_sigs, &bad_sigs, &skipped_sigs);
434  SCFree(sfile);
435 
436  if (de_ctx->failure_fatal && ret != 0) {
437  /* Some rules failed to load, just exit as
438  * errors would have already been logged. */
439  exit(EXIT_FAILURE);
440  }
441 
442  if (good_sigs == 0) {
443  SCLogConfig("No rules loaded from %s.", file->val);
444  }
445  }
446  }
447  }
448  }
449 
450  /* If a Signature file is specified from command-line, parse it too */
451  if (sig_file != NULL) {
452  ret = ProcessSigFiles(de_ctx, sig_file, sig_stat, &good_sigs, &bad_sigs, &skipped_sigs);
453 
454  if (ret != 0) {
455  if (de_ctx->failure_fatal) {
456  exit(EXIT_FAILURE);
457  }
458  }
459 
460  if (good_sigs == 0) {
461  SCLogConfig("No rules loaded from %s", sig_file);
462  }
463  }
464 
465 skip_regular_rules:
466  /* now we should have signatures to work with */
467  if (sig_stat->good_sigs_total <= 0) {
468  if (sig_stat->total_files > 0) {
469  SCLogWarning(
470  "%d rule files specified, but no rules were loaded!", sig_stat->total_files);
471  } else {
472  SCLogInfo("No signatures supplied.");
473  goto end;
474  }
475  } else {
476  /* we report the total of files and rules successfully loaded and failed */
477  if (strlen(de_ctx->config_prefix) > 0) {
478  SCLogInfo("tenant id %d: %" PRId32 " rule files processed. %" PRId32
479  " rules successfully loaded, %" PRId32 " rules failed, %" PRId32
480  " rules skipped",
481  de_ctx->tenant_id, sig_stat->total_files, sig_stat->good_sigs_total,
482  sig_stat->bad_sigs_total, sig_stat->skipped_sigs_total);
483  } else {
484  SCLogInfo("%" PRId32 " rule files processed. %" PRId32
485  " rules successfully loaded, %" PRId32 " rules failed, %" PRId32
486  " rules skipped",
487  sig_stat->total_files, sig_stat->good_sigs_total, sig_stat->bad_sigs_total,
488  sig_stat->skipped_sigs_total);
489  }
490  if (de_ctx->requirements != NULL && sig_stat->skipped_sigs_total > 0) {
491  SCDetectRequiresStatusLog(de_ctx->requirements, PROG_VER,
492  strlen(de_ctx->config_prefix) > 0 ? de_ctx->tenant_id : 0);
493  }
494  }
495 
496  if ((sig_stat->bad_sigs_total || sig_stat->bad_files) && de_ctx->failure_fatal) {
497  ret = -1;
498  goto end;
499  }
500 
504 
506  ret = -1;
507  goto end;
508  }
509 
510  /* Setup the signature group lookup structure and pattern matchers */
511  if (SigGroupBuild(de_ctx) < 0)
512  goto end;
513 
514  ret = 0;
515 
516  end:
517  gettimeofday(&de_ctx->last_reload, NULL);
520  }
521 
523  SCReturnInt(ret);
524 }
525 
526 #define NLOADERS 4
527 static DetectLoaderControl *loaders = NULL;
528 static int cur_loader = 0;
529 static void TmThreadWakeupDetectLoaderThreads(void);
530 static int num_loaders = NLOADERS;
531 
532 /** \param loader -1 for auto select
533  * \retval loader_id or negative in case of error */
534 int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx, LoaderFreeFunc FreeFunc)
535 {
536  if (loader_id == -1) {
537  loader_id = cur_loader;
538  cur_loader++;
539  if (cur_loader >= num_loaders)
540  cur_loader = 0;
541  }
542  if (loader_id >= num_loaders || loader_id < 0) {
543  return -ERANGE;
544  }
545 
546  DetectLoaderControl *loader = &loaders[loader_id];
547 
548  DetectLoaderTask *t = SCCalloc(1, sizeof(*t));
549  if (t == NULL)
550  return -ENOMEM;
551 
552  t->Func = Func;
553  t->ctx = func_ctx;
554  t->FreeFunc = FreeFunc;
555 
556  SCMutexLock(&loader->m);
557  TAILQ_INSERT_TAIL(&loader->task_list, t, next);
558  SCMutexUnlock(&loader->m);
559 
560  TmThreadWakeupDetectLoaderThreads();
561 
562  SCLogDebug("%d %p %p", loader_id, Func, func_ctx);
563  return loader_id;
564 }
565 
566 /** \brief wait for loader tasks to complete
567  * \retval result 0 for ok, -1 for errors */
569 {
570  SCLogDebug("waiting");
571  int errors = 0;
572  for (int i = 0; i < num_loaders; i++) {
573  bool done = false;
574 
575  DetectLoaderControl *loader = &loaders[i];
576  while (!done) {
577  SCMutexLock(&loader->m);
578  if (TAILQ_EMPTY(&loader->task_list)) {
579  done = true;
580  }
581  SCMutexUnlock(&loader->m);
582  if (!done) {
583  /* nudge thread in case it's sleeping */
584  SCCtrlMutexLock(loader->tv->ctrl_mutex);
585  pthread_cond_broadcast(loader->tv->ctrl_cond);
586  SCCtrlMutexUnlock(loader->tv->ctrl_mutex);
587  }
588  }
589  SCMutexLock(&loader->m);
590  if (loader->result != 0) {
591  errors++;
592  loader->result = 0;
593  }
594  SCMutexUnlock(&loader->m);
595  }
596  if (errors) {
597  SCLogError("%d loaders reported errors", errors);
598  return -1;
599  }
600  SCLogDebug("done");
601  return 0;
602 }
603 
604 static void DetectLoaderInit(DetectLoaderControl *loader)
605 {
606  memset(loader, 0x00, sizeof(*loader));
607  SCMutexInit(&loader->m, NULL);
608  TAILQ_INIT(&loader->task_list);
609 }
610 
612 {
613  intmax_t setting = NLOADERS;
614  (void)SCConfGetInt("multi-detect.loaders", &setting);
615 
616  if (setting < 1 || setting > 1024) {
617  FatalError("invalid multi-detect.loaders setting %" PRIdMAX, setting);
618  }
619 
620  num_loaders = (int32_t)setting;
621  SCLogInfo("using %d detect loader threads", num_loaders);
622 
623  BUG_ON(loaders != NULL);
624  loaders = SCCalloc(num_loaders, sizeof(DetectLoaderControl));
625  BUG_ON(loaders == NULL);
626 
627  for (int i = 0; i < num_loaders; i++) {
628  DetectLoaderInit(&loaders[i]);
629  }
630 }
631 
632 /**
633  * \brief Unpauses all threads present in tv_root
634  */
635 static void TmThreadWakeupDetectLoaderThreads(void)
636 {
638  for (int i = 0; i < TVT_MAX; i++) {
639  ThreadVars *tv = tv_root[i];
640  while (tv != NULL) {
641  if (strncmp(tv->name,"DL#",3) == 0) {
642  BUG_ON(tv->ctrl_cond == NULL);
644  pthread_cond_broadcast(tv->ctrl_cond);
646  }
647  tv = tv->next;
648  }
649  }
651 }
652 
653 /**
654  * \brief Unpauses all threads present in tv_root
655  */
657 {
659  for (int i = 0; i < TVT_MAX; i++) {
660  ThreadVars *tv = tv_root[i];
661  while (tv != NULL) {
662  if (strncmp(tv->name,"DL#",3) == 0)
664 
665  tv = tv->next;
666  }
667  }
669 }
670 
671 SC_ATOMIC_DECLARE(int, detect_loader_cnt);
672 
673 typedef struct DetectLoaderThreadData_ {
674  uint32_t instance;
676 
677 static TmEcode DetectLoaderThreadInit(ThreadVars *t, const void *initdata, void **data)
678 {
680  if (ftd == NULL)
681  return TM_ECODE_FAILED;
682 
683  ftd->instance = SC_ATOMIC_ADD(detect_loader_cnt, 1); /* id's start at 0 */
684  SCLogDebug("detect loader instance %u", ftd->instance);
685 
686  /* pass thread data back to caller */
687  *data = ftd;
688 
689  DetectLoaderControl *loader = &loaders[ftd->instance];
690  loader->tv = t;
691 
692  return TM_ECODE_OK;
693 }
694 
695 static TmEcode DetectLoaderThreadDeinit(ThreadVars *t, void *data)
696 {
697  SCFree(data);
698  return TM_ECODE_OK;
699 }
700 
701 
702 static TmEcode DetectLoader(ThreadVars *th_v, void *thread_data)
703 {
704  DetectLoaderThreadData *ftd = (DetectLoaderThreadData *)thread_data;
705  BUG_ON(ftd == NULL);
706 
708  SCLogDebug("loader thread started");
709  bool run = TmThreadsWaitForUnpause(th_v);
710  while (run) {
711  /* see if we have tasks */
712 
713  DetectLoaderControl *loader = &loaders[ftd->instance];
714  SCMutexLock(&loader->m);
715 
716  DetectLoaderTask *task = NULL, *tmptask = NULL;
717  TAILQ_FOREACH_SAFE(task, &loader->task_list, next, tmptask) {
718  int r = task->Func(task->ctx, ftd->instance);
719  loader->result |= r;
720  TAILQ_REMOVE(&loader->task_list, task, next);
721  task->FreeFunc(task->ctx);
722  SCFree(task);
723  }
724 
725  SCMutexUnlock(&loader->m);
726 
727  /* just wait until someone wakes us up */
729  int rc = 0;
730  while (rc == 0) {
731  if (TmThreadsCheckFlag(th_v, THV_KILL)) {
732  run = false;
733  break;
734  }
735  SCMutexLock(&loader->m);
736  bool has_work = loader->task_list.tqh_first != NULL;
737  SCMutexUnlock(&loader->m);
738  if (has_work)
739  break;
740 
741  rc = SCCtrlCondWait(th_v->ctrl_cond, th_v->ctrl_mutex);
742  }
744 
745  SCLogDebug("woke up...");
746  }
747 
751 
752  return TM_ECODE_OK;
753 }
754 
755 /** \brief spawn the detect loader manager thread */
757 {
758  for (int i = 0; i < num_loaders; i++) {
759  char name[TM_THREAD_NAME_MAX];
760  snprintf(name, sizeof(name), "%s#%02d", thread_name_detect_loader, i+1);
761 
762  ThreadVars *tv_loader = TmThreadCreateCmdThreadByName(name, "DetectLoader", 1);
763  if (tv_loader == NULL) {
764  FatalError("failed to create thread %s", name);
765  }
766  if (TmThreadSpawn(tv_loader) != TM_ECODE_OK) {
767  FatalError("failed to create spawn %s", name);
768  }
769  }
770 }
771 
773 {
774  tmm_modules[TMM_DETECTLOADER].name = "DetectLoader";
775  tmm_modules[TMM_DETECTLOADER].ThreadInit = DetectLoaderThreadInit;
776  tmm_modules[TMM_DETECTLOADER].ThreadDeinit = DetectLoaderThreadDeinit;
777  tmm_modules[TMM_DETECTLOADER].Management = DetectLoader;
780  SCLogDebug("%s registered", tmm_modules[TMM_DETECTLOADER].name);
781 
782  SC_ATOMIC_INIT(detect_loader_cnt);
783 }
DetectLoaderTask_::FreeFunc
LoaderFreeFunc FreeFunc
Definition: detect-engine-loader.h:40
TmModule_::cap_flags
uint8_t cap_flags
Definition: tm-modules.h:77
DetectLoaderControl_
Definition: detect-engine-loader.h:44
SigFileLoaderStat_::bad_files
int bad_files
Definition: detect.h:883
RUNMODE_ENGINE_ANALYSIS
@ RUNMODE_ENGINE_ANALYSIS
Definition: runmodes.h:58
tm-threads.h
SCCtrlCondWait
#define SCCtrlCondWait
Definition: threads-debug.h:387
len
uint8_t len
Definition: app-layer-dnp3.h:2
TmThreadSpawn
TmEcode TmThreadSpawn(ThreadVars *tv)
Spawns a thread associated with the ThreadVars instance tv.
Definition: tm-threads.c:1706
detect-engine.h
DetectLoaderThreadSpawn
void DetectLoaderThreadSpawn(void)
spawn the detect loader manager thread
Definition: detect-engine-loader.c:756
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
ThreadVars_::name
char name[16]
Definition: threadvars.h:65
PathMergeAlloc
char * PathMergeAlloc(const char *const dir, const char *const fname)
Definition: util-path.c:107
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:262
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
SigLoadSignatures
int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, bool sig_file_exclusive)
Load signatures.
Definition: detect-engine-loader.c:383
DetectEngineCtx_::firewall_rule_file_exclusive
const char * firewall_rule_file_exclusive
Definition: detect.h:1184
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SetupEngineAnalysis
void SetupEngineAnalysis(DetectEngineCtx *de_ctx, bool *fp_analysis, bool *rule_analysis)
Definition: detect-engine-analyzer.c:477
DetectLoaderTask_::ctx
void * ctx
Definition: detect-engine-loader.h:39
DetectEngineCtx_::sigerror_silent
bool sigerror_silent
Definition: detect.h:1066
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
TmThreadsSetFlag
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition: tm-threads.c:103
TmThreadWaitForFlag
void TmThreadWaitForFlag(ThreadVars *tv, uint32_t flags)
Waits till the specified flag(s) is(are) set. We don't bother if the kill flag has been set or not on...
Definition: tm-threads.c:1824
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(int, detect_loader_cnt)
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
name
const char * name
Definition: detect-engine-proto.c:48
THV_DEINIT
#define THV_DEINIT
Definition: threadvars.h:45
threads.h
TmThreadContinueDetectLoaderThreads
void TmThreadContinueDetectLoaderThreads(void)
Unpauses all threads present in tv_root.
Definition: detect-engine-loader.c:656
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:966
THV_RUNNING
#define THV_RUNNING
Definition: threadvars.h:55
TAILQ_EMPTY
#define TAILQ_EMPTY(head)
Definition: queue.h:248
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
LoaderFreeFunc
void(* LoaderFreeFunc)(void *ctx)
Definition: detect-engine-loader.h:35
SCSigSignatureOrderingModuleCleanup
void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *de_ctx)
De-registers all the signature ordering functions registered.
Definition: detect-engine-sigorder.c:939
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
rust.h
tv_root
ThreadVars * tv_root[TVT_MAX]
Definition: tm-threads.c:84
LoaderFunc
int(* LoaderFunc)(void *ctx, int loader_id)
Definition: detect-engine-loader.h:34
DetectEngineCtx_::sigerror_requires
bool sigerror_requires
Definition: detect.h:1070
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
DetectFirewallInitDefaultPolicies
int DetectFirewallInitDefaultPolicies(DetectEngineCtx *de_ctx)
allocate and initialize to default values the policies table
Definition: detect-parse.c:3818
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3290
DetectEngineCtx_::sigerror_ok
bool sigerror_ok
Definition: detect.h:1067
DetectLoaderControl_::result
int result
Definition: detect-engine-loader.h:51
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3540
EngineModeIsFirewall
bool EngineModeIsFirewall(void)
Definition: suricata.c:239
SCThresholdConfInitContext
int SCThresholdConfInitContext(DetectEngineCtx *de_ctx)
Inits the context to be used by the Threshold Config parsing API.
Definition: util-threshold-config.c:169
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
EngineAnalysisRulesFailure
void EngineAnalysisRulesFailure(const DetectEngineCtx *de_ctx, const char *line, const char *file, int lineno)
Definition: detect-engine-analyzer.c:625
TM_THREAD_NAME_MAX
#define TM_THREAD_NAME_MAX
Definition: tm-threads.h:49
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
SCConfNodeIsSequence
int SCConfNodeIsSequence(const SCConfNode *node)
Check if a node is a sequence or node.
Definition: conf.c:973
TmModule_::ThreadDeinit
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:53
THV_RUNNING_DONE
#define THV_RUNNING_DONE
Definition: threadvars.h:46
SigFileLoaderStat_::skipped_sigs_total
int skipped_sigs_total
Definition: detect.h:887
NLOADERS
#define NLOADERS
Definition: detect-engine-loader.c:526
TmThreadContinue
void TmThreadContinue(ThreadVars *tv)
Unpauses a thread.
Definition: tm-threads.c:1836
DetectEngineCtx_::requirements
SCDetectRequiresStatus * requirements
Definition: detect.h:1175
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:312
SCRunmodeGet
SCRunMode SCRunmodeGet(void)
Get the current run mode.
Definition: suricata.c:301
rule_engine_analysis_set
bool rule_engine_analysis_set
Definition: detect-engine-loader.c:58
SigStringAppend
int SigStringAppend(SigFileLoaderStat *sig_stats, const char *sig_file, const char *sig_str, const char *sig_error, int line)
Append a new list member to SigString list.
Definition: util-detect.c:104
DetectEngineCtx_::fw_policies
struct DetectFirewallPolicies * fw_policies
Definition: detect.h:996
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectLoadersInit
void DetectLoadersInit(void)
Definition: detect-engine-loader.c:611
SCSigOrderSignatures
void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
Orders the signatures.
Definition: detect-engine-sigorder.c:804
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
SCConfGetInt
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:415
DetectEngineCtx_::last_reload
struct timeval last_reload
Definition: detect.h:1139
DetectEngineCtx_::failure_fatal
bool failure_fatal
Definition: detect.h:967
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
detect-engine-mpm.h
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
TmModule_::Management
TmEcode(* Management)(ThreadVars *, void *)
Definition: tm-modules.h:69
THV_KILL
#define THV_KILL
Definition: threadvars.h:40
SCSigRegisterSignatureOrderingFuncs
void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx)
Lets you register the Signature ordering functions. The order in which the functions are registered s...
Definition: detect-engine-sigorder.c:919
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:262
EngineAnalysisRules
void EngineAnalysisRules(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
Prints analysis of loaded rules.
Definition: detect-engine-analyzer.c:1699
rule_reload
int rule_reload
engine_analysis
int engine_analysis
app-layer-parser.h
ThreadVars_::next
struct ThreadVars_ * next
Definition: threadvars.h:124
DetectLoaderThreadData_::instance
uint32_t instance
Definition: detect-engine-loader.c:674
SigFileLoaderStat_::bad_sigs_total
int bad_sigs_total
Definition: detect.h:886
util-detect.h
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
tv_root_lock
SCMutex tv_root_lock
Definition: tm-threads.c:87
thread_name_detect_loader
const char * thread_name_detect_loader
Definition: runmodes.c:74
TmModuleDetectLoaderRegister
void TmModuleDetectLoaderRegister(void)
Definition: detect-engine-loader.c:772
SCCtrlMutexLock
#define SCCtrlMutexLock(mut)
Definition: threads-debug.h:377
detect-engine-build.h
tmm_modules
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.c:29
DetectLoaderThreadData
struct DetectLoaderThreadData_ DetectLoaderThreadData
ThreadVars_::ctrl_cond
SCCtrlCondT * ctrl_cond
Definition: threadvars.h:129
conf.h
DETECT_MAX_RULE_SIZE
#define DETECT_MAX_RULE_SIZE
Definition: detect.h:46
TmEcode
TmEcode
Definition: tm-threads-common.h:80
DetectLoaderThreadData_
Definition: detect-engine-loader.c:673
queue.h
TmModule_::name
const char * name
Definition: tm-modules.h:48
runmodes.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
TAILQ_FOREACH_SAFE
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:329
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
DetectLoaderQueueTask
int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx, LoaderFreeFunc FreeFunc)
Definition: detect-engine-loader.c:534
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2274
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:1091
detect-engine-analyzer.h
DetectLoaderTask_
Definition: detect-engine-loader.h:37
THV_INIT_DONE
#define THV_INIT_DONE
Definition: threadvars.h:37
SCCtrlMutexUnlock
#define SCCtrlMutexUnlock(mut)
Definition: threads-debug.h:379
DetectEngineCtx_::sig_stat
SigFileLoaderStat sig_stat
Definition: detect.h:1142
DetectEngineCtx_::rule_file
const char * rule_file
Definition: detect.h:1064
DetectFirewallLoadDefaultPolicies
int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx)
Definition: detect-parse.c:3853
suricata-common.h
TMM_DETECTLOADER
@ TMM_DETECTLOADER
Definition: tm-threads-common.h:72
util-path.h
TmThreadsWaitForUnpause
bool TmThreadsWaitForUnpause(ThreadVars *tv)
Wait for a thread to become unpaused.
Definition: tm-threads.c:365
CleanupEngineAnalysis
void CleanupEngineAnalysis(DetectEngineCtx *de_ctx)
Definition: detect-engine-analyzer.c:513
DetectLoaderControl_::m
SCMutex m
Definition: detect-engine-loader.h:50
SigFileLoaderStat_::total_files
int total_files
Definition: detect.h:884
TmModule_::ThreadInit
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:51
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(...)
Definition: util-debug.h:517
TmThreadCreateCmdThreadByName
ThreadVars * TmThreadCreateCmdThreadByName(const char *name, const char *module, int mucond)
Creates and returns the TV instance for a Command thread (CMD). This function supports only custom sl...
Definition: tm-threads.c:1160
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:33
threadvars.h
detect-engine-sigorder.h
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
EngineAnalysisFP
void EngineAnalysisFP(const DetectEngineCtx *de_ctx, const Signature *s, const char *line)
Definition: detect-engine-analyzer.c:172
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:182
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SigFileLoaderStat_::good_sigs_total
int good_sigs_total
Definition: detect.h:885
Signature_::id
uint32_t id
Definition: detect.h:717
PathIsRelative
int PathIsRelative(const char *path)
Check if a path is relative.
Definition: util-path.c:69
detect-parse.h
Signature_
Signature container.
Definition: detect.h:672
SCConfNode_::final
int final
Definition: conf.h:44
DetectLoadersSync
int DetectLoadersSync(void)
wait for loader tasks to complete
Definition: detect-engine-loader.c:568
suricata.h
DetectLoaderTask_::Func
LoaderFunc Func
Definition: detect-engine-loader.h:38
DetectLoadCompleteSigPath
char * DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, const char *sig_file)
Create the path if default-rule-path was specified.
Definition: detect-engine-loader.c:108
DetectEngineCtx_::sigerror
const char * sigerror
Definition: detect.h:1065
ThreadVars_::ctrl_mutex
SCCtrlMutex * ctrl_mutex
Definition: threadvars.h:128
DetectEngineCtx_::rule_line
int rule_line
Definition: detect.h:1063
PROG_VER
#define PROG_VER
Definition: suricata.h:76
TmThreadsCheckFlag
int TmThreadsCheckFlag(ThreadVars *tv, uint32_t flag)
Check if a thread flag is set.
Definition: tm-threads.c:95
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:250
THV_CLOSED
#define THV_CLOSED
Definition: threadvars.h:42
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCConfNode_
Definition: conf.h:37
DetectEngineCtx_::tenant_id
uint32_t tenant_id
Definition: detect.h:973
detect-engine-loader.h
SigFileLoaderStat_
Signature loader statistics.
Definition: detect.h:881
SCConfNode_::val
char * val
Definition: conf.h:39
TVT_MAX
@ TVT_MAX
Definition: tm-threads-common.h:91
TmModule_::flags
uint8_t flags
Definition: tm-modules.h:80
DetectFirewallRuleAppendNew
Signature * DetectFirewallRuleAppendNew(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3468
DetectLoaderControl_::tv
ThreadVars * tv
Definition: detect-engine-loader.h:46
util-threshold-config.h
TM_FLAG_MANAGEMENT_TM
#define TM_FLAG_MANAGEMENT_TM
Definition: tm-modules.h:36