1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18
19 // file_decomp.h author Ed Borgoyn eborgoyn@sourcefire.com
20
21 #ifndef FILE_DECOMP_H
22 #define FILE_DECOMP_H
23
24 // File_Decomp global typedefs (used in child objects)
25
26 #include <cstring>
27
28 #include "main/snort_types.h"
29
30 #define NEW_OFFICE_FRMT 120
31 #define OLD_OFFICE_FRMT 27
32
33 /* Function return codes used internally and with caller */
34 // FIXIT-L these need to be split into internal-only codes and things that may be returned to the
35 // application. The codes used by PDF and SWF should be standardized. PDF is returning BlockIn and
36 // BlockOut while SWF is using OK. There also needs to be clarity about what Error means and what
37 // should be done about it. Is it just an indicator of programming error or are there operational
38 // cases where it occurs? No idea whether Complete and Eof are real things and what should be done
39 // about them.
40
41 enum fd_status_t
42 {
43 File_Decomp_DecompError = -2, /* Error from decompression */
44 File_Decomp_Error = -1, /* Error from decompression */
45 File_Decomp_OK = 0,
46 File_Decomp_NoSig = 1, /* No file signature located */
47 File_Decomp_Complete = 2, /* Completed */
48 File_Decomp_BlockOut = 3, /* Blocked due to lack of output space */
49 File_Decomp_BlockIn = 4, /* Blocked due to lack in input data */
50 File_Decomp_Eof = 5 /* End of file located */
51 };
52
53 enum file_compression_type_t
54 {
55 FILE_COMPRESSION_TYPE_NONE,
56 FILE_COMPRESSION_TYPE_DEFLATE,
57 FILE_COMPRESSION_TYPE_ZLIB,
58 FILE_COMPRESSION_TYPE_LZMA,
59 FILE_COMPRESSION_TYPE_MAX
60 };
61
62 /* Potential decompression modes, passed in at initialization time. */
63 #define FILE_SWF_LZMA_BIT (0x00000001)
64 #define FILE_SWF_ZLIB_BIT (0x00000002)
65 #define FILE_PDF_DEFL_BIT (0x00000004)
66 #define FILE_ZIP_DEFL_BIT (0x00000008)
67 #define FILE_VBA_EXTR_BIT (0x00000010)
68
69 #define FILE_PDF_ANY (FILE_PDF_DEFL_BIT)
70 #define FILE_SWF_ANY (FILE_SWF_LZMA_BIT | FILE_SWF_ZLIB_BIT)
71 #define FILE_ZIP_ANY (FILE_ZIP_DEFL_BIT | FILE_VBA_EXTR_BIT)
72
73 /* Error codes either passed to caller via the session->Error_Alert of
74 the File_Decomp_Alert() call-back function. */
75 enum FileDecompError
76 {
77 FILE_DECOMP_ERR_SWF_ZLIB_FAILURE,
78 FILE_DECOMP_ERR_SWF_LZMA_FAILURE,
79 FILE_DECOMP_ERR_PDF_DEFL_FAILURE,
80 FILE_DECOMP_ERR_PDF_UNSUP_COMP_TYPE,
81 FILE_DECOMP_ERR_PDF_CASC_COMP,
82 FILE_DECOMP_ERR_PDF_PARSE_FAILURE,
83 FILE_DECOMP_ERR_ZIP_PARSE_FAILURE,
84 FILE_DECOMP_ERR_ZIP_DEFL_FAILURE
85 };
86
87 /* Private Types */
88 enum file_type_t
89 {
90 FILE_TYPE_NONE,
91 FILE_TYPE_SWF,
92 FILE_TYPE_PDF,
93 FILE_TYPE_ZIP,
94 FILE_TYPE_MAX
95 };
96
97 enum fd_states_t
98 {
99 STATE_NEW, /* Session created */
100 STATE_READY, /* Session created and ready for content, no file/decomp selected */
101 STATE_ACTIVE, /* Decompressor inited and ready for content */
102 STATE_COMPLETE /* Decompression completed */
103 };
104
105 /* Primary file decompression session state context */
106 struct fd_session_t
107 {
108 // FIXIT-L replace with abstract base class pointer used for
109 // PDF or SWF subclass and eliminate switches on File_Type
110 union
111 {
112 struct fd_PDF_t* PDF;
113 struct fd_SWF_t* SWF;
114 struct fd_ZIP_t* ZIP;
115 };
116
117 const uint8_t* Next_In; // next input byte
118 uint8_t* Next_Out; // next output byte should be put there
119
120 // Alerting callback
121 void (* Alert_Callback)(void* Context, int Event);
122 void* Alert_Context;
123
124 uint32_t Avail_In; // number of bytes available at next_in
125 uint32_t Total_In; // total number of input bytes read so far
126
127 uint32_t Avail_Out; // remaining free space at next_out
128 uint32_t Total_Out; // total number of bytes output so far
129
130 // Configuration settings
131 // FIXIT-RC Compr_Depth and Decompr_Depth only support OHI and eventually should be removed
132 uint32_t Compr_Depth;
133 uint32_t Decompr_Depth;
134 uint32_t Modes; // Bit mapped set of potential file/algo modes
135
136 int Error_Event; // Specific event indicated by DecomprError return
137
138 // Internal State
139 uint8_t File_Type; // Active file type
140 uint8_t Decomp_Type; // Active decompression type
141 uint8_t Sig_State; // Sig search state machine
142 uint8_t State; // main state machine
143 uint8_t* ole_data_ptr; // compressed ole file.
144 uint32_t ole_data_len;
145 bool vba_analysis;
146
get_ole_datafd_session_t147 void get_ole_data(uint8_t*& ole_data_ptr, uint32_t& ole_data_len)
148 {
149 ole_data_ptr = this->ole_data_ptr;
150 ole_data_len = this->ole_data_len;
151 }
152
ole_data_resetfd_session_t153 void ole_data_reset()
154 {
155 ole_data_ptr = nullptr;
156 ole_data_len = 0;
157 }
158 };
159
160 /* Macros */
161
162 /* Macros used to sync my decompression context with that
163 of the underlying decompression engine context. */
164 #ifndef SYNC_IN
165 #define SYNC_IN(dest) \
166 dest->next_in = const_cast<Bytef*>(SessionPtr->Next_In); \
167 (dest)->avail_in = SessionPtr->Avail_In; \
168 (dest)->total_in = SessionPtr->Total_In; \
169 (dest)->next_out = SessionPtr->Next_Out; \
170 (dest)->avail_out = SessionPtr->Avail_Out; \
171 (dest)->total_out = SessionPtr->Total_Out;
172 #endif
173
174 #ifndef SYNC_OUT
175 #define SYNC_OUT(src) \
176 SessionPtr->Next_In = (const uint8_t*)(src)->next_in; \
177 SessionPtr->Avail_In = (src)->avail_in; \
178 SessionPtr->Total_In = (src)->total_in; \
179 SessionPtr->Next_Out = (uint8_t*)(src)->next_out; \
180 SessionPtr->Avail_Out = (src)->avail_out; \
181 SessionPtr->Total_Out = (src)->total_out;
182 #endif
183
184 /* Inline Functions */
185
186 /* If available, look at the next available byte in the input queue */
Peek_1(fd_session_t * SessionPtr,uint8_t * c)187 inline bool Peek_1(fd_session_t* SessionPtr, uint8_t* c)
188 {
189 if ( (SessionPtr->Next_In != nullptr) && (SessionPtr->Avail_In > 0) )
190 {
191 *c = *(SessionPtr->Next_In);
192 return( true );
193 }
194 else
195 return( false );
196 }
197
198 /* If available, get a byte from the input queue */
Get_1(fd_session_t * SessionPtr,uint8_t * c)199 inline bool Get_1(fd_session_t* SessionPtr, uint8_t* c)
200 {
201 if ( (SessionPtr->Next_In != nullptr) && (SessionPtr->Avail_In > 0) )
202 {
203 *c = *(SessionPtr->Next_In)++;
204 SessionPtr->Avail_In -= 1;
205 SessionPtr->Total_In += 1;
206 return( true );
207 }
208 else
209 return( false );
210 }
211
212 /* If available, get N bytes from the input queue. All N must be
213 available for this call to succeed. */
Get_N(fd_session_t * SessionPtr,const uint8_t ** c,uint32_t N)214 inline bool Get_N(fd_session_t* SessionPtr, const uint8_t** c, uint32_t N)
215 {
216 if ( (SessionPtr->Next_In != nullptr) && (SessionPtr->Avail_In >= N) )
217 {
218 *c = SessionPtr->Next_In;
219 SessionPtr->Next_In += N;
220 SessionPtr->Avail_In -= N;
221 SessionPtr->Total_In += N;
222 return( true );
223 }
224 else
225 return( false );
226 }
227
228 /* If there's room in the output queue, put one byte. */
Put_1(fd_session_t * SessionPtr,uint8_t c)229 inline bool Put_1(fd_session_t* SessionPtr, uint8_t c)
230 {
231 if ( (SessionPtr->Next_Out != nullptr) && (SessionPtr->Avail_Out > 0) )
232 {
233 *(SessionPtr->Next_Out)++ = c;
234 SessionPtr->Avail_Out -= 1;
235 SessionPtr->Total_Out += 1;
236 return( true );
237 }
238 else
239 return( false );
240 }
241
242 /* If the output queue has room available, place N bytes onto the queue.
243 The output queue must have space for N bytes for this call to succeed. */
Put_N(fd_session_t * SessionPtr,const uint8_t * c,uint32_t N)244 inline bool Put_N(fd_session_t* SessionPtr, const uint8_t* c, uint32_t N)
245 {
246 if ( (SessionPtr->Next_Out != nullptr) && (SessionPtr->Avail_Out >= N) )
247 {
248 strncpy( (char*)SessionPtr->Next_Out, (const char*)c, N);
249 SessionPtr->Next_Out += N;
250 SessionPtr->Avail_Out -= N;
251 SessionPtr->Total_Out += N;
252 return( true );
253 }
254 else
255 return( false );
256 }
257
258 /* If the input queue has at least one byte available AND there's at
259 space for at least one byte in the output queue, then move one byte. */
Move_1(fd_session_t * SessionPtr)260 inline bool Move_1(fd_session_t* SessionPtr)
261 {
262 if ( (SessionPtr->Next_Out != nullptr) && (SessionPtr->Avail_Out > 0) &&
263 (SessionPtr->Next_In != nullptr) && (SessionPtr->Avail_In > 0) )
264 {
265 *(SessionPtr->Next_Out) = *(SessionPtr->Next_In);
266 SessionPtr->Next_In += 1;
267 SessionPtr->Next_Out += 1;
268 SessionPtr->Avail_In -= 1;
269 SessionPtr->Avail_Out -= 1;
270 SessionPtr->Total_In += 1;
271 SessionPtr->Total_Out += 1;
272 return( true );
273 }
274 else
275 return( false );
276 }
277
278 /* If the input queue has at least N bytes available AND there's at
279 space for at least N bytes in the output queue, then move all N bytes. */
Move_N(fd_session_t * SessionPtr,uint32_t N)280 inline bool Move_N(fd_session_t* SessionPtr, uint32_t N)
281 {
282 if ( (SessionPtr->Next_Out != nullptr) && (SessionPtr->Avail_Out >= N) &&
283 (SessionPtr->Next_In != nullptr) && (SessionPtr->Avail_In >= N) )
284 {
285 memcpy( (char*)SessionPtr->Next_Out, (const char*)SessionPtr->Next_In, N);
286 SessionPtr->Next_In += N;
287 SessionPtr->Next_Out += N;
288 SessionPtr->Avail_In -= N;
289 SessionPtr->Avail_Out -= N;
290 SessionPtr->Total_In += N;
291 SessionPtr->Total_Out += N;
292 return( true );
293 }
294 else
295 return( false );
296 }
297
298 /* API Functions */
299 namespace snort
300 {
301 /* Create a new decompression session object */
302 SO_PUBLIC fd_session_t* File_Decomp_New();
303
304 /* Initialize the session */
305 SO_PUBLIC fd_status_t File_Decomp_Init(fd_session_t*);
306
307 /* Run the incremental decompression engine */
308 SO_PUBLIC fd_status_t File_Decomp(fd_session_t*);
309
310 /* Close the decomp session processing */
311 SO_PUBLIC fd_status_t File_Decomp_End(fd_session_t*);
312
313 /* Close the current decomp session, but setup for another */
314 SO_PUBLIC fd_status_t File_Decomp_Reset(fd_session_t*);
315
316 /* Abort and delete the session */
317 SO_PUBLIC fd_status_t File_Decomp_StopFree(fd_session_t*);
318
319 /* Delete the session object */
320 SO_PUBLIC void File_Decomp_Free(fd_session_t*);
321
322 /* Call the error alerting call-back function */
323 SO_PUBLIC void File_Decomp_Alert(fd_session_t*, int Event);
324 }
325 #endif
326
327