|
|
|
|
@ -17,7 +17,7 @@
|
|
|
|
|
|
|
|
|
|
use crate::detect::uint::detect_parse_uint_with_unit;
|
|
|
|
|
use crate::detect::SIGMATCH_OPTIONAL_OPT;
|
|
|
|
|
use flate2::bufread::GzDecoder;
|
|
|
|
|
use flate2::bufread::{GzDecoder, ZlibDecoder};
|
|
|
|
|
use suricata_sys::sys::{
|
|
|
|
|
DetectEngineCtx, DetectEngineThreadCtx, InspectionBuffer, SCDetectHelperTransformRegister,
|
|
|
|
|
SCDetectSignatureAddTransform, SCInspectionBufferCheckAndExpand, SCInspectionBufferTruncate,
|
|
|
|
|
@ -29,6 +29,7 @@ use std::io::Read;
|
|
|
|
|
use std::os::raw::{c_int, c_void};
|
|
|
|
|
|
|
|
|
|
static mut G_TRANSFORM_GUNZIP_ID: c_int = 0;
|
|
|
|
|
static mut G_TRANSFORM_ZLIB_DEFLATE_ID: c_int = 0;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
|
struct DetectTransformDecompressData {
|
|
|
|
|
@ -37,7 +38,7 @@ struct DetectTransformDecompressData {
|
|
|
|
|
|
|
|
|
|
const DEFAULT_MAX_SIZE: u32 = 1024;
|
|
|
|
|
// 16 MiB
|
|
|
|
|
const ABSOLUTE_MAX_SIZE: u32 = 16*1024*1024;
|
|
|
|
|
const ABSOLUTE_MAX_SIZE: u32 = 16 * 1024 * 1024;
|
|
|
|
|
|
|
|
|
|
fn decompress_parse_do(s: &str) -> Option<DetectTransformDecompressData> {
|
|
|
|
|
let mut max_size_parsed = None;
|
|
|
|
|
@ -121,8 +122,10 @@ fn gunzip_transform_do(input: &[u8], output: &mut [u8]) -> Option<u32> {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe extern "C" fn gunzip_transform(
|
|
|
|
|
_det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, ctx: *mut c_void,
|
|
|
|
|
pub type DecompressFn = fn(input: &[u8], output: &mut [u8]) -> Option<u32>;
|
|
|
|
|
|
|
|
|
|
unsafe fn decompress_transform(
|
|
|
|
|
buffer: *mut InspectionBuffer, ctx: &DetectTransformDecompressData, decompress_fn: DecompressFn,
|
|
|
|
|
) {
|
|
|
|
|
let input = (*buffer).inspect;
|
|
|
|
|
let input_len = (*buffer).inspect_len;
|
|
|
|
|
@ -130,8 +133,6 @@ unsafe extern "C" fn gunzip_transform(
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let input = build_slice!(input, input_len as usize);
|
|
|
|
|
let ctx = cast_pointer!(ctx, DetectTransformDecompressData);
|
|
|
|
|
|
|
|
|
|
let output = SCInspectionBufferCheckAndExpand(buffer, ctx.max_size);
|
|
|
|
|
if output.is_null() {
|
|
|
|
|
// allocation failure
|
|
|
|
|
@ -150,7 +151,7 @@ unsafe extern "C" fn gunzip_transform(
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// this succeeds if decompressed data > max_size, but we get nb = max_size
|
|
|
|
|
if let Some(nb) = gunzip_transform_do(input, buf) {
|
|
|
|
|
if let Some(nb) = decompress_fn(input, buf) {
|
|
|
|
|
SCInspectionBufferTruncate(buffer, nb);
|
|
|
|
|
} else {
|
|
|
|
|
// decompression failure
|
|
|
|
|
@ -158,6 +159,13 @@ unsafe extern "C" fn gunzip_transform(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe extern "C" fn gunzip_transform(
|
|
|
|
|
_det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, ctx: *mut c_void,
|
|
|
|
|
) {
|
|
|
|
|
let ctx = cast_pointer!(ctx, DetectTransformDecompressData);
|
|
|
|
|
decompress_transform(buffer, ctx, gunzip_transform_do);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe extern "C" fn decompress_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) {
|
|
|
|
|
std::mem::drop(Box::from_raw(ctx as *mut DetectTransformDecompressData));
|
|
|
|
|
}
|
|
|
|
|
@ -171,6 +179,35 @@ unsafe extern "C" fn decompress_id(data: *mut *const u8, length: *mut u32, ctx:
|
|
|
|
|
*length = std::mem::size_of::<DetectTransformDecompressData>() as u32; // 4
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe extern "C" fn zlib_deflate_setup(
|
|
|
|
|
de: *mut DetectEngineCtx, s: *mut Signature, opt_str: *const std::os::raw::c_char,
|
|
|
|
|
) -> c_int {
|
|
|
|
|
let ctx = decompress_parse(opt_str);
|
|
|
|
|
if ctx.is_null() {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
let r = SCDetectSignatureAddTransform(s, G_TRANSFORM_ZLIB_DEFLATE_ID, ctx);
|
|
|
|
|
if r != 0 {
|
|
|
|
|
decompress_free(de, ctx);
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn zlib_deflate_transform_do(input: &[u8], output: &mut [u8]) -> Option<u32> {
|
|
|
|
|
let mut gz = ZlibDecoder::new(input);
|
|
|
|
|
return match gz.read(output) {
|
|
|
|
|
Ok(n) => Some(n as u32),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe extern "C" fn zlib_deflate_transform(
|
|
|
|
|
_det: *mut DetectEngineThreadCtx, buffer: *mut InspectionBuffer, ctx: *mut c_void,
|
|
|
|
|
) {
|
|
|
|
|
let ctx = cast_pointer!(ctx, DetectTransformDecompressData);
|
|
|
|
|
decompress_transform(buffer, ctx, zlib_deflate_transform_do);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
|
pub unsafe extern "C" fn DetectTransformGunzipRegister() {
|
|
|
|
|
let kw = SCTransformTableElmt {
|
|
|
|
|
@ -192,6 +229,27 @@ pub unsafe extern "C" fn DetectTransformGunzipRegister() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
|
pub unsafe extern "C" fn DetectTransformZlibDeflateRegister() {
|
|
|
|
|
let kw = SCTransformTableElmt {
|
|
|
|
|
name: b"zlib_deflate\0".as_ptr() as *const libc::c_char,
|
|
|
|
|
desc: b"modify buffer via zlib decompression\0".as_ptr() as *const libc::c_char,
|
|
|
|
|
url: b"/rules/transforms.html#zlib_deflate\0".as_ptr() as *const libc::c_char,
|
|
|
|
|
Setup: Some(zlib_deflate_setup),
|
|
|
|
|
flags: SIGMATCH_OPTIONAL_OPT,
|
|
|
|
|
Transform: Some(zlib_deflate_transform),
|
|
|
|
|
Free: Some(decompress_free),
|
|
|
|
|
TransformValidate: None,
|
|
|
|
|
TransformId: Some(decompress_id),
|
|
|
|
|
};
|
|
|
|
|
unsafe {
|
|
|
|
|
G_TRANSFORM_ZLIB_DEFLATE_ID = SCDetectHelperTransformRegister(&kw);
|
|
|
|
|
if G_TRANSFORM_ZLIB_DEFLATE_ID < 0 {
|
|
|
|
|
SCLogWarning!("Failed registering transform zlib_deflate");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|