]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
file/swf: Use lzma-rs decompression instead of libhtp.
authorTodd Mortimer <richard.mortimer@cyber.gc.ca>
Fri, 8 Jul 2022 20:47:41 +0000 (20:47 +0000)
committerVictor Julien <vjulien@oisf.net>
Sat, 3 Dec 2022 05:32:23 +0000 (06:32 +0100)
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

rust/Cargo.toml.in
rust/src/lib.rs
rust/src/lzma.rs [new file with mode: 0644]
src/detect-engine.c
src/detect.h
src/util-file-swf-decompression.c

index 0077a01ed57aaef7bf966a3602f65061c2f776e0..011e8bb74491742848e575625d98dcebd1ec2828 100644 (file)
@@ -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"
index 175053fc088c3a54eee4a4c585fd95f72f72d99e..346bbe8cfed57b004dc2415807f1f6ad70a73a54 100644 (file)
@@ -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 (file)
index 0000000..c097e9d
--- /dev/null
@@ -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(),
+    }
+}
index f791e6befab60cc857832f085a47743574db6c5f..8b833d9bddca0bbf14077e2b7e38b4e15824f3f0 100644 (file)
@@ -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",
index bf510cb18a24be358b12ce4191da335846e7c62a..e70384710d6987c920a9e44cb479ca26d5f03393 100644 (file)
@@ -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,
index 71ca6eda8699342e2e3ebc21b9ba2dfa932e66ca..378b4f96e9423adeaf3c0d1abbe0dcdedfa7f11f 100644 (file)
 #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;
 }