suricata
util-file-swf-decompression.c
Go to the documentation of this file.
1 /* Copyright (C) 2017 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /** \file
19  *
20  * \author Giuseppe Longo <giuseppe@glongo.it>
21  *
22  */
23 
24 
25 #include "suricata.h"
26 #include "suricata-common.h"
27 
28 #include "app-layer-htp.h"
29 
32 #include "util-misc.h"
33 #include "util-print.h"
34 #include "util-validate.h"
35 
36 #include "rust.h"
37 
38 #include <zlib.h>
39 
40 uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len)
41 {
42  if (buffer_len > 3)
43  return buffer[3];
44 
45  return 0;
46 }
47 
48 static bool FileSwfDecompressionBufferGrow(DetectEngineThreadCtx *det_ctx,
49  InspectionBuffer *out_buffer, uint32_t decompressed_data_limit)
50 {
51  const uint32_t maximum_buffer_len = decompressed_data_limit + SWF_HEADER_LEN;
52  uint32_t requested_len = out_buffer->size;
53 
54  if (requested_len >= maximum_buffer_len)
55  return true;
56 
57  if (requested_len == 0) {
58  requested_len = MIN(SWF_DECOMPRESS_INITIAL_BUFFER_LEN, maximum_buffer_len);
59  } else if (requested_len > maximum_buffer_len / 2) {
60  requested_len = maximum_buffer_len;
61  } else {
62  requested_len *= 2;
63  }
64 
65  if (SCInspectionBufferCheckAndExpand(out_buffer, requested_len) == NULL) {
67  return false;
68  }
69  return true;
70 }
71 
72 static uint32_t FileSwfDecompressionOutputCapacity(
73  const InspectionBuffer *out_buffer, uint32_t decompressed_data_limit)
74 {
75  if (out_buffer->size <= SWF_HEADER_LEN)
76  return 0;
77  return MIN(out_buffer->size - SWF_HEADER_LEN, decompressed_data_limit);
78 }
79 
80 /* CWS format */
81 /*
82  * | 4 bytes | 4 bytes | n bytes |
83  * | 'CWS' + version | script len | compressed data |
84  */
85 int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, const uint8_t *compressed_data,
86  uint32_t compressed_data_len, InspectionBuffer *out_buffer,
87  uint32_t decompressed_data_limit, uint32_t *decompressed_data_produced)
88 {
89  int ret = 1;
90  *decompressed_data_produced = 0;
91  z_stream infstream;
92  memset(&infstream, 0, sizeof(infstream));
93  infstream.zalloc = Z_NULL;
94  infstream.zfree = Z_NULL;
95  infstream.opaque = Z_NULL;
96 
97  infstream.avail_in = (uInt)compressed_data_len;
98  infstream.next_in = (Bytef *)compressed_data;
99 
100  int result = inflateInit(&infstream);
101  if (result != Z_OK) {
103  return 0;
104  }
105 
106  while (true) {
107  uint32_t output_capacity =
108  FileSwfDecompressionOutputCapacity(out_buffer, decompressed_data_limit);
109  DEBUG_VALIDATE_BUG_ON(infstream.total_out > output_capacity);
110  infstream.avail_out = (uInt)(output_capacity - infstream.total_out);
111  infstream.next_out = out_buffer->buf + SWF_HEADER_LEN + infstream.total_out;
112 
113  result = inflate(&infstream, Z_NO_FLUSH);
114  *decompressed_data_produced = (uint32_t)infstream.total_out;
115 
116  if (result == Z_STREAM_END || *decompressed_data_produced == decompressed_data_limit)
117  break;
118 
119  /* More output can be pending even after all input has been consumed. */
120  if (result == Z_OK && infstream.avail_out == 0) {
121  if (!FileSwfDecompressionBufferGrow(det_ctx, out_buffer, decompressed_data_limit)) {
122  ret = 0;
123  break;
124  }
125  continue;
126  }
127 
128  /* A retry with no input returns Z_BUF_ERROR when no output was pending. */
129  if ((result == Z_OK || result == Z_BUF_ERROR) && infstream.avail_in == 0)
130  break;
131 
132  if (result == Z_DATA_ERROR) {
134  } else if (result == Z_STREAM_ERROR) {
136  } else if (result == Z_BUF_ERROR) {
138  } else {
140  }
141  ret = 0;
142  break;
143  }
144  inflateEnd(&infstream);
145 
146  return ret;
147 }
148 
149 /* ZWS format */
150 /*
151  * | 4 bytes | 4 bytes | 4 bytes | 5 bytes | n bytes | 6 bytes |
152  * | 'ZWS' + version | script len | compressed len | LZMA props | LZMA data | LZMA end marker |
153  */
154 static uint8_t *FileSwfLzmaOutputGrow(void *output, uint32_t min_size)
155 {
156  return SCInspectionBufferCheckAndExpand(output, min_size);
157 }
158 
159 int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, const uint8_t *compressed_data,
160  uint32_t compressed_data_len, InspectionBuffer *out_buffer,
161  uint32_t decompressed_data_limit, uint32_t *decompressed_data_produced)
162 {
163  *decompressed_data_produced = 0;
164 
165  size_t inprocessed = compressed_data_len;
166  size_t outprocessed = 0;
167  int ret = lzma_decompress(compressed_data, &inprocessed, out_buffer, SWF_HEADER_LEN,
168  decompressed_data_limit, &outprocessed, FileSwfLzmaOutputGrow,
170  *decompressed_data_produced = (uint32_t)outprocessed;
171 
172  if (ret == LzmaOk || ret == LzmaOutputFull) {
174  ret == LzmaOutputFull && *decompressed_data_produced != decompressed_data_limit);
175  return 1;
176  }
177 
178  if (ret == LzmaOutputAllocError) {
180  } else if (ret == LzmaIoError) {
182  } else if (ret == LzmaHeaderTooShortError) {
184  } else if (ret == LzmaError) {
186  } else if (ret == LzmaMemoryError) {
188  } else if (ret == LzmaXzError) {
189  /* We should not see XZ compressed SWF files */
191  } else {
193  }
194  return 0;
195 }
SWF_DECOMPRESS_INITIAL_BUFFER_LEN
#define SWF_DECOMPRESS_INITIAL_BUFFER_LEN
Definition: util-file-swf-decompression.h:35
InspectionBuffer
Definition: detect-engine-inspect-buffer.h:34
rust.h
DetectEngineSetEvent
void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
Definition: detect-engine.c:5293
MIN
#define MIN(x, y)
Definition: suricata-common.h:416
InspectionBuffer::size
uint32_t size
Definition: detect-engine-inspect-buffer.h:45
FILE_DECODER_EVENT_Z_UNKNOWN_ERROR
@ FILE_DECODER_EVENT_Z_UNKNOWN_ERROR
Definition: detect.h:1541
FileGetSwfVersion
uint8_t FileGetSwfVersion(const uint8_t *buffer, const uint32_t buffer_len)
Definition: util-file-swf-decompression.c:40
app-layer-htp.h
SWF_HEADER_LEN
#define SWF_HEADER_LEN
Definition: util-file-decompression.h:30
DetectEngineThreadCtx_
Definition: detect.h:1306
util-print.h
InspectionBuffer::buf
uint8_t * buf
Definition: detect-engine-inspect-buffer.h:44
FILE_DECODER_EVENT_Z_BUF_ERROR
@ FILE_DECODER_EVENT_Z_BUF_ERROR
Definition: detect.h:1540
FILE_DECODER_EVENT_LZMA_DECODER_ERROR
@ FILE_DECODER_EVENT_LZMA_DECODER_ERROR
Definition: detect.h:1544
FILE_DECODER_EVENT_LZMA_XZ_ERROR
@ FILE_DECODER_EVENT_LZMA_XZ_ERROR
Definition: detect.h:1546
FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR
@ FILE_DECODER_EVENT_LZMA_HEADER_TOO_SHORT_ERROR
Definition: detect.h:1543
suricata-common.h
FILE_DECODER_EVENT_Z_DATA_ERROR
@ FILE_DECODER_EVENT_Z_DATA_ERROR
Definition: detect.h:1538
FILE_DECODER_EVENT_NO_MEM
@ FILE_DECODER_EVENT_NO_MEM
Definition: detect.h:1535
util-validate.h
util-file-swf-decompression.h
FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR
@ FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR
Definition: detect.h:1545
util-file-decompression.h
FILE_DECODER_EVENT_Z_STREAM_ERROR
@ FILE_DECODER_EVENT_Z_STREAM_ERROR
Definition: detect.h:1539
suricata.h
SCInspectionBufferCheckAndExpand
uint8_t * SCInspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
make sure that the buffer has at least 'min_size' bytes Expand the buffer if necessary
Definition: detect-engine-inspect-buffer.c:217
MAX_SWF_DECOMPRESSED_LEN
#define MAX_SWF_DECOMPRESSED_LEN
Definition: util-file-swf-decompression.h:33
util-misc.h
FileSwfZlibDecompression
int FileSwfZlibDecompression(DetectEngineThreadCtx *det_ctx, const uint8_t *compressed_data, uint32_t compressed_data_len, InspectionBuffer *out_buffer, uint32_t decompressed_data_limit, uint32_t *decompressed_data_produced)
Definition: util-file-swf-decompression.c:85
FILE_DECODER_EVENT_LZMA_IO_ERROR
@ FILE_DECODER_EVENT_LZMA_IO_ERROR
Definition: detect.h:1542
FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR
@ FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR
Definition: detect.h:1547
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
FileSwfLzmaDecompression
int FileSwfLzmaDecompression(DetectEngineThreadCtx *det_ctx, const uint8_t *compressed_data, uint32_t compressed_data_len, InspectionBuffer *out_buffer, uint32_t decompressed_data_limit, uint32_t *decompressed_data_produced)
Definition: util-file-swf-decompression.c:159