]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: integer keywords now accept bitmasks
authorPhilippe Antoine <pantoine@oisf.net>
Sat, 30 Dec 2023 20:46:54 +0000 (21:46 +0100)
committerVictor Julien <victor@inliniac.net>
Tue, 30 Jan 2024 08:35:17 +0000 (09:35 +0100)
Ticket: 6648

Like &0x40=0x40 to test for a specific bit set

rust/src/detect/uint.rs

index fd6079a53635ef61e08abe525827741834aa22ee..7ce86d57f3e2bd58950d5ce95c3773021f59c387 100644 (file)
@@ -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<T: DetectIntType>(
     ))
 }
 
+pub fn detect_parse_uint_bitmask<T: DetectIntType>(
+    i: &str,
+) -> IResult<&str, DetectUintData<T>> {
+    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<T: DetectIntType>(
     i: &str,
 ) -> IResult<&str, DetectUintData<T>> {
@@ -298,6 +331,16 @@ pub fn detect_match_uint<T: DetectIntType>(x: &DetectUintData<T>, 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<T: DetectIntType>(x: &DetectUintData<T>, val: T) -> boo
 pub fn detect_parse_uint_notending<T: DetectIntType>(i: &str) -> IResult<&str, DetectUintData<T>> {
     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::<u64>("&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::<u64>("&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::<u64>("&0xc0=12").is_err());
+    }
     #[test]
     fn test_parse_uint_hex() {
         let (_, val) = detect_parse_uint::<u64>("0x100").unwrap();