From: Philippe Antoine Date: Sat, 30 Dec 2023 20:46:54 +0000 (+0100) Subject: detect: integer keywords now accept bitmasks X-Git-Tag: suricata-8.0.0-beta1~1807 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d05f3ac791c25f789040e677cfa09c7e3fad7d60;p=thirdparty%2Fsuricata.git detect: integer keywords now accept bitmasks Ticket: 6648 Like &0x40=0x40 to test for a specific bit set --- diff --git a/rust/src/detect/uint.rs b/rust/src/detect/uint.rs index fd6079a536..7ce86d57f3 100644 --- a/rust/src/detect/uint.rs +++ b/rust/src/detect/uint.rs @@ -38,6 +38,8 @@ pub enum DetectUintMode { DetectUintModeRange, DetectUintModeNe, DetectUintModeNegRg, + DetectUintModeBitmask, + DetectUintModeNegBitmask, } #[derive(Debug)] @@ -173,6 +175,37 @@ pub fn detect_parse_uint_start_interval( )) } +pub fn detect_parse_uint_bitmask( + i: &str, +) -> IResult<&str, DetectUintData> { + let (i, _) = opt(is_a(" "))(i)?; + let (i, _) = tag("&")(i)?; + let (i, _) = opt(is_a(" "))(i)?; + let (i, arg1) = detect_parse_uint_value(i)?; + let (i, _) = opt(is_a(" "))(i)?; + let (i, neg) = opt(tag("!"))(i)?; + let (i, _) = tag("=")(i)?; + let (i, _) = opt(is_a(" "))(i)?; + let (i, arg2) = detect_parse_uint_value(i)?; + if arg2 & arg1 != arg2 { + // could never match + return Err(Err::Error(make_error(i, ErrorKind::Verify))); + } + let mode = if neg.is_none() { + DetectUintMode::DetectUintModeBitmask + } else { + DetectUintMode::DetectUintModeNegBitmask + }; + Ok(( + i, + DetectUintData { + arg1, + arg2, + mode, + }, + )) +} + fn detect_parse_uint_start_interval_inclusive( i: &str, ) -> IResult<&str, DetectUintData> { @@ -298,6 +331,16 @@ pub fn detect_match_uint(x: &DetectUintData, val: T) -> boo return true; } } + DetectUintMode::DetectUintModeBitmask => { + if val & x.arg1 == x.arg2 { + return true; + } + } + DetectUintMode::DetectUintModeNegBitmask => { + if val & x.arg1 != x.arg2 { + return true; + } + } } return false; } @@ -305,6 +348,7 @@ pub fn detect_match_uint(x: &DetectUintData, val: T) -> boo pub fn detect_parse_uint_notending(i: &str) -> IResult<&str, DetectUintData> { let (i, _) = opt(is_a(" "))(i)?; let (i, uint) = alt(( + detect_parse_uint_bitmask, detect_parse_uint_start_interval, detect_parse_uint_start_equal, detect_parse_uint_start_symbol, @@ -487,6 +531,24 @@ mod tests { assert_eq!(ctx.mode, DetectUintMode::DetectUintModeGt); } + #[test] + fn test_parse_uint_bitmask() { + let (_, val) = detect_parse_uint::("&0x40!=0").unwrap(); + assert_eq!(val.arg1, 0x40); + assert_eq!(val.arg2, 0); + assert_eq!(val.mode, DetectUintMode::DetectUintModeNegBitmask); + assert!(!detect_match_uint(&val, 0xBF)); + assert!(detect_match_uint(&val, 0x40)); + let (_, val) = detect_parse_uint::("&0xc0=0x80").unwrap(); + assert_eq!(val.arg1, 0xc0); + assert_eq!(val.arg2, 0x80); + assert_eq!(val.mode, DetectUintMode::DetectUintModeBitmask); + assert!(detect_match_uint(&val, 0x80)); + assert!(!detect_match_uint(&val, 0x40)); + assert!(!detect_match_uint(&val, 0xc0)); + // could never match + assert!(detect_parse_uint::("&0xc0=12").is_err()); + } #[test] fn test_parse_uint_hex() { let (_, val) = detect_parse_uint::("0x100").unwrap();