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.
pull/13235/head
Jeff Lucovsky 1 year ago committed by Victor Julien
parent 0b53a19c81
commit 07205ab057

@ -19,9 +19,9 @@
use crate::detect::error::RuleParseError; use crate::detect::error::RuleParseError;
use crate::detect::parser::{parse_var, take_until_whitespace, ResultValue}; use crate::detect::parser::{parse_var, take_until_whitespace, ResultValue};
use crate::ffi::base64::SCBase64Mode;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::os::raw::c_char; use std::os::raw::c_char;
use crate::ffi::base64::SCBase64Mode;
use nom7::bytes::complete::tag; use nom7::bytes::complete::tag;
use nom7::character::complete::multispace0; use nom7::character::complete::multispace0;
@ -147,7 +147,8 @@ fn parse_transform_base64(
} else { } else {
return Err(make_error(format!( return Err(make_error(format!(
"invalid offset value: must be between 0 and {}: {}", "invalid offset value: must be between 0 and {}: {}",
u16::MAX, val u16::MAX,
val
))); )));
} }
} }
@ -179,7 +180,9 @@ fn parse_transform_base64(
} else { } else {
return Err(make_error(format!( return Err(make_error(format!(
"invalid bytes value: must be between {} and {}: {}", "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(); return std::ptr::null_mut();
} }
let arg = CStr::from_ptr(c_arg) let arg = CStr::from_ptr(c_arg).to_str().unwrap_or("");
.to_str()
.unwrap_or("");
match parse_transform_base64(arg) { match parse_transform_base64(arg) {
Ok((_, detect)) => return Box::into_raw(Box::new(detect)), Ok((_, detect)) => return Box::into_raw(Box::new(detect)),
@ -264,13 +265,8 @@ mod tests {
} }
fn valid_test( fn valid_test(
args: &str, args: &str, nbytes: u32, nbytes_str: &str, offset: u32, offset_str: &str,
nbytes: u32, mode: SCBase64Mode, flags: u8,
nbytes_str: &str,
offset: u32,
offset_str: &str,
mode: SCBase64Mode,
flags: u8,
) { ) {
let tbd = SCDetectTransformFromBase64Data { let tbd = SCDetectTransformFromBase64Data {
flags, flags,

@ -83,6 +83,7 @@ pub unsafe extern "C" fn DetectTransformToLowerRegister() {
Transform: Some(tolower_transform), Transform: Some(tolower_transform),
Free: None, Free: None,
TransformValidate: Some(tolower_validate), TransformValidate: Some(tolower_validate),
TransformId: None,
}; };
G_TRANSFORM_TOLOWER_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_TOLOWER_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_TOLOWER_ID < 0 { if G_TRANSFORM_TOLOWER_ID < 0 {
@ -145,6 +146,7 @@ pub unsafe extern "C" fn DetectTransformToUpperRegister() {
Transform: Some(toupper_transform), Transform: Some(toupper_transform),
Free: None, Free: None,
TransformValidate: Some(toupper_validate), TransformValidate: Some(toupper_validate),
TransformId: None,
}; };
G_TRANSFORM_TOUPPER_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_TOUPPER_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_TOUPPER_ID < 0 { if G_TRANSFORM_TOUPPER_ID < 0 {

@ -106,6 +106,7 @@ pub unsafe extern "C" fn DetectTransformCompressWhitespaceRegister() {
Transform: Some(compress_whitespace_transform), Transform: Some(compress_whitespace_transform),
Free: None, Free: None,
TransformValidate: Some(compress_whitespace_validate), TransformValidate: Some(compress_whitespace_validate),
TransformId: None,
}; };
G_TRANSFORM_COMPRESS_WHITESPACE_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_COMPRESS_WHITESPACE_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_COMPRESS_WHITESPACE_ID < 0 { if G_TRANSFORM_COMPRESS_WHITESPACE_ID < 0 {

@ -116,6 +116,7 @@ pub unsafe extern "C" fn SCDetectTransformDomainRegister() {
Transform: Some(domain_transform), Transform: Some(domain_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
unsafe { unsafe {
G_TRANSFORM_DOMAIN_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_DOMAIN_ID = SCDetectHelperTransformRegister(&kw);
@ -133,6 +134,7 @@ pub unsafe extern "C" fn SCDetectTransformDomainRegister() {
Transform: Some(tld_transform), Transform: Some(tld_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
unsafe { unsafe {
G_TRANSFORM_TLD_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_TLD_ID = SCDetectHelperTransformRegister(&kw);

@ -79,6 +79,7 @@ pub unsafe extern "C" fn DetectTransformDotPrefixRegister() {
Transform: Some(dot_prefix_transform), Transform: Some(dot_prefix_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
unsafe { unsafe {
G_TRANSFORM_DOT_PREFIX_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_DOT_PREFIX_ID = SCDetectHelperTransformRegister(&kw);

@ -84,6 +84,7 @@ pub unsafe extern "C" fn DetectTransformMd5Register() {
Transform: Some(md5_transform), Transform: Some(md5_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
G_TRANSFORM_MD5_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_MD5_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_MD5_ID < 0 { if G_TRANSFORM_MD5_ID < 0 {
@ -138,6 +139,7 @@ pub unsafe extern "C" fn DetectTransformSha1Register() {
Transform: Some(sha1_transform), Transform: Some(sha1_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
G_TRANSFORM_SHA1_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_SHA1_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_SHA1_ID < 0 { if G_TRANSFORM_SHA1_ID < 0 {
@ -192,6 +194,7 @@ pub unsafe extern "C" fn DetectTransformSha256Register() {
Transform: Some(sha256_transform), Transform: Some(sha256_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
G_TRANSFORM_SHA256_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_SHA256_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_SHA256_ID < 0 { if G_TRANSFORM_SHA256_ID < 0 {

@ -86,6 +86,7 @@ pub unsafe extern "C" fn DetectTransformHeaderLowercaseRegister() {
Transform: Some(header_lowertransform), Transform: Some(header_lowertransform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
G_TRANSFORM_HEADER_LOWER_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_HEADER_LOWER_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_HEADER_LOWER_ID < 0 { if G_TRANSFORM_HEADER_LOWER_ID < 0 {
@ -150,6 +151,7 @@ pub unsafe extern "C" fn DetectTransformStripPseudoHeadersRegister() {
Transform: Some(strip_pseudo_transform), Transform: Some(strip_pseudo_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
G_TRANSFORM_STRIP_PSEUDO_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_STRIP_PSEUDO_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_STRIP_PSEUDO_ID < 0 { if G_TRANSFORM_STRIP_PSEUDO_ID < 0 {

@ -93,6 +93,7 @@ pub unsafe extern "C" fn DetectTransformStripWhitespaceRegister() {
Transform: Some(strip_whitespace_transform), Transform: Some(strip_whitespace_transform),
Free: None, Free: None,
TransformValidate: Some(strip_whitespace_validate), TransformValidate: Some(strip_whitespace_validate),
TransformId: None,
}; };
unsafe { unsafe {
G_TRANSFORM_STRIP_WHITESPACE_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_STRIP_WHITESPACE_ID = SCDetectHelperTransformRegister(&kw);

@ -121,6 +121,7 @@ pub unsafe extern "C" fn DetectTransformUrlDecodeRegister() {
Transform: Some(url_decode_transform), Transform: Some(url_decode_transform),
Free: None, Free: None,
TransformValidate: None, TransformValidate: None,
TransformId: None,
}; };
G_TRANSFORM_URL_DECODE_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_URL_DECODE_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_URL_DECODE_ID < 0 { if G_TRANSFORM_URL_DECODE_ID < 0 {

@ -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)); 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] #[no_mangle]
pub unsafe extern "C" fn DetectTransformXorRegister() { pub unsafe extern "C" fn DetectTransformXorRegister() {
let kw = SCTransformTableElmt { let kw = SCTransformTableElmt {
@ -119,11 +129,12 @@ pub unsafe extern "C" fn DetectTransformXorRegister() {
Transform: Some(xor_transform), Transform: Some(xor_transform),
Free: Some(xor_free), Free: Some(xor_free),
TransformValidate: None, TransformValidate: None,
TransformId: Some(xor_id),
}; };
unsafe { unsafe {
G_TRANSFORM_XOR_ID = SCDetectHelperTransformRegister(&kw); G_TRANSFORM_XOR_ID = SCDetectHelperTransformRegister(&kw);
if G_TRANSFORM_XOR_ID < 0 { 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] #[test]
fn test_xor_transform() { fn test_xor_transform() {
let mut buf = Vec::new(); let mut buf = Vec::new();

@ -325,6 +325,13 @@ pub struct SCTransformTableElmt {
context: *mut ::std::os::raw::c_void, context: *mut ::std::os::raw::c_void,
) -> bool, ) -> 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" { extern "C" {
pub fn SCDetectHelperNewKeywordId() -> ::std::os::raw::c_int; pub fn SCDetectHelperNewKeywordId() -> ::std::os::raw::c_int;

@ -163,6 +163,8 @@ int SCDetectHelperTransformRegister(const SCTransformTableElmt *kw)
sigmatch_table[transform_id].Setup = sigmatch_table[transform_id].Setup =
(int (*)(DetectEngineCtx * de, Signature * s, const char *raw)) kw->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].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; return transform_id;
} }

@ -71,6 +71,7 @@ typedef struct SCTransformTableElmt {
void (*Free)(DetectEngineCtx *, void *); void (*Free)(DetectEngineCtx *, void *);
void (*Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context); void (*Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context);
bool (*TransformValidate)(const uint8_t *content, uint16_t content_len, 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; } SCTransformTableElmt;
int SCDetectHelperNewKeywordId(void); int SCDetectHelperNewKeywordId(void);

@ -984,12 +984,40 @@ int DetectBufferTypeMaxId(void)
return g_buffer_type_id; 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) static uint32_t DetectBufferTypeHashNameFunc(HashListTable *ht, void *data, uint16_t datalen)
{ {
const DetectBufferType *map = (DetectBufferType *)data; const DetectBufferType *map = (DetectBufferType *)data;
uint32_t hash = hashlittle_safe(map->name, strlen(map->name), 0); 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; hash %= ht->array_size;
SCLogDebug("map->name %s, hash %d", map->name, hash);
return hash; return hash;
} }
@ -1007,7 +1035,49 @@ static char DetectBufferTypeCompareNameFunc(void *data1, uint16_t len1, void *da
DetectBufferType *map2 = (DetectBufferType *)data2; DetectBufferType *map2 = (DetectBufferType *)data2;
char r = (strcmp(map1->name, map2->name) == 0); 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; return r;
} }
@ -1030,6 +1100,7 @@ static void DetectBufferTypeFreeFunc(void *data)
for (int i = 0; i < map->transforms.cnt; i++) { for (int i = 0; i < map->transforms.cnt; i++) {
if (map->transforms.transforms[i].options == NULL) if (map->transforms.transforms[i].options == NULL)
continue; continue;
if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) { if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) {
SCLogError("%s allocates transform option memory but has no free routine", SCLogError("%s allocates transform option memory but has no free routine",
sigmatch_table[map->transforms.transforms[i].transform].name); sigmatch_table[map->transforms.transforms[i].transform].name);
@ -1561,6 +1632,11 @@ int DetectEngineBufferTypeGetByIdTransforms(
memset(&lookup_map, 0, sizeof(lookup_map)); memset(&lookup_map, 0, sizeof(lookup_map));
strlcpy(lookup_map.name, base_map->name, sizeof(lookup_map.name)); strlcpy(lookup_map.name, base_map->name, sizeof(lookup_map.name));
lookup_map.transforms = t; 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); DetectBufferType *res = HashListTableLookup(de_ctx->buffer_type_hash_name, &lookup_map, 0);
SCLogDebug("res %p", res); SCLogDebug("res %p", res);

@ -37,33 +37,28 @@
#include "util-unittest.h" #include "util-unittest.h"
#include "util-print.h" #include "util-print.h"
static int DetectTransformFromBase64DecodeSetup(DetectEngineCtx *, Signature *, const char *);
static void DetectTransformFromBase64DecodeFree(DetectEngineCtx *, void *);
#ifdef UNITTESTS #ifdef UNITTESTS
#define DETECT_TRANSFORM_FROM_BASE64_MODE_DEFAULT (uint8_t) SCBase64ModeRFC4648 #define DETECT_TRANSFORM_FROM_BASE64_MODE_DEFAULT (uint8_t) SCBase64ModeRFC4648
static void DetectTransformFromBase64DecodeRegisterTests(void); static void DetectTransformFromBase64DecodeRegisterTests(void);
#endif #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"; if (context) {
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].desc = "convert the base64 decode of the buffer"; SCDetectTransformFromBase64Data *b64d = (SCDetectTransformFromBase64Data *)context;
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].url = "/rules/transforms.html#from_base64"; /* Since the context structure contains the unique values for the keyword usage,
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Setup = DetectTransformFromBase64DecodeSetup; * a pointer to the context structure is returned.
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Transform = TransformFromBase64Decode; */
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].Free = DetectTransformFromBase64DecodeFree; *data = (const uint8_t *)b64d;
#ifdef UNITTESTS *length = sizeof(*b64d);
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].RegisterTests = }
DetectTransformFromBase64DecodeRegisterTests;
#endif
sigmatch_table[DETECT_TRANSFORM_FROM_BASE64].flags |= SIGMATCH_OPTIONAL_OPT;
} }
static void DetectTransformFromBase64DecodeFree(DetectEngineCtx *de_ctx, void *ptr) static void DetectTransformFromBase64DecodeFree(DetectEngineCtx *de_ctx, void *ptr)
{ {
SCTransformBase64Free(ptr); if (ptr) {
SCTransformBase64Free(ptr);
}
} }
static SCDetectTransformFromBase64Data *DetectTransformFromBase64DecodeParse(const char *str) 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 #ifdef UNITTESTS
/* Simple success case -- check buffer */ /* Simple success case -- check buffer */
static int DetectTransformFromBase64DecodeTest01(void) static int DetectTransformFromBase64DecodeTest01(void)

@ -34,6 +34,8 @@
typedef struct DetectTransformPcrexformData { typedef struct DetectTransformPcrexformData {
pcre2_code *regex; pcre2_code *regex;
pcre2_match_context *context; pcre2_match_context *context;
uint8_t *id_data;
uint32_t id_data_len;
} DetectTransformPcrexformData; } DetectTransformPcrexformData;
static int DetectTransformPcrexformSetup (DetectEngineCtx *, Signature *, const char *); static int DetectTransformPcrexformSetup (DetectEngineCtx *, Signature *, const char *);
@ -44,6 +46,15 @@ static void DetectTransformPcrexform(
void DetectTransformPcrexformRegisterTests (void); void DetectTransformPcrexformRegisterTests (void);
#endif #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) void DetectTransformPcrexformRegister(void)
{ {
sigmatch_table[DETECT_TRANSFORM_PCREXFORM].name = "pcrexform"; 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].url = "/rules/transforms.html#pcre-xform";
sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Transform = sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Transform =
DetectTransformPcrexform; DetectTransformPcrexform;
sigmatch_table[DETECT_TRANSFORM_PCREXFORM].TransformId = DetectTransformPcrexformId;
sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Free = sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Free =
DetectTransformPcrexformFree; DetectTransformPcrexformFree;
sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Setup = sigmatch_table[DETECT_TRANSFORM_PCREXFORM].Setup =
@ -66,8 +78,11 @@ static void DetectTransformPcrexformFree(DetectEngineCtx *de_ctx, void *ptr)
{ {
if (ptr != NULL) { if (ptr != NULL) {
DetectTransformPcrexformData *pxd = (DetectTransformPcrexformData *) ptr; DetectTransformPcrexformData *pxd = (DetectTransformPcrexformData *) ptr;
pcre2_match_context_free(pxd->context); pcre2_match_context_free(pxd->context);
pcre2_code_free(pxd->regex); pcre2_code_free(pxd->regex);
SCFree(pxd->id_data);
SCFree(pxd); SCFree(pxd);
} }
} }
@ -112,6 +127,7 @@ static int DetectTransformPcrexformSetup (DetectEngineCtx *de_ctx, Signature *s,
SCFree(pxd); SCFree(pxd);
SCReturnInt(-1); SCReturnInt(-1);
} }
// check pcd->regex has exactly one capture expression // check pcd->regex has exactly one capture expression
uint32_t nb; uint32_t nb;
if (pcre2_pattern_info(pxd->regex, PCRE2_INFO_CAPTURECOUNT, &nb) < 0) { 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); 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); int r = SCDetectSignatureAddTransform(s, DETECT_TRANSFORM_PCREXFORM, pxd);
if (r != 0) { if (r != 0) {
DetectTransformPcrexformFree(de_ctx, pxd); DetectTransformPcrexformFree(de_ctx, pxd);

@ -438,6 +438,11 @@ typedef struct DetectEngineAppInspectionEngine_ {
struct DetectEngineAppInspectionEngine_ *next; struct DetectEngineAppInspectionEngine_ *next;
} DetectEngineAppInspectionEngine; } DetectEngineAppInspectionEngine;
typedef struct TransformIdData_ {
const uint8_t *id_data;
uint32_t id_data_len;
} TransformIdData;
typedef struct DetectBufferType_ { typedef struct DetectBufferType_ {
char name[64]; char name[64];
char description[128]; char description[128];
@ -452,6 +457,7 @@ typedef struct DetectBufferType_ {
bool (*ValidateCallback)( bool (*ValidateCallback)(
const struct Signature_ *, const char **sigerror, const struct DetectBufferType_ *); const struct Signature_ *, const char **sigerror, const struct DetectBufferType_ *);
DetectEngineTransforms transforms; DetectEngineTransforms transforms;
TransformIdData xform_id[DETECT_TRANSFORMS_MAX];
} DetectBufferType; } DetectBufferType;
struct DetectEnginePktInspectionEngine; struct DetectEnginePktInspectionEngine;
@ -1386,6 +1392,9 @@ typedef struct SigTableElmt_ {
void (*Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context); void (*Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context);
bool (*TransformValidate)(const uint8_t *content, uint16_t content_len, 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 */ /** keyword setup function pointer */
int (*Setup)(DetectEngineCtx *, Signature *, const char *); int (*Setup)(DetectEngineCtx *, Signature *, const char *);

Loading…
Cancel
Save