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