From: Jeff Lucovsky Date: Sat, 5 Apr 2025 20:08:39 +0000 (-0400) Subject: detect/xform: Support transform identity data X-Git-Tag: suricata-8.0.0-rc1~289 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=07205ab057704c8b8cfaf1fa1739c8491db2961c;p=thirdparty%2Fsuricata.git detect/xform: Support transform identity data Transforms that support optional strings, like from_base64 and pcrexform, should also support identity-strings to treat transforms with like transform options as the same. This commit adds transform identity data handling: - When computing a hash, include identity data from the transform - When comparing, include the identity data from the transforms - Omitting the "options" ptr from the transform hash/compare - Modify xor, pcrexform and from_base64 to supply identification data for disambiguation in the compare/hash logic. --- diff --git a/rust/src/detect/transform_base64.rs b/rust/src/detect/transform_base64.rs index a85622b2e5..7d867ff23e 100644 --- a/rust/src/detect/transform_base64.rs +++ b/rust/src/detect/transform_base64.rs @@ -19,9 +19,9 @@ use crate::detect::error::RuleParseError; use crate::detect::parser::{parse_var, take_until_whitespace, ResultValue}; +use crate::ffi::base64::SCBase64Mode; use std::ffi::{CStr, CString}; use std::os::raw::c_char; -use crate::ffi::base64::SCBase64Mode; use nom7::bytes::complete::tag; use nom7::character::complete::multispace0; @@ -147,7 +147,8 @@ fn parse_transform_base64( } else { return Err(make_error(format!( "invalid offset value: must be between 0 and {}: {}", - u16::MAX, val + u16::MAX, + val ))); } } @@ -179,7 +180,9 @@ fn parse_transform_base64( } else { return Err(make_error(format!( "invalid bytes value: must be between {} and {}: {}", - 0, u16::MAX, val + 0, + u16::MAX, + val ))); } } @@ -215,9 +218,7 @@ pub unsafe extern "C" fn SCTransformBase64Parse( return std::ptr::null_mut(); } - let arg = CStr::from_ptr(c_arg) - .to_str() - .unwrap_or(""); + let arg = CStr::from_ptr(c_arg).to_str().unwrap_or(""); match parse_transform_base64(arg) { Ok((_, detect)) => return Box::into_raw(Box::new(detect)), @@ -264,13 +265,8 @@ mod tests { } fn valid_test( - args: &str, - nbytes: u32, - nbytes_str: &str, - offset: u32, - offset_str: &str, - mode: SCBase64Mode, - flags: u8, + args: &str, nbytes: u32, nbytes_str: &str, offset: u32, offset_str: &str, + mode: SCBase64Mode, flags: u8, ) { let tbd = SCDetectTransformFromBase64Data { flags, diff --git a/rust/src/detect/transforms/casechange.rs b/rust/src/detect/transforms/casechange.rs index cea9d9248e..6cdf9c7da4 100644 --- a/rust/src/detect/transforms/casechange.rs +++ b/rust/src/detect/transforms/casechange.rs @@ -83,6 +83,7 @@ pub unsafe extern "C" fn DetectTransformToLowerRegister() { Transform: Some(tolower_transform), Free: None, TransformValidate: Some(tolower_validate), + TransformId: None, }; G_TRANSFORM_TOLOWER_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_TOLOWER_ID < 0 { @@ -145,6 +146,7 @@ pub unsafe extern "C" fn DetectTransformToUpperRegister() { Transform: Some(toupper_transform), Free: None, TransformValidate: Some(toupper_validate), + TransformId: None, }; G_TRANSFORM_TOUPPER_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_TOUPPER_ID < 0 { diff --git a/rust/src/detect/transforms/compress_whitespace.rs b/rust/src/detect/transforms/compress_whitespace.rs index 7d33825614..704b285e71 100644 --- a/rust/src/detect/transforms/compress_whitespace.rs +++ b/rust/src/detect/transforms/compress_whitespace.rs @@ -106,6 +106,7 @@ pub unsafe extern "C" fn DetectTransformCompressWhitespaceRegister() { Transform: Some(compress_whitespace_transform), Free: None, TransformValidate: Some(compress_whitespace_validate), + TransformId: None, }; G_TRANSFORM_COMPRESS_WHITESPACE_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_COMPRESS_WHITESPACE_ID < 0 { diff --git a/rust/src/detect/transforms/domain.rs b/rust/src/detect/transforms/domain.rs index 709c9d3ee6..49df1aa5a3 100644 --- a/rust/src/detect/transforms/domain.rs +++ b/rust/src/detect/transforms/domain.rs @@ -116,6 +116,7 @@ pub unsafe extern "C" fn SCDetectTransformDomainRegister() { Transform: Some(domain_transform), Free: None, TransformValidate: None, + TransformId: None, }; unsafe { G_TRANSFORM_DOMAIN_ID = SCDetectHelperTransformRegister(&kw); @@ -133,6 +134,7 @@ pub unsafe extern "C" fn SCDetectTransformDomainRegister() { Transform: Some(tld_transform), Free: None, TransformValidate: None, + TransformId: None, }; unsafe { G_TRANSFORM_TLD_ID = SCDetectHelperTransformRegister(&kw); diff --git a/rust/src/detect/transforms/dotprefix.rs b/rust/src/detect/transforms/dotprefix.rs index ac2693cbfe..76e745e5b5 100644 --- a/rust/src/detect/transforms/dotprefix.rs +++ b/rust/src/detect/transforms/dotprefix.rs @@ -79,6 +79,7 @@ pub unsafe extern "C" fn DetectTransformDotPrefixRegister() { Transform: Some(dot_prefix_transform), Free: None, TransformValidate: None, + TransformId: None, }; unsafe { G_TRANSFORM_DOT_PREFIX_ID = SCDetectHelperTransformRegister(&kw); diff --git a/rust/src/detect/transforms/hash.rs b/rust/src/detect/transforms/hash.rs index 7a4a27f974..8452247d95 100644 --- a/rust/src/detect/transforms/hash.rs +++ b/rust/src/detect/transforms/hash.rs @@ -84,6 +84,7 @@ pub unsafe extern "C" fn DetectTransformMd5Register() { Transform: Some(md5_transform), Free: None, TransformValidate: None, + TransformId: None, }; G_TRANSFORM_MD5_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_MD5_ID < 0 { @@ -138,6 +139,7 @@ pub unsafe extern "C" fn DetectTransformSha1Register() { Transform: Some(sha1_transform), Free: None, TransformValidate: None, + TransformId: None, }; G_TRANSFORM_SHA1_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_SHA1_ID < 0 { @@ -192,6 +194,7 @@ pub unsafe extern "C" fn DetectTransformSha256Register() { Transform: Some(sha256_transform), Free: None, TransformValidate: None, + TransformId: None, }; G_TRANSFORM_SHA256_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_SHA256_ID < 0 { diff --git a/rust/src/detect/transforms/http_headers.rs b/rust/src/detect/transforms/http_headers.rs index 7bd9495038..b56470cba2 100644 --- a/rust/src/detect/transforms/http_headers.rs +++ b/rust/src/detect/transforms/http_headers.rs @@ -86,6 +86,7 @@ pub unsafe extern "C" fn DetectTransformHeaderLowercaseRegister() { Transform: Some(header_lowertransform), Free: None, TransformValidate: None, + TransformId: None, }; G_TRANSFORM_HEADER_LOWER_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_HEADER_LOWER_ID < 0 { @@ -150,6 +151,7 @@ pub unsafe extern "C" fn DetectTransformStripPseudoHeadersRegister() { Transform: Some(strip_pseudo_transform), Free: None, TransformValidate: None, + TransformId: None, }; G_TRANSFORM_STRIP_PSEUDO_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_STRIP_PSEUDO_ID < 0 { diff --git a/rust/src/detect/transforms/strip_whitespace.rs b/rust/src/detect/transforms/strip_whitespace.rs index dbc77fb531..25c6fe41a6 100644 --- a/rust/src/detect/transforms/strip_whitespace.rs +++ b/rust/src/detect/transforms/strip_whitespace.rs @@ -93,6 +93,7 @@ pub unsafe extern "C" fn DetectTransformStripWhitespaceRegister() { Transform: Some(strip_whitespace_transform), Free: None, TransformValidate: Some(strip_whitespace_validate), + TransformId: None, }; unsafe { G_TRANSFORM_STRIP_WHITESPACE_ID = SCDetectHelperTransformRegister(&kw); diff --git a/rust/src/detect/transforms/urldecode.rs b/rust/src/detect/transforms/urldecode.rs index a7317db6b5..fa4c403fc3 100644 --- a/rust/src/detect/transforms/urldecode.rs +++ b/rust/src/detect/transforms/urldecode.rs @@ -121,6 +121,7 @@ pub unsafe extern "C" fn DetectTransformUrlDecodeRegister() { Transform: Some(url_decode_transform), Free: None, TransformValidate: None, + TransformId: None, }; G_TRANSFORM_URL_DECODE_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_URL_DECODE_ID < 0 { diff --git a/rust/src/detect/transforms/xor.rs b/rust/src/detect/transforms/xor.rs index e4f46f2f09..a416bd9de8 100644 --- a/rust/src/detect/transforms/xor.rs +++ b/rust/src/detect/transforms/xor.rs @@ -108,6 +108,16 @@ unsafe extern "C" fn xor_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) { std::mem::drop(Box::from_raw(ctx as *mut DetectTransformXorData)); } +unsafe extern "C" fn xor_id(data: *mut *const u8, length: *mut u32, ctx: *mut c_void) { + if data.is_null() || length.is_null() || ctx.is_null() { + return; + } + + let ctx = cast_pointer!(ctx, DetectTransformXorData); + *data = ctx.key.as_ptr(); + *length = ctx.key.len() as u32; +} + #[no_mangle] pub unsafe extern "C" fn DetectTransformXorRegister() { let kw = SCTransformTableElmt { @@ -119,11 +129,12 @@ pub unsafe extern "C" fn DetectTransformXorRegister() { Transform: Some(xor_transform), Free: Some(xor_free), TransformValidate: None, + TransformId: Some(xor_id), }; unsafe { G_TRANSFORM_XOR_ID = SCDetectHelperTransformRegister(&kw); if G_TRANSFORM_XOR_ID < 0 { - SCLogWarning!("Failed registering transform dot_prefix"); + SCLogWarning!("Failed registering transform xor"); } } } @@ -142,6 +153,32 @@ mod tests { ); } + #[test] + fn test_xor_id() { + let ctx = Box::new(DetectTransformXorData { + key: vec![1, 2, 3, 4, 5], + }); + + let ctx_ptr: *const c_void = &*ctx as *const _ as *const c_void; + + let mut data_ptr: *const u8 = std::ptr::null(); + let mut length: u32 = 0; + + unsafe { + xor_id( + &mut data_ptr as *mut *const u8, + &mut length as *mut u32, + ctx_ptr as *mut c_void, + ); + + assert!(!data_ptr.is_null(), "data_ptr should not be null"); + assert_eq!(length, 5); + + let actual = std::slice::from_raw_parts(data_ptr, length as usize); + assert_eq!(actual, &[1, 2, 3, 4, 5]); + } + } + #[test] fn test_xor_transform() { let mut buf = Vec::new(); diff --git a/rust/sys/src/sys.rs b/rust/sys/src/sys.rs index b744177703..b4b30d3c0d 100644 --- a/rust/sys/src/sys.rs +++ b/rust/sys/src/sys.rs @@ -325,6 +325,13 @@ pub struct SCTransformTableElmt { context: *mut ::std::os::raw::c_void, ) -> bool, >, + pub TransformId: ::std::option::Option< + unsafe extern "C" fn( + id_data: *mut *const u8, + id_length: *mut u32, + context: *mut ::std::os::raw::c_void, + ), + >, } extern "C" { pub fn SCDetectHelperNewKeywordId() -> ::std::os::raw::c_int; diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index 87af817421..7c6221ca45 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -163,6 +163,8 @@ int SCDetectHelperTransformRegister(const SCTransformTableElmt *kw) sigmatch_table[transform_id].Setup = (int (*)(DetectEngineCtx * de, Signature * s, const char *raw)) kw->Setup; sigmatch_table[transform_id].Free = (void (*)(DetectEngineCtx * de, void *ptr)) kw->Free; + sigmatch_table[transform_id].TransformId = + (void (*)(const uint8_t **id_data, uint32_t *length, void *context))kw->TransformId; return transform_id; } diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index 284be45713..170cda374e 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -71,6 +71,7 @@ typedef struct SCTransformTableElmt { void (*Free)(DetectEngineCtx *, void *); void (*Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context); bool (*TransformValidate)(const uint8_t *content, uint16_t content_len, void *context); + void (*TransformId)(const uint8_t **id_data, uint32_t *id_length, void *context); } SCTransformTableElmt; int SCDetectHelperNewKeywordId(void); diff --git a/src/detect-engine.c b/src/detect-engine.c index f0ff76fc1f..5117c38203 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -984,12 +984,40 @@ int DetectBufferTypeMaxId(void) return g_buffer_type_id; } +static void DetectBufferAddTransformData(DetectBufferType *map) +{ + for (int i = 0; i < map->transforms.cnt; i++) { + const TransformData *t = &map->transforms.transforms[i]; + if (sigmatch_table[t->transform].TransformId) { + sigmatch_table[t->transform].TransformId( + &map->xform_id[i].id_data, &map->xform_id[i].id_data_len, t->options); + SCLogDebug("transform identity data: [%p] \"%s\" [%d]", map->xform_id[i].id_data, + (char *)map->xform_id[i].id_data, map->xform_id[i].id_data_len); + } + } +} + static uint32_t DetectBufferTypeHashNameFunc(HashListTable *ht, void *data, uint16_t datalen) { const DetectBufferType *map = (DetectBufferType *)data; uint32_t hash = hashlittle_safe(map->name, strlen(map->name), 0); - hash += hashlittle_safe((uint8_t *)&map->transforms, sizeof(map->transforms), 0); + + // Add the transform data + // - Collect transform id and position + // - Collect identity data, if any + hash += hashlittle_safe((uint8_t *)&map->transforms.cnt, sizeof(map->transforms.cnt), 0); + for (int i = 0; i < map->transforms.cnt; i++) { + const TransformData *t = &map->transforms.transforms[i]; + int tval = t->transform; + hash += hashlittle_safe((uint8_t *)&tval, sizeof(tval), 0); + if (map->xform_id[i].id_data) { + hash += hashlittle_safe( + &map->xform_id[i].id_data_len, sizeof(map->xform_id[i].id_data_len), 0); + hash += hashlittle_safe(map->xform_id[i].id_data, map->xform_id[i].id_data_len, 0); + } + } hash %= ht->array_size; + SCLogDebug("map->name %s, hash %d", map->name, hash); return hash; } @@ -1007,7 +1035,49 @@ static char DetectBufferTypeCompareNameFunc(void *data1, uint16_t len1, void *da DetectBufferType *map2 = (DetectBufferType *)data2; char r = (strcmp(map1->name, map2->name) == 0); - r &= (memcmp((uint8_t *)&map1->transforms, (uint8_t *)&map2->transforms, sizeof(map2->transforms)) == 0); + + // Compare the transforms + // the transform supports identity, that data will also be added. + r &= map1->transforms.cnt == map2->transforms.cnt; + if (r && map1->transforms.cnt) { + for (int i = 0; i < map1->transforms.cnt; i++) { + if (map1->transforms.transforms[i].transform != + map2->transforms.transforms[i].transform) { + r = 0; + break; + } + + SCLogDebug("%s: transform ids match; checking specialized data", map1->name); + // Checks + // - Both NULL: --> ok, continue + // - One NULL: --> no match, break? + // - identity data lengths match: --> ok, continue + // - identity data matches: ok + + // Stop if only one is NULL + if ((map1->xform_id[i].id_data == NULL) ^ (map2->xform_id[i].id_data == NULL)) { + SCLogDebug("identity data: only one is null"); + r = 0; + break; + } else if (map1->xform_id[i].id_data == NULL) { /* continue when both are null */ + SCLogDebug("identity data: both null"); + r = 1; + continue; + } else if (map1->xform_id[i].id_data_len != map2->xform_id[i].id_data_len) { + // Stop when id data lengths aren't equal + SCLogDebug("id data: unequal lengths"); + r = 0; + break; + } + + // stop if the identity data is different + r &= memcmp(map1->xform_id[i].id_data, map2->xform_id[i].id_data, + map1->xform_id[i].id_data_len) == 0; + if (r == 0) + break; + SCLogDebug("identity data: data matches"); + } + } return r; } @@ -1030,6 +1100,7 @@ static void DetectBufferTypeFreeFunc(void *data) for (int i = 0; i < map->transforms.cnt; i++) { if (map->transforms.transforms[i].options == NULL) continue; + if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) { SCLogError("%s allocates transform option memory but has no free routine", sigmatch_table[map->transforms.transforms[i].transform].name); @@ -1561,6 +1632,11 @@ int DetectEngineBufferTypeGetByIdTransforms( memset(&lookup_map, 0, sizeof(lookup_map)); strlcpy(lookup_map.name, base_map->name, sizeof(lookup_map.name)); lookup_map.transforms = t; + + /* Add transform identity data from transforms */ + if (t.cnt) { + DetectBufferAddTransformData(&lookup_map); + } DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash_name, &lookup_map, 0); SCLogDebug("res %p", res); diff --git a/src/detect-transform-base64.c b/src/detect-transform-base64.c index a488a7fce6..6e3b58c800 100644 --- a/src/detect-transform-base64.c +++ b/src/detect-transform-base64.c @@ -37,33 +37,28 @@ #include "util-unittest.h" #include "util-print.h" -static int DetectTransformFromBase64DecodeSetup(DetectEngineCtx *, Signature *, const char *); -static void DetectTransformFromBase64DecodeFree(DetectEngineCtx *, void *); #ifdef UNITTESTS #define DETECT_TRANSFORM_FROM_BASE64_MODE_DEFAULT (uint8_t) SCBase64ModeRFC4648 static void DetectTransformFromBase64DecodeRegisterTests(void); #endif -static void TransformFromBase64Decode( - DetectEngineThreadCtx *det_ctx, InspectionBuffer *buffer, void *options); -void DetectTransformFromBase64DecodeRegister(void) +static void DetectTransformFromBase64Id(const uint8_t **data, uint32_t *length, void *context) { - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].name = "from_base64"; - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].desc = "convert the base64 decode of the buffer"; - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].url = "/rules/transforms.html#from_base64"; - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Setup = DetectTransformFromBase64DecodeSetup; - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Transform = TransformFromBase64Decode; - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Free = DetectTransformFromBase64DecodeFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].RegisterTests = - DetectTransformFromBase64DecodeRegisterTests; -#endif - sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].flags |= SIGMATCH_OPTIONAL_OPT; + if (context) { + SCDetectTransformFromBase64Data *b64d = (SCDetectTransformFromBase64Data *)context; + /* Since the context structure contains the unique values for the keyword usage, + * a pointer to the context structure is returned. + */ + *data = (const uint8_t *)b64d; + *length = sizeof(*b64d); + } } static void DetectTransformFromBase64DecodeFree(DetectEngineCtx *de_ctx, void *ptr) { - SCTransformBase64Free(ptr); + if (ptr) { + SCTransformBase64Free(ptr); + } } static SCDetectTransformFromBase64Data *DetectTransformFromBase64DecodeParse(const char *str) @@ -155,6 +150,22 @@ static void TransformFromBase64Decode( } } +void DetectTransformFromBase64DecodeRegister(void) +{ + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].name = "from_base64"; + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].desc = "convert the base64 decode of the buffer"; + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].url = "/rules/transforms.html#from_base64"; + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Setup = DetectTransformFromBase64DecodeSetup; + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Transform = TransformFromBase64Decode; + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].TransformId = DetectTransformFromBase64Id; + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Free = DetectTransformFromBase64DecodeFree; +#ifdef UNITTESTS + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].RegisterTests = + DetectTransformFromBase64DecodeRegisterTests; +#endif + sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].flags |= SIGMATCH_OPTIONAL_OPT; +} + #ifdef UNITTESTS /* Simple success case -- check buffer */ static int DetectTransformFromBase64DecodeTest01(void) diff --git a/src/detect-transform-pcrexform.c b/src/detect-transform-pcrexform.c index 24b02bfb4a..b901c99875 100644 --- a/src/detect-transform-pcrexform.c +++ b/src/detect-transform-pcrexform.c @@ -34,6 +34,8 @@ typedef struct DetectTransformPcrexformData { pcre2_code *regex; pcre2_match_context *context; + uint8_t *id_data; + uint32_t id_data_len; } DetectTransformPcrexformData; static int DetectTransformPcrexformSetup (DetectEngineCtx *, Signature *, const char *); @@ -44,6 +46,15 @@ static void DetectTransformPcrexform( void DetectTransformPcrexformRegisterTests (void); #endif +static void DetectTransformPcrexformId(const uint8_t **data, uint32_t *length, void *context) +{ + if (context) { + DetectTransformPcrexformData *pxd = (DetectTransformPcrexformData *)context; + *data = (const uint8_t *)pxd->id_data; + *length = pxd->id_data_len; + } +} + void DetectTransformPcrexformRegister(void) { sigmatch_table[DETECT_TRANSFORM_PCREXFORM].name = "pcrexform"; @@ -52,6 +63,7 @@ void DetectTransformPcrexformRegister(void) sigmatch_table[DETECT_TRANSFORM_PCREXFORM].url = "/rules/transforms.html#pcre-xform"; sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Transform = DetectTransformPcrexform; + sigmatch_table[DETECT_TRANSFORM_PCREXFORM].TransformId = DetectTransformPcrexformId; sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Free = DetectTransformPcrexformFree; sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Setup = @@ -66,8 +78,11 @@ static void DetectTransformPcrexformFree(DetectEngineCtx *de_ctx, void *ptr) { if (ptr != NULL) { DetectTransformPcrexformData *pxd = (DetectTransformPcrexformData *) ptr; + pcre2_match_context_free(pxd->context); pcre2_code_free(pxd->regex); + + SCFree(pxd->id_data); SCFree(pxd); } } @@ -112,6 +127,7 @@ static int DetectTransformPcrexformSetup (DetectEngineCtx *de_ctx, Signature *s, SCFree(pxd); SCReturnInt(-1); } + // check pcd->regex has exactly one capture expression uint32_t nb; if (pcre2_pattern_info(pxd->regex, PCRE2_INFO_CAPTURECOUNT, &nb) < 0) { @@ -125,6 +141,13 @@ static int DetectTransformPcrexformSetup (DetectEngineCtx *de_ctx, Signature *s, SCReturnInt(-1); } + pxd->id_data = (uint8_t *)SCStrdup(regexstr); + if (pxd->id_data == NULL) { + DetectTransformPcrexformFree(de_ctx, pxd); + SCReturnInt(-1); + } + pxd->id_data_len = strlen(regexstr); + int r = SCDetectSignatureAddTransform(s, DETECT_TRANSFORM_PCREXFORM, pxd); if (r != 0) { DetectTransformPcrexformFree(de_ctx, pxd); diff --git a/src/detect.h b/src/detect.h index bbe9273e75..2d4ecb5d38 100644 --- a/src/detect.h +++ b/src/detect.h @@ -438,6 +438,11 @@ typedef struct DetectEngineAppInspectionEngine_ { struct DetectEngineAppInspectionEngine_ *next; } DetectEngineAppInspectionEngine; +typedef struct TransformIdData_ { + const uint8_t *id_data; + uint32_t id_data_len; +} TransformIdData; + typedef struct DetectBufferType_ { char name[64]; char description[128]; @@ -452,6 +457,7 @@ typedef struct DetectBufferType_ { bool (*ValidateCallback)( const struct Signature_ *, const char **sigerror, const struct DetectBufferType_ *); DetectEngineTransforms transforms; + TransformIdData xform_id[DETECT_TRANSFORMS_MAX]; } DetectBufferType; struct DetectEnginePktInspectionEngine; @@ -1386,6 +1392,9 @@ typedef struct SigTableElmt_ { void (*Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context); bool (*TransformValidate)(const uint8_t *content, uint16_t content_len, void *context); + /** Transform identity callback */ + void (*TransformId)(const uint8_t **data, uint32_t *length, void *context); + /** keyword setup function pointer */ int (*Setup)(DetectEngineCtx *, Signature *, const char *);