From 4bbe7d92dc858f77484ad9d41327422ff84af655 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 26 Apr 2024 16:31:47 +0200 Subject: [PATCH] detect: helper to have pure rust keywords detect: make number of keywords dynamic Ticket: 4683 --- configure.ac | 11 ++++ examples/lib/simple/Makefile.am | 2 +- rust/cbindgen.toml | 1 + rust/src/detect/mod.rs | 61 ++++++++++++++++++ src/Makefile.am | 12 +++- src/detect-engine-helper.c | 107 ++++++++++++++++++++++++++++++++ src/detect-engine-helper.h | 41 ++++++++++++ src/detect-engine-register.c | 26 +++++++- src/detect-engine-register.h | 7 ++- src/detect-engine.c | 10 +++ src/detect-parse.c | 6 +- src/detect-parse.h | 2 +- src/detect.h | 6 +- src/suricata.c | 1 + 14 files changed, 279 insertions(+), 14 deletions(-) create mode 100644 src/detect-engine-helper.c create mode 100644 src/detect-engine-helper.h diff --git a/configure.ac b/configure.ac index 19bb8ffc2092..7a8be3b6faea 100644 --- a/configure.ac +++ b/configure.ac @@ -318,6 +318,17 @@ CFLAGS="$CFLAGS -std=gnu99" fi + # check if our target supports -Wl,--start-group + AC_MSG_CHECKING(for -Wl,--start-group support) + OLDFLAGS=$LDFLAGS + LDFLAGS="-Wl,--start-group,--end-group" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[ + have_linker_group_support=yes + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) + LDFLAGS=$OLDFLAGS + AM_CONDITIONAL([LINKER_SUPPORTS_GROUP], [test "x$have_linker_group_support" = "xyes"]) + # check if our target supports thread local storage AC_MSG_CHECKING(for thread local storage gnu __thread support) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], diff --git a/examples/lib/simple/Makefile.am b/examples/lib/simple/Makefile.am index afc6505c3bae..c4004b9446c9 100644 --- a/examples/lib/simple/Makefile.am +++ b/examples/lib/simple/Makefile.am @@ -5,7 +5,7 @@ simple_SOURCES = main.c AM_CPPFLAGS = -I$(top_srcdir)/src simple_LDFLAGS = $(all_libraries) $(SECLDFLAGS) -simple_LDADD = $(top_builddir)/src/libsuricata_c.a ../../$(RUST_SURICATA_LIB) $(RUST_LDADD) +simple_LDADD = "-Wl,--start-group,$(top_builddir)/src/libsuricata_c.a,../../$(RUST_SURICATA_LIB),--end-group" $(RUST_LDADD) if HTP_LDADD simple_LDADD += ../../$(HTP_LDADD) endif diff --git a/rust/cbindgen.toml b/rust/cbindgen.toml index 3240f4661ef1..b277e00506d8 100644 --- a/rust/cbindgen.toml +++ b/rust/cbindgen.toml @@ -82,6 +82,7 @@ include = [ "QuicState", "QuicTransaction", "FtpEvent", + "SCSigTableElmt", ] # A list of items to not include in the generated bindings diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index 2b1fd0e464b0..bb2441798edb 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -27,6 +27,9 @@ pub mod uri; pub mod requires; pub mod tojson; +use crate::core::AppProto; +use std::os::raw::{c_int, c_void}; + /// EnumString trait that will be implemented on enums that /// derive StringEnum. pub trait EnumString { @@ -43,6 +46,64 @@ pub trait EnumString { fn from_str(s: &str) -> Option where Self: Sized; } +#[repr(C)] +#[allow(non_snake_case)] +pub struct SCSigTableElmt { + pub name: *const libc::c_char, + pub desc: *const libc::c_char, + pub url: *const libc::c_char, + pub flags: u16, + pub Setup: unsafe extern "C" fn( + de: *mut c_void, + s: *mut c_void, + raw: *const std::os::raw::c_char, + ) -> c_int, + pub Free: Option, + pub AppLayerTxMatch: Option< + unsafe extern "C" fn( + de: *mut c_void, + f: *mut c_void, + flags: u8, + state: *mut c_void, + tx: *mut c_void, + sig: *const c_void, + ctx: *const c_void, + ) -> c_int, + >, +} + +pub(crate) const SIGMATCH_NOOPT: u16 = 1; // BIT_U16(0) in detect.h +pub(crate) const SIGMATCH_INFO_STICKY_BUFFER: u16 = 0x200; // BIT_U16(9) + +extern { + pub fn DetectBufferSetActiveList(de: *mut c_void, s: *mut c_void, bufid: c_int) -> c_int; + pub fn DetectHelperGetData( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, + get_buf: unsafe extern "C" fn(*const c_void, u8, *mut *const u8, *mut u32) -> bool, + ) -> *mut c_void; + pub fn DetectHelperBufferMpmRegister( + name: *const libc::c_char, desc: *const libc::c_char, alproto: AppProto, toclient: bool, + toserver: bool, + get_data: unsafe extern "C" fn( + *mut c_void, + *const c_void, + *const c_void, + u8, + *const c_void, + i32, + ) -> *mut c_void, + ) -> c_int; + pub fn DetectHelperKeywordRegister(kw: *const SCSigTableElmt) -> c_int; + pub fn DetectHelperBufferRegister( + name: *const libc::c_char, alproto: AppProto, toclient: bool, toserver: bool, + ) -> c_int; + pub fn DetectSignatureSetAppProto(s: *mut c_void, alproto: AppProto) -> c_int; + pub fn SigMatchAppendSMToList( + de: *mut c_void, s: *mut c_void, kwid: c_int, ctx: *const c_void, bufid: c_int, + ) -> *mut c_void; +} + #[cfg(test)] mod test { use super::*; diff --git a/src/Makefile.am b/src/Makefile.am index 4ccc691802d2..dd7bd36cca23 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -131,6 +131,7 @@ noinst_HEADERS = \ detect-engine-file.h \ detect-engine-frame.h \ detect-engine.h \ + detect-engine-helper.h \ detect-engine-iponly.h \ detect-engine-loader.h \ detect-engine-mpm.h \ @@ -758,6 +759,7 @@ libsuricata_c_a_SOURCES = \ detect-engine-event.c \ detect-engine-file.c \ detect-engine-frame.c \ + detect-engine-helper.c \ detect-engine-iponly.c \ detect-engine-loader.c \ detect-engine-mpm.c \ @@ -1320,7 +1322,13 @@ suricata_SOURCES = main.c # the library search path. suricata_LDFLAGS = $(all_libraries) ${SECLDFLAGS} -suricata_LDADD = libsuricata_c.a $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD) +# rust library depends also on c +if LINKER_SUPPORTS_GROUP +LDADD_GENERIC = "-Wl,--start-group,libsuricata_c.a,$(RUST_SURICATA_LIB),--end-group" $(HTP_LDADD) $(RUST_LDADD) +else +LDADD_GENERIC = libsuricata_c.a $(RUST_SURICATA_LIB) libsuricata_c.a $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD) +endif +suricata_LDADD = $(LDADD_GENERIC) suricata_DEPENDENCIES = libsuricata_c.a $(RUST_SURICATA_LIB) if BUILD_SHARED_LIBRARY @@ -1356,7 +1364,7 @@ uninstall-local: if BUILD_FUZZTARGETS LDFLAGS_FUZZ = $(all_libraries) $(SECLDFLAGS) -LDADD_FUZZ = libsuricata_c.a $(RUST_SURICATA_LIB) $(HTP_LDADD) $(RUST_LDADD) +LDADD_FUZZ = $(LDADD_GENERIC) fuzz_applayerprotodetectgetproto_SOURCES = tests/fuzz/fuzz_applayerprotodetectgetproto.c fuzz_applayerprotodetectgetproto_LDFLAGS = $(LDFLAGS_FUZZ) diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c new file mode 100644 index 000000000000..0b7c9ccb2077 --- /dev/null +++ b/src/detect-engine-helper.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Philippe Antoine + * + */ + +#include "suricata-common.h" +#include "detect-engine.h" +#include "detect-engine-helper.h" +#include "detect-engine-mpm.h" +#include "detect-engine-prefilter.h" +#include "detect-parse.h" + +int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver) +{ + if (toserver) { + DetectAppLayerInspectEngineRegister( + name, alproto, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); + } + if (toclient) { + DetectAppLayerInspectEngineRegister( + name, alproto, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); + } + return DetectBufferTypeRegister(name); +} + +InspectionBuffer *DetectHelperGetData(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, + bool (*GetBuf)(void *txv, const uint8_t flow_flags, const uint8_t **buf, uint32_t *buf_len)) +{ + InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); + if (buffer->inspect == NULL) { + const uint8_t *b = NULL; + uint32_t b_len = 0; + + if (!GetBuf(txv, flow_flags, &b, &b_len)) + return NULL; + + InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); + InspectionBufferApplyTransforms(buffer, transforms); + } + return buffer; +} + +int DetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, + bool toclient, bool toserver, InspectionBufferGetDataPtr GetData) +{ + if (toserver) { + DetectAppLayerInspectEngineRegister( + name, alproto, SIG_FLAG_TOSERVER, 0, DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerMpmRegister( + name, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister, GetData, alproto, 0); + } + if (toclient) { + DetectAppLayerInspectEngineRegister( + name, alproto, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectBufferGeneric, GetData); + DetectAppLayerMpmRegister( + name, SIG_FLAG_TOCLIENT, 2, PrefilterGenericMpmRegister, GetData, alproto, 0); + } + DetectBufferTypeSetDescriptionByName(name, desc); + return DetectBufferTypeGetByName(name); +} + +int DetectHelperKeywordRegister(const SCSigTableElmt *kw) +{ + if (DETECT_TBLSIZE_IDX >= DETECT_TBLSIZE) { + void *tmp = SCRealloc( + sigmatch_table, (DETECT_TBLSIZE + DETECT_TBLSIZE_STEP) * sizeof(SigTableElmt)); + if (unlikely(tmp == NULL)) { + return -1; + } + sigmatch_table = tmp; + DETECT_TBLSIZE += DETECT_TBLSIZE_STEP; + } + + sigmatch_table[DETECT_TBLSIZE_IDX].name = kw->name; + sigmatch_table[DETECT_TBLSIZE_IDX].desc = kw->desc; + sigmatch_table[DETECT_TBLSIZE_IDX].url = kw->url; + sigmatch_table[DETECT_TBLSIZE_IDX].flags = kw->flags; + sigmatch_table[DETECT_TBLSIZE_IDX].AppLayerTxMatch = + (int (*)(DetectEngineThreadCtx * det_ctx, Flow * f, uint8_t flags, void *alstate, + void *txv, const Signature *s, const SigMatchCtx *ctx)) kw->AppLayerTxMatch; + sigmatch_table[DETECT_TBLSIZE_IDX].Setup = + (int (*)(DetectEngineCtx * de, Signature * s, const char *raw)) kw->Setup; + sigmatch_table[DETECT_TBLSIZE_IDX].Free = (void (*)(DetectEngineCtx * de, void *ptr)) kw->Free; + DETECT_TBLSIZE_IDX++; + return DETECT_TBLSIZE_IDX - 1; +} diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h new file mode 100644 index 000000000000..bd8fe6cce5a6 --- /dev/null +++ b/src/detect-engine-helper.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Philippe Antoine + */ + +#ifndef SURICATA_DETECT_ENGINE_HELPER_H +#define SURICATA_DETECT_ENGINE_HELPER_H + +#include "app-layer-protos.h" +#include "detect.h" +#include "rust.h" + +int DetectHelperKeywordRegister(const SCSigTableElmt *kw); +int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver); + +typedef bool (*SimpleGetTxBuffer)(void *, uint8_t, const uint8_t **, uint32_t *); +InspectionBuffer *DetectHelperGetData(struct DetectEngineThreadCtx_ *det_ctx, + const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, + const int list_id, SimpleGetTxBuffer GetBuf); +int DetectHelperBufferMpmRegister(const char *name, const char *desc, AppProto alproto, + bool toclient, bool toserver, InspectionBufferGetDataPtr GetData); + +#endif /* SURICATA_DETECT_ENGINE_HELPER_H */ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 7b7e5442aad1..d5b814be5696 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -340,6 +340,9 @@ #include "util-mpm-ac.h" #include "runmodes.h" +int DETECT_TBLSIZE = 0; +int DETECT_TBLSIZE_IDX = DETECT_TBLSIZE_STATIC; + static void PrintFeatureList(const SigTableElmt *e, char sep) { const uint16_t flags = e->flags; @@ -408,7 +411,7 @@ static void SigMultilinePrint(int i, const char *prefix) int SigTableList(const char *keyword) { - size_t size = sizeof(sigmatch_table) / sizeof(SigTableElmt); + size_t size = DETECT_TBLSIZE; size_t i; if (keyword == NULL) { @@ -483,15 +486,32 @@ int SigTableList(const char *keyword) static void DetectFileHandlerRegister(void) { - for (int i = 0; i < DETECT_TBLSIZE; i++) { + for (int i = 0; i < DETECT_TBLSIZE_STATIC; i++) { if (filehandler_table[i].name) DetectFileRegisterFileProtocols(&filehandler_table[i]); } } +void SigTableCleanup(void) +{ + if (sigmatch_table != NULL) { + SCFree(sigmatch_table); + sigmatch_table = NULL; + DETECT_TBLSIZE = 0; + } +} + void SigTableSetup(void) { - memset(sigmatch_table, 0, sizeof(sigmatch_table)); + if (sigmatch_table == NULL) { + DETECT_TBLSIZE = DETECT_TBLSIZE_STATIC + DETECT_TBLSIZE_STEP; + sigmatch_table = SCCalloc(DETECT_TBLSIZE, sizeof(SigTableElmt)); + if (sigmatch_table == NULL) { + DETECT_TBLSIZE = 0; + FatalError("Could not allocate sigmatch_table"); + return; + } + } DetectSidRegister(); DetectPriorityRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 58908c05d756..3def9ed3be9f 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -374,10 +374,15 @@ enum DetectKeywordId { DETECT_AL_JA4_HASH, /* make sure this stays last */ - DETECT_TBLSIZE, + DETECT_TBLSIZE_STATIC, }; +extern int DETECT_TBLSIZE; +extern int DETECT_TBLSIZE_IDX; +// step for reallocating sigmatch_table +#define DETECT_TBLSIZE_STEP 256 int SigTableList(const char *keyword); +void SigTableCleanup(void); void SigTableSetup(void); void SigTableRegisterTests(void); diff --git a/src/detect-engine.c b/src/detect-engine.c index 995d285f7489..efb480f59088 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -2493,6 +2493,14 @@ static DetectEngineCtx *DetectEngineCtxInitReal( goto error; } + de_ctx->sm_types_prefilter = SCCalloc(DETECT_TBLSIZE, sizeof(bool)); + if (de_ctx->sm_types_prefilter == NULL) { + goto error; + } + de_ctx->sm_types_silent_error = SCCalloc(DETECT_TBLSIZE, sizeof(bool)); + if (de_ctx->sm_types_silent_error == NULL) { + goto error; + } if (DetectEngineCtxLoadConf(de_ctx) == -1) { goto error; } @@ -2625,6 +2633,8 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx) SigGroupCleanup(de_ctx); SpmDestroyGlobalThreadCtx(de_ctx->spm_global_thread_ctx); + SCFree(de_ctx->sm_types_prefilter); + SCFree(de_ctx->sm_types_silent_error); MpmFactoryDeRegisterAllMpmCtxProfiles(de_ctx); diff --git a/src/detect-parse.c b/src/detect-parse.c index 67d68c57cb86..61318521f45d 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -74,7 +74,7 @@ #include "util-validate.h" /* Table with all filehandler registrations */ -DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE]; +DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE_STATIC]; void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg) { @@ -124,7 +124,7 @@ void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *reg) } /* Table with all SigMatch registrations */ -SigTableElmt sigmatch_table[DETECT_TBLSIZE]; +SigTableElmt *sigmatch_table = NULL; extern bool sc_set_caps; @@ -383,7 +383,7 @@ bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, bool SigMatchStrictEnabled(const enum DetectKeywordId id) { - if (id < DETECT_TBLSIZE) { + if ((int)id < DETECT_TBLSIZE) { return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0); } return false; diff --git a/src/detect-parse.h b/src/detect-parse.h index 0a993a794f84..ec2c204c0f42 100644 --- a/src/detect-parse.h +++ b/src/detect-parse.h @@ -42,7 +42,7 @@ typedef struct DetectFileHandlerTableElmt_ { void DetectFileRegisterFileProtocols(DetectFileHandlerTableElmt *entry); /* File registration table */ -extern DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE]; +extern DetectFileHandlerTableElmt filehandler_table[DETECT_TBLSIZE_STATIC]; /** Flags to indicate if the Signature parsing must be done * switching the source and dest (for ip addresses and ports) diff --git a/src/detect.h b/src/detect.h index 5c1583074f05..87a4219de917 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1029,8 +1029,8 @@ typedef struct DetectEngineCtx_ { /** per keyword flag indicating if a prefilter has been * set for it. If true, the setup function will have to * run. */ - bool sm_types_prefilter[DETECT_TBLSIZE]; - bool sm_types_silent_error[DETECT_TBLSIZE]; + bool *sm_types_prefilter; + bool *sm_types_silent_error; /* classification config parsing */ @@ -1574,7 +1574,7 @@ typedef struct DetectEngineMasterCtx_ { } DetectEngineMasterCtx; /* Table with all SigMatch registrations */ -extern SigTableElmt sigmatch_table[DETECT_TBLSIZE]; +extern SigTableElmt *sigmatch_table; /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ diff --git a/src/suricata.c b/src/suricata.c index 48a51b815f4b..0ff1bdbb8398 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -393,6 +393,7 @@ void GlobalsDestroy(void) FeatureTrackingRelease(); SCProtoNameRelease(); TimeDeinit(); + SigTableCleanup(); TmqhCleanup(); TmModuleRunDeInit(); ParseSizeDeinit();