From 967b23a81c61ce7c60b284feb216ab1826853be6 Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Thu, 22 Jul 2021 15:15:36 +0300 Subject: [PATCH] Set and get configuration (#35) feat: add set and get configuration Co-authored-by: Ivan Krivosheev --- src/internals/configuration.rs | 52 ++++++++++++ src/internals/mod.rs | 23 +++--- src/internals/scan.rs | 3 +- src/lib.rs | 30 ++++--- src/scanner.rs | 7 +- tests/tests.rs | 9 ++- yara-sys/bindings/yara-4.1.1-unix.rs | 99 +++++++++++++++++------ yara-sys/bindings/yara-4.1.1-windows.rs | 103 +++++++++++++++++++++++- yara-sys/build.rs | 3 + 9 files changed, 280 insertions(+), 49 deletions(-) create mode 100644 src/internals/configuration.rs diff --git a/src/internals/configuration.rs b/src/internals/configuration.rs new file mode 100644 index 0000000..77311d2 --- /dev/null +++ b/src/internals/configuration.rs @@ -0,0 +1,52 @@ +use std::ffi::c_void; + +use yara_sys; + +use crate::errors::*; + +/// A `ConfigName` is enum of available configuration options +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ConfigName { + /// Stack size to use for YR_CONFIG_STACK_SIZE + StackSize, + /// Maximum number of strings to allow per yara rule. Will be mapped to YR_CONFIG_MAX_STRINGS_PER_RULE + MaxStringsPerRule, + /// Maximum number of bytes to allow per yara match. Will be mapped to YR_CONFIG_MAX_MATCH_DATA + MaxMatchData, +} + +#[cfg(unix)] +type EnumType = u32; +#[cfg(windows)] +type EnumType = i32; + +impl ConfigName { + pub fn to_yara(&self) -> EnumType { + use self::ConfigName::*; + let res = match self { + StackSize => yara_sys::_YR_CONFIG_NAME_YR_CONFIG_STACK_SIZE, + MaxStringsPerRule => yara_sys::_YR_CONFIG_NAME_YR_CONFIG_MAX_STRINGS_PER_RULE, + MaxMatchData => yara_sys::_YR_CONFIG_NAME_YR_CONFIG_MAX_MATCH_DATA, + }; + res as EnumType + } +} + +pub fn set_configuration(name: ConfigName, value: u32) -> Result<(), YaraError> { + let result = unsafe { + yara_sys::yr_set_configuration(name.to_yara(), &value as *const u32 as *mut c_void) + }; + + yara_sys::Error::from_code(result).map_err(Into::into) +} + +pub fn get_configuration(name: ConfigName) -> Result { + let value: u32 = 0; + let result = unsafe { + yara_sys::yr_get_configuration(name.to_yara(), &value as *const u32 as *mut c_void) + }; + + yara_sys::Error::from_code(result) + .map_err(Into::into) + .map(|_| value) +} diff --git a/src/internals/mod.rs b/src/internals/mod.rs index 80bf340..1e24b6b 100644 --- a/src/internals/mod.rs +++ b/src/internals/mod.rs @@ -1,22 +1,25 @@ +use std::sync::Mutex; + +use lazy_static::lazy_static; +pub use yara_sys; + +use crate::errors::*; + +pub use self::compiler::*; +pub use self::configuration::*; +pub use self::rules::*; +pub use self::scan::*; + pub mod matches; pub mod meta; pub mod string; mod compiler; +mod configuration; mod rules; mod scan; mod stream; -pub use self::compiler::*; -pub use self::rules::*; -pub use self::scan::*; - -use std::sync::Mutex; - -use lazy_static::lazy_static; - -use crate::errors::*; - lazy_static! { static ref INIT_MUTEX: Mutex<()> = Mutex::new(()); } diff --git a/src/internals/scan.rs b/src/internals/scan.rs index 9ec79c2..71d8d32 100644 --- a/src/internals/scan.rs +++ b/src/internals/scan.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use std::ffi::{CStr, CString}; use std::fs::File; use std::os::raw::c_void; @@ -5,11 +6,11 @@ use std::os::raw::c_void; use std::os::unix::io::AsRawFd; #[cfg(windows)] use std::os::windows::io::AsRawHandle; + use yara_sys::{YR_SCANNER, YR_SCAN_CONTEXT}; use crate::errors::*; use crate::Rule; -use std::convert::TryInto; #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum CallbackMsg { diff --git a/src/lib.rs b/src/lib.rs index 22a4da1..f1e19b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,17 @@ //! [Yara-doc]: https://yara.readthedocs.io/en/stable/gettingstarted.html //! [polydet]: https://github.com/Polydet/polydet/ +pub use internals::ConfigName; +use internals::{get_configuration, set_configuration}; + +pub use crate::compiler::Compiler; +pub use crate::errors::*; +use crate::initialize::InitializationToken; +pub use crate::matches::Match; +pub use crate::rules::*; +pub use crate::scanner::Scanner; +pub use crate::string::YrString; + mod compiler; mod initialize; mod internals; @@ -55,15 +66,6 @@ mod string; pub mod errors; -use crate::initialize::InitializationToken; - -pub use crate::compiler::Compiler; -pub use crate::errors::*; -pub use crate::matches::Match; -pub use crate::rules::*; -pub use crate::scanner::Scanner; -pub use crate::string::YrString; - /// Yara initialization token. /// /// Act as an initialization token to keep the library initialized. @@ -134,6 +136,16 @@ impl Yara { InitializationToken::new().map(|token| Yara { _token: token }) } + /// Set the configuration variable + pub fn set_configuration(&self, name: ConfigName, value: u32) -> Result<(), YaraError> { + set_configuration(name, value) + } + + /// Get the configuration variable + pub fn get_configuration(&self, name: ConfigName) -> Result { + get_configuration(name) + } + /// Create and initialize the library. #[deprecated = "Use new"] pub fn create() -> Result { diff --git a/src/scanner.rs b/src/scanner.rs index 5b7990c..d228445 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -322,7 +322,12 @@ mod test { let bytes = if cfg!(windows) { // the string is in utf-16 format, filter out the zeroes. - string.matches[0].data.clone().into_iter().filter(|v| *v != 0).collect() + string.matches[0] + .data + .clone() + .into_iter() + .filter(|v| *v != 0) + .collect() } else { string.matches[0].data.clone() }; diff --git a/tests/tests.rs b/tests/tests.rs index d758822..0979270 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,6 +1,6 @@ extern crate yara; -use yara::{CompileErrorLevel, Compiler, Error, Metadata, MetadataValue, Rules, Yara}; +use yara::{CompileErrorLevel, Compiler, ConfigName, Error, Metadata, MetadataValue, Rules, Yara}; const RULES: &str = r#" rule is_awesome { @@ -42,6 +42,13 @@ fn test_initialize() { assert!(Yara::new().is_ok()); } +#[test] +fn test_configuration() { + let yara = Yara::new().expect("Should be Ok"); + assert_eq!(Ok(()), yara.set_configuration(ConfigName::StackSize, 100)); + assert_eq!(Ok(100), yara.get_configuration(ConfigName::StackSize)); +} + #[test] fn test_create_compiler() { assert!(Compiler::new().is_ok()); diff --git a/yara-sys/bindings/yara-4.1.1-unix.rs b/yara-sys/bindings/yara-4.1.1-unix.rs index 25730e4..5876fde 100644 --- a/yara-sys/bindings/yara-4.1.1-unix.rs +++ b/yara-sys/bindings/yara-4.1.1-unix.rs @@ -96,22 +96,57 @@ pub type __time_t = ::std::os::raw::c_long; pub type __suseconds_t = ::std::os::raw::c_long; pub type __syscall_slong_t = ::std::os::raw::c_long; pub type FILE = _IO_FILE; +pub type _IO_lock_t = ::std::os::raw::c_void; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _IO_marker { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IO_codecvt { - _unused: [u8; 0], + pub _next: *mut _IO_marker, + pub _sbuf: *mut _IO_FILE, + pub _pos: ::std::os::raw::c_int, } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IO_wide_data { - _unused: [u8; 0], +#[test] +fn bindgen_test_layout__IO_marker() { + assert_eq!( + ::std::mem::size_of::<_IO_marker>(), + 24usize, + concat!("Size of: ", stringify!(_IO_marker)) + ); + assert_eq!( + ::std::mem::align_of::<_IO_marker>(), + 8usize, + concat!("Alignment of ", stringify!(_IO_marker)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_IO_marker>()))._next as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(_IO_marker), + "::", + stringify!(_next) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_IO_marker>()))._sbuf as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_IO_marker), + "::", + stringify!(_sbuf) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_IO_marker>()))._pos as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_IO_marker), + "::", + stringify!(_pos) + ) + ); } -pub type _IO_lock_t = ::std::os::raw::c_void; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _IO_FILE { @@ -137,10 +172,10 @@ pub struct _IO_FILE { pub _shortbuf: [::std::os::raw::c_char; 1usize], pub _lock: *mut _IO_lock_t, pub _offset: __off64_t, - pub _codecvt: *mut _IO_codecvt, - pub _wide_data: *mut _IO_wide_data, - pub _freeres_list: *mut _IO_FILE, - pub _freeres_buf: *mut ::std::os::raw::c_void, + pub __pad1: *mut ::std::os::raw::c_void, + pub __pad2: *mut ::std::os::raw::c_void, + pub __pad3: *mut ::std::os::raw::c_void, + pub __pad4: *mut ::std::os::raw::c_void, pub __pad5: size_t, pub _mode: ::std::os::raw::c_int, pub _unused2: [::std::os::raw::c_char; 20usize], @@ -378,43 +413,43 @@ fn bindgen_test_layout__IO_FILE() { ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._codecvt as *const _ as usize }, + unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad1 as *const _ as usize }, 152usize, concat!( "Offset of field: ", stringify!(_IO_FILE), "::", - stringify!(_codecvt) + stringify!(__pad1) ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._wide_data as *const _ as usize }, + unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad2 as *const _ as usize }, 160usize, concat!( "Offset of field: ", stringify!(_IO_FILE), "::", - stringify!(_wide_data) + stringify!(__pad2) ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._freeres_list as *const _ as usize }, + unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad3 as *const _ as usize }, 168usize, concat!( "Offset of field: ", stringify!(_IO_FILE), "::", - stringify!(_freeres_list) + stringify!(__pad3) ) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<_IO_FILE>()))._freeres_buf as *const _ as usize }, + unsafe { &(*(::std::ptr::null::<_IO_FILE>())).__pad4 as *const _ as usize }, 176usize, concat!( "Offset of field: ", stringify!(_IO_FILE), "::", - stringify!(_freeres_buf) + stringify!(__pad4) ) ); assert_eq!( @@ -3608,12 +3643,30 @@ extern "C" { rules: *mut *mut YR_RULES, ) -> ::std::os::raw::c_int; } +pub const _YR_CONFIG_NAME_YR_CONFIG_STACK_SIZE: _YR_CONFIG_NAME = 0; +pub const _YR_CONFIG_NAME_YR_CONFIG_MAX_STRINGS_PER_RULE: _YR_CONFIG_NAME = 1; +pub const _YR_CONFIG_NAME_YR_CONFIG_MAX_MATCH_DATA: _YR_CONFIG_NAME = 2; +pub const _YR_CONFIG_NAME_YR_CONFIG_LAST: _YR_CONFIG_NAME = 3; +pub type _YR_CONFIG_NAME = ::std::os::raw::c_uint; +pub use self::_YR_CONFIG_NAME as YR_CONFIG_NAME; extern "C" { pub fn yr_initialize() -> ::std::os::raw::c_int; } extern "C" { pub fn yr_finalize() -> ::std::os::raw::c_int; } +extern "C" { + pub fn yr_set_configuration( + arg1: YR_CONFIG_NAME, + arg2: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn yr_get_configuration( + arg1: YR_CONFIG_NAME, + arg2: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} pub type YR_SCANNER = YR_SCAN_CONTEXT; extern "C" { pub fn yr_scanner_create( diff --git a/yara-sys/bindings/yara-4.1.1-windows.rs b/yara-sys/bindings/yara-4.1.1-windows.rs index c382dd4..4083512 100644 --- a/yara-sys/bindings/yara-4.1.1-windows.rs +++ b/yara-sys/bindings/yara-4.1.1-windows.rs @@ -2732,13 +2732,20 @@ pub type size_t = ::std::os::raw::c_ulonglong; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _iobuf { - pub _Placeholder: *mut ::std::os::raw::c_void, + pub _ptr: *mut ::std::os::raw::c_char, + pub _cnt: ::std::os::raw::c_int, + pub _base: *mut ::std::os::raw::c_char, + pub _flag: ::std::os::raw::c_int, + pub _file: ::std::os::raw::c_int, + pub _charbuf: ::std::os::raw::c_int, + pub _bufsiz: ::std::os::raw::c_int, + pub _tmpfname: *mut ::std::os::raw::c_char, } #[test] fn bindgen_test_layout__iobuf() { assert_eq!( ::std::mem::size_of::<_iobuf>(), - 8usize, + 48usize, concat!("Size of: ", stringify!(_iobuf)) ); assert_eq!( @@ -2747,13 +2754,83 @@ fn bindgen_test_layout__iobuf() { concat!("Alignment of ", stringify!(_iobuf)) ); assert_eq!( - unsafe { &(*(::std::ptr::null::<_iobuf>()))._Placeholder as *const _ as usize }, + unsafe { &(*(::std::ptr::null::<_iobuf>()))._ptr as *const _ as usize }, 0usize, concat!( "Offset of field: ", stringify!(_iobuf), "::", - stringify!(_Placeholder) + stringify!(_ptr) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._cnt as *const _ as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_cnt) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._base as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_base) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._flag as *const _ as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_flag) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._file as *const _ as usize }, + 28usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_file) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._charbuf as *const _ as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_charbuf) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._bufsiz as *const _ as usize }, + 36usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_bufsiz) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::<_iobuf>()))._tmpfname as *const _ as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(_iobuf), + "::", + stringify!(_tmpfname) ) ); } @@ -5949,12 +6026,30 @@ extern "C" { rules: *mut *mut YR_RULES, ) -> ::std::os::raw::c_int; } +pub const _YR_CONFIG_NAME_YR_CONFIG_STACK_SIZE: _YR_CONFIG_NAME = 0; +pub const _YR_CONFIG_NAME_YR_CONFIG_MAX_STRINGS_PER_RULE: _YR_CONFIG_NAME = 1; +pub const _YR_CONFIG_NAME_YR_CONFIG_MAX_MATCH_DATA: _YR_CONFIG_NAME = 2; +pub const _YR_CONFIG_NAME_YR_CONFIG_LAST: _YR_CONFIG_NAME = 3; +pub type _YR_CONFIG_NAME = ::std::os::raw::c_int; +pub use self::_YR_CONFIG_NAME as YR_CONFIG_NAME; extern "C" { pub fn yr_initialize() -> ::std::os::raw::c_int; } extern "C" { pub fn yr_finalize() -> ::std::os::raw::c_int; } +extern "C" { + pub fn yr_set_configuration( + arg1: YR_CONFIG_NAME, + arg2: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn yr_get_configuration( + arg1: YR_CONFIG_NAME, + arg2: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int; +} pub type YR_SCANNER = YR_SCAN_CONTEXT; extern "C" { pub fn yr_scanner_create( diff --git a/yara-sys/build.rs b/yara-sys/build.rs index 3166a47..9d144c7 100644 --- a/yara-sys/build.rs +++ b/yara-sys/build.rs @@ -195,6 +195,9 @@ mod bindings { .allowlist_var("STRING_FLAGS_LAST_IN_RULE") .allowlist_var("YARA_ERROR_LEVEL_.*") .allowlist_var("SCAN_FLAGS_.*") + .allowlist_var("YR_CONFIG_.*") + .allowlist_function("yr_set_configuration") + .allowlist_function("yr_get_configuration") .allowlist_function("yr_initialize") .allowlist_function("yr_finalize") .allowlist_function("yr_finalize_thread")