From 717b826d256a021bfd52991e1ec654779f05c3e5 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 20 Jun 2017 12:47:34 -0600 Subject: [PATCH] rust: safe string handling in logging In logging (SCLog*), safely convert strings to cstrings instead of blindly unwrapping them. Also implement a simple rust logger if the Suricata C context is not available. --- rust/src/core.rs | 19 +-------------- rust/src/log.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/rust/src/core.rs b/rust/src/core.rs index e3647673c6..98d37afcdc 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -105,7 +105,7 @@ pub type SCFileSetTx = extern "C" fn ( #[allow(non_snake_case)] #[repr(C)] pub struct SuricataContext { - SCLogMessage: SCLogMessageFunc, + pub SCLogMessage: SCLogMessageFunc, DetectEngineStateFree: DetectEngineStateFreeFunc, AppLayerDecoderEventsSetEventRaw: AppLayerDecoderEventsSetEventRawFunc, AppLayerDecoderEventsFreeEvents: AppLayerDecoderEventsFreeEventsFunc, @@ -135,23 +135,6 @@ pub extern "C" fn rs_init(context: &'static mut SuricataContext) } } -/// SCLogMessage wrapper. -pub fn sc_log_message(level: libc::c_int, - filename: *const libc::c_char, - line: libc::c_uint, - function: *const libc::c_char, - code: libc::c_int, - message: *const libc::c_char) -> libc::c_int -{ - unsafe { - if let Some(c) = SC { - return (c.SCLogMessage)(level, filename, line, function, - code, message); - } - } - return 0; -} - /// DetectEngineStateFree wrapper. pub fn sc_detect_engine_state_free(state: *mut DetectEngineState) { diff --git a/rust/src/log.rs b/rust/src/log.rs index 19b78cf6c3..ec09f812a2 100644 --- a/rust/src/log.rs +++ b/rust/src/log.rs @@ -17,11 +17,12 @@ extern crate libc; -use std::ffi::{CString}; +use std::ffi::CString; use std::path::Path; use core::*; +#[derive(Debug)] pub enum Level { NotSet = -1, None = 0, @@ -59,12 +60,12 @@ pub fn sclog(level: Level, file: &str, line: u32, function: &str, code: i32, message: &str) { let filename = basename(file); - sc_log_message(level as i32, - CString::new(filename).unwrap().as_ptr(), + sc_log_message(level, + filename, line, - CString::new(function).unwrap().as_ptr(), + function, code, - CString::new(message).unwrap().as_ptr()); + message); } /// Return the function name, but for now just return as Rust @@ -126,3 +127,52 @@ pub extern "C" fn rs_log_set_level(level: i32) { LEVEL = level; } } + +pub fn log_set_level(level: Level) { + rs_log_set_level(level as i32); +} + +/// SCLogMessage wrapper. If the Suricata C context is not registered +/// a more basic log format will be used (for example, when running +/// Rust unit tests). +pub fn sc_log_message(level: Level, + filename: &str, + line: libc::c_uint, + function: &str, + code: libc::c_int, + message: &str) -> libc::c_int +{ + unsafe { + if let Some(c) = SC { + let filename = match CString::new(filename) { + Ok(filename) => filename, + Err(_) => CString::new("").unwrap() + }; + let function = match CString::new(function) { + Ok(function) => function, + Err(_) => CString::new("").unwrap() + }; + let message = match CString::new(message) { + Ok(val) => val, + Err(_) => CString::new("").unwrap() + }; + return (c.SCLogMessage)( + level as i32, + filename.as_ptr(), + line, + function.as_ptr(), + code, + message.as_ptr()); + } + } + + // Fall back if the Suricata C context is not registered which is + // the case when Rust unit tests are running. + // + // We don't log the time right now as I don't think it can be done + // with Rust 1.7.0 without using an external crate. With Rust + // 1.8.0 and newer we can unix UNIX_EPOCH.elapsed() to get the + // unix time. + println!("{}:{} <{:?}> -- {}", filename, line, level, message); + return 0; +}