diff --git a/rust/Cargo.toml.in b/rust/Cargo.toml.in index 0077a01ed5..011e8bb744 100644 --- a/rust/Cargo.toml.in +++ b/rust/Cargo.toml.in @@ -27,6 +27,7 @@ bitflags = "~1.2.1" byteorder = "~1.4.2" uuid = "~0.8.2" crc = "~1.8.1" +lzma-rs = { version = "~0.2.0", features = ["stream"] } memchr = "~2.4.1" num = "~0.2.1" num-derive = "~0.2.5" diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 175053fc08..346bbe8cfe 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -120,5 +120,6 @@ pub mod http2; pub mod quic; pub mod bittorrent_dht; pub mod plugin; +pub mod lzma; pub mod util; pub mod ffi; diff --git a/rust/src/lzma.rs b/rust/src/lzma.rs new file mode 100644 index 0000000000..c097e9d163 --- /dev/null +++ b/rust/src/lzma.rs @@ -0,0 +1,85 @@ +/* Copyright (C) 2022 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +use lzma_rs::decompress::{Options, Stream}; +use lzma_rs::error::Error; +use std::io::{Cursor, Write}; + +/// Propagate lzma crate errors +#[repr(C)] +pub enum LzmaStatus { + LzmaOk, + LzmaIoError, + LzmaHeaderTooShortError, + LzmaError, + LzmaMemoryError, + LzmaXzError, +} + +impl From for LzmaStatus { + fn from(e: Error) -> LzmaStatus { + match e { + Error::IoError(_) => LzmaStatus::LzmaIoError, + Error::HeaderTooShort(_) => LzmaStatus::LzmaHeaderTooShortError, + Error::LzmaError(e) => { + if e.to_string().contains("exceeded memory limit") { + LzmaStatus::LzmaMemoryError + } else { + LzmaStatus::LzmaError + } + } + Error::XzError(_) => LzmaStatus::LzmaXzError, + } + } +} + +impl From for LzmaStatus { + fn from(_e: std::io::Error) -> LzmaStatus { + LzmaStatus::LzmaIoError + } +} + +/// Use the lzma algorithm to decompress a chunk of data. +#[no_mangle] +pub unsafe extern "C" fn lzma_decompress( + input: *const u8, input_len: &mut usize, output: *mut u8, output_len: &mut usize, + memlimit: usize, +) -> LzmaStatus { + let input = std::slice::from_raw_parts(input, *input_len); + let output = std::slice::from_raw_parts_mut(output, *output_len); + let output = Cursor::new(output); + + let options = Options { + memlimit: Some(memlimit), + allow_incomplete: true, + ..Default::default() + }; + + let mut stream = Stream::new_with_options(&options, output); + + if let Err(e) = stream.write_all(input) { + return e.into(); + } + + match stream.finish() { + Ok(output) => { + *output_len = output.position() as usize; + LzmaStatus::LzmaOk + } + Err(e) => e.into(), + } +} diff --git a/src/detect-engine.c b/src/detect-engine.c index f791e6befa..8b833d9bdd 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -117,12 +117,11 @@ SCEnumCharMap det_ctx_event_table[] = { { "Z_STREAM_ERROR", FILE_DECODER_EVENT_Z_STREAM_ERROR }, { "Z_BUF_ERROR", FILE_DECODER_EVENT_Z_BUF_ERROR }, { "Z_UNKNOWN_ERROR", FILE_DECODER_EVENT_Z_UNKNOWN_ERROR }, + { "LZMA_IO_ERROR", FILE_DECODER_EVENT_LZMA_IO_ERROR }, + { "LZMA_HEADER_TOO_SHORT_ERROR", FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR }, { "LZMA_DECODER_ERROR", FILE_DECODER_EVENT_LZMA_DECODER_ERROR }, { "LZMA_MEMLIMIT_ERROR", FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR }, - { "LZMA_OPTIONS_ERROR", FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR }, - { "LZMA_FORMAT_ERROR", FILE_DECODER_EVENT_LZMA_FORMAT_ERROR }, - { "LZMA_DATA_ERROR", FILE_DECODER_EVENT_LZMA_DATA_ERROR }, - { "LZMA_BUF_ERROR", FILE_DECODER_EVENT_LZMA_BUF_ERROR }, + { "LZMA_XZ_ERROR", FILE_DECODER_EVENT_LZMA_XZ_ERROR }, { "LZMA_UNKNOWN_ERROR", FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR }, { "TOO_MANY_BUFFERS", diff --git a/src/detect.h b/src/detect.h index bf510cb18a..e70384710d 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1251,12 +1251,11 @@ enum { FILE_DECODER_EVENT_Z_STREAM_ERROR, FILE_DECODER_EVENT_Z_BUF_ERROR, FILE_DECODER_EVENT_Z_UNKNOWN_ERROR, + FILE_DECODER_EVENT_LZMA_IO_ERROR, + FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR, FILE_DECODER_EVENT_LZMA_DECODER_ERROR, FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR, - FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR, - FILE_DECODER_EVENT_LZMA_FORMAT_ERROR, - FILE_DECODER_EVENT_LZMA_DATA_ERROR, - FILE_DECODER_EVENT_LZMA_BUF_ERROR, + FILE_DECODER_EVENT_LZMA_XZ_ERROR, FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR, DETECT_EVENT_TOO_MANY_BUFFERS, diff --git a/src/util-file-swf-decompression.c b/src/util-file-swf-decompression.c index 71ca6eda86..378b4f96e9 100644 --- a/src/util-file-swf-decompression.c +++ b/src/util-file-swf-decompression.c @@ -31,10 +31,11 @@ #include "util-file-swf-decompression.h" #include "util-misc.h" #include "util-print.h" +#include "util-validate.h" -#include +#include "rust.h" -#include +#include #define MAX_SWF_DECOMPRESSED_LEN 50000000 /* @@ -129,10 +130,6 @@ int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, return ret; } -static void *SzAlloc(ISzAllocPtr p, size_t size) { return malloc(size); } -static void SzFree(ISzAllocPtr p, void *address) { free(address); } -static const ISzAlloc suri_lzma_Alloc = { SzAlloc, SzFree }; - /* ZWS format */ /* * | 4 bytes | 4 bytes | 4 bytes | 5 bytes | n bytes | 6 bytes | @@ -144,46 +141,36 @@ int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, { int ret = 0; - CLzmaDec strm; - LzmaDec_Construct(&strm); - ELzmaStatus status; - - if (compressed_data_len < LZMA_PROPS_SIZE + 8) { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_FORMAT_ERROR); - return 0; - } - ret = LzmaDec_Allocate(&strm, compressed_data, LZMA_PROPS_SIZE, &suri_lzma_Alloc); - if (ret != SZ_OK) { - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_DECODER_ERROR); - return 0; - } - LzmaDec_Init(&strm); - compressed_data += LZMA_PROPS_SIZE + 8; - compressed_data_len -= LZMA_PROPS_SIZE + 8; size_t inprocessed = compressed_data_len; size_t outprocessed = decompressed_data_len; - ret = LzmaDec_DecodeToBuf(&strm, decompressed_data, &outprocessed, - compressed_data, &inprocessed, LZMA_FINISH_ANY, &status, MAX_SWF_DECOMPRESSED_LEN); + ret = lzma_decompress(compressed_data, &inprocessed, decompressed_data, &outprocessed, + MAX_SWF_DECOMPRESSED_LEN); switch(ret) { - case SZ_OK: + case LzmaOk: ret = 1; break; - case SZ_ERROR_MEM: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR); + case LzmaIoError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_IO_ERROR); ret = 0; break; - case SZ_ERROR_UNSUPPORTED: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR); + case LzmaHeaderTooShortError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR); ret = 0; break; - case SZ_ERROR_DATA: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_DATA_ERROR); + case LzmaError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_DECODER_ERROR); + ret = 0; + break; + case LzmaMemoryError: + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR); ret = 0; break; - case SZ_ERROR_INPUT_EOF: - DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_BUF_ERROR); + case LzmaXzError: + /* We should not see XZ compressed SWF files */ + DEBUG_VALIDATE_BUG_ON(ret == LzmaXzError); + DetectEngineSetEvent(det_ctx, FILE_DECODER_EVENT_LZMA_XZ_ERROR); ret = 0; break; default: @@ -192,6 +179,5 @@ int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, break; } - LzmaDec_Free(&strm, &suri_lzma_Alloc); return ret; }