file/swf: Use lzma-rs decompression instead of libhtp.

Use the lzma-rs crate for decompressing swf/lzma files instead of
the lzma decompressor in libhtp. This decouples suricata from libhtp
except for actual http parsing, and means libhtp no longer has to
export a lzma decompression interface.

Ticket: #5638
pull/8237/head
Todd Mortimer 3 years ago committed by Victor Julien
parent 45eb038e63
commit 7d1a8cc335

@ -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"

@ -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;

@ -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<Error> 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<std::io::Error> 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(),
}
}

@ -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",

@ -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,

@ -31,10 +31,11 @@
#include "util-file-swf-decompression.h"
#include "util-misc.h"
#include "util-print.h"
#include "util-validate.h"
#include <zlib.h>
#include "rust.h"
#include <htp/lzma/LzmaDec.h>
#include <zlib.h>
#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;
}

Loading…
Cancel
Save