/src/suricata7/src/detect-filesize.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2020 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 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Victor Julien <victor@inliniac.net> |
22 | | * |
23 | | * Implements the filesize keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "app-layer-protos.h" |
28 | | #include "app-layer-htp.h" |
29 | | #include "util-unittest.h" |
30 | | #include "util-unittest-helper.h" |
31 | | #include "util-misc.h" |
32 | | |
33 | | #include "detect.h" |
34 | | #include "detect-parse.h" |
35 | | #include "detect-engine.h" |
36 | | #include "detect-engine-state.h" |
37 | | #include "detect-engine-uint.h" |
38 | | #include "detect-engine-build.h" |
39 | | |
40 | | #include "detect-filesize.h" |
41 | | #include "util-debug.h" |
42 | | #include "util-byte.h" |
43 | | #include "flow-util.h" |
44 | | #include "stream-tcp.h" |
45 | | |
46 | | |
47 | | /*prototypes*/ |
48 | | static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f, |
49 | | uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m); |
50 | | static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, const char *); |
51 | | static void DetectFilesizeFree (DetectEngineCtx *, void *); |
52 | | #ifdef UNITTESTS |
53 | | static void DetectFilesizeRegisterTests (void); |
54 | | #endif |
55 | | static int g_file_match_list_id = 0; |
56 | | |
57 | | /** |
58 | | * \brief Registration function for filesize: keyword |
59 | | */ |
60 | | |
61 | | void DetectFilesizeRegister(void) |
62 | 73 | { |
63 | 73 | sigmatch_table[DETECT_FILESIZE].name = "filesize"; |
64 | 73 | sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; |
65 | 73 | sigmatch_table[DETECT_FILESIZE].url = "/rules/file-keywords.html#filesize"; |
66 | 73 | sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; |
67 | 73 | sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; |
68 | 73 | sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; |
69 | | #ifdef UNITTESTS |
70 | | sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests; |
71 | | #endif |
72 | | |
73 | 73 | g_file_match_list_id = DetectBufferTypeRegister("files"); |
74 | 73 | } |
75 | | |
76 | | /** |
77 | | * \brief This function is used to match filesize rule option. |
78 | | * |
79 | | * \param t thread local vars |
80 | | * \param det_ctx pattern matcher thread local data |
81 | | * \param f *LOCKED* flow |
82 | | * \param flags direction flags |
83 | | * \param file file being inspected |
84 | | * \param s signature being inspected |
85 | | * \param m sigmatch that we will cast into DetectU64Data |
86 | | * |
87 | | * \retval 0 no match |
88 | | * \retval 1 match |
89 | | */ |
90 | | static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f, |
91 | | uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) |
92 | 125 | { |
93 | 125 | SCEnter(); |
94 | | |
95 | 125 | DetectU64Data *fsd = (DetectU64Data *)m; |
96 | 125 | int ret = 0; |
97 | 125 | uint64_t file_size = FileTrackedSize(file); |
98 | | |
99 | 125 | SCLogDebug("file size %" PRIu64 ", check %" PRIu64, file_size, fsd->arg1); |
100 | | |
101 | 125 | if (file->state == FILE_STATE_CLOSED) { |
102 | 125 | return DetectU64Match(file_size, fsd); |
103 | | /* truncated, error: only see if what we have meets the GT condition */ |
104 | 125 | } else if (file->state > FILE_STATE_CLOSED) { |
105 | 0 | if (fsd->mode == DETECT_UINT_GT || fsd->mode == DETECT_UINT_GTE) { |
106 | 0 | ret = DetectU64Match(file_size, fsd); |
107 | 0 | } |
108 | 0 | } |
109 | 125 | SCReturnInt(ret); |
110 | 125 | } |
111 | | |
112 | | /** |
113 | | * \brief this function is used to parse filesize data into the current signature |
114 | | * |
115 | | * \param de_ctx pointer to the Detection Engine Context |
116 | | * \param s pointer to the Current Signature |
117 | | * \param str pointer to the user provided options |
118 | | * |
119 | | * \retval 0 on Success |
120 | | * \retval -1 on Failure |
121 | | */ |
122 | | static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
123 | 1.04k | { |
124 | 1.04k | SCEnter(); |
125 | 1.04k | DetectU64Data *fsd = NULL; |
126 | 1.04k | SigMatch *sm = NULL; |
127 | | |
128 | 1.04k | fsd = DetectU64Parse(str); |
129 | 1.04k | if (fsd == NULL) |
130 | 532 | SCReturnInt(-1); |
131 | | |
132 | 517 | sm = SigMatchAlloc(); |
133 | 517 | if (sm == NULL) |
134 | 0 | goto error; |
135 | | |
136 | 517 | sm->type = DETECT_FILESIZE; |
137 | 517 | sm->ctx = (SigMatchCtx *)fsd; |
138 | | |
139 | 517 | SigMatchAppendSMToList(s, sm, g_file_match_list_id); |
140 | | |
141 | 517 | s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); |
142 | 517 | SCReturnInt(0); |
143 | | |
144 | 0 | error: |
145 | 0 | if (fsd != NULL) |
146 | 0 | DetectFilesizeFree(de_ctx, fsd); |
147 | 0 | if (sm != NULL) |
148 | 0 | SCFree(sm); |
149 | 0 | SCReturnInt(-1); |
150 | 517 | } |
151 | | |
152 | | /** |
153 | | * \brief this function will free memory associated with DetectU64Data |
154 | | * |
155 | | * \param ptr pointer to DetectU64Data |
156 | | */ |
157 | | static void DetectFilesizeFree(DetectEngineCtx *de_ctx, void *ptr) |
158 | 839 | { |
159 | 839 | rs_detect_u64_free(ptr); |
160 | 839 | } |
161 | | |
162 | | #ifdef UNITTESTS |
163 | | #include "stream.h" |
164 | | #include "stream-tcp-private.h" |
165 | | #include "stream-tcp-reassemble.h" |
166 | | #include "detect-engine-mpm.h" |
167 | | #include "app-layer-parser.h" |
168 | | |
169 | | /** \test Test the Filesize keyword setup */ |
170 | | static int DetectFilesizeParseTest01(void) |
171 | | { |
172 | | DetectU64Data *fsd = DetectU64Parse("10"); |
173 | | FAIL_IF_NULL(fsd); |
174 | | FAIL_IF_NOT(fsd->arg1 == 10); |
175 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_EQ); |
176 | | DetectFilesizeFree(NULL, fsd); |
177 | | |
178 | | PASS; |
179 | | } |
180 | | |
181 | | /** \test Test the Filesize keyword setup */ |
182 | | static int DetectFilesizeParseTest02(void) |
183 | | { |
184 | | DetectU64Data *fsd = DetectU64Parse(" < 10 "); |
185 | | FAIL_IF_NULL(fsd); |
186 | | FAIL_IF_NOT(fsd->arg1 == 10); |
187 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_LT); |
188 | | DetectFilesizeFree(NULL, fsd); |
189 | | |
190 | | PASS; |
191 | | } |
192 | | |
193 | | /** \test Test the Filesize keyword setup */ |
194 | | static int DetectFilesizeParseTest03(void) |
195 | | { |
196 | | DetectU64Data *fsd = DetectU64Parse(" > 10 "); |
197 | | FAIL_IF_NULL(fsd); |
198 | | FAIL_IF_NOT(fsd->arg1 == 10); |
199 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_GT); |
200 | | DetectFilesizeFree(NULL, fsd); |
201 | | |
202 | | PASS; |
203 | | } |
204 | | |
205 | | /** \test Test the Filesize keyword setup */ |
206 | | static int DetectFilesizeParseTest04(void) |
207 | | { |
208 | | DetectU64Data *fsd = DetectU64Parse(" 5 <> 10 "); |
209 | | FAIL_IF_NULL(fsd); |
210 | | FAIL_IF_NOT(fsd->arg1 == 5); |
211 | | FAIL_IF_NOT(fsd->arg2 == 10); |
212 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA); |
213 | | DetectFilesizeFree(NULL, fsd); |
214 | | |
215 | | PASS; |
216 | | } |
217 | | |
218 | | /** \test Test the Filesize keyword setup */ |
219 | | static int DetectFilesizeParseTest05(void) |
220 | | { |
221 | | DetectU64Data *fsd = DetectU64Parse("5<>10"); |
222 | | FAIL_IF_NULL(fsd); |
223 | | FAIL_IF_NOT(fsd->arg1 == 5); |
224 | | FAIL_IF_NOT(fsd->arg2 == 10); |
225 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA); |
226 | | DetectFilesizeFree(NULL, fsd); |
227 | | |
228 | | PASS; |
229 | | } |
230 | | |
231 | | /** |
232 | | * \brief this function is used to initialize the detection engine context and |
233 | | * setup the signature with passed values. |
234 | | * |
235 | | */ |
236 | | |
237 | | static int DetectFilesizeInitTest( |
238 | | DetectEngineCtx **de_ctx, Signature **sig, DetectU64Data **fsd, const char *str) |
239 | | { |
240 | | char fullstr[1024]; |
241 | | *de_ctx = NULL; |
242 | | |
243 | | *de_ctx = DetectEngineCtxInit(); |
244 | | (*de_ctx)->flags |= DE_QUIET; |
245 | | FAIL_IF_NULL((*de_ctx)); |
246 | | |
247 | | *sig = NULL; |
248 | | |
249 | | FAIL_IF(snprintf(fullstr, 1024, |
250 | | "alert http any any -> any any (msg:\"Filesize " |
251 | | "test\"; filesize:%s; sid:1;)", |
252 | | str) >= 1024); |
253 | | |
254 | | Signature *s = DetectEngineAppendSig(*de_ctx, fullstr); |
255 | | FAIL_IF_NULL(s); |
256 | | |
257 | | *sig = (*de_ctx)->sig_list; |
258 | | |
259 | | *fsd = DetectU64Parse(str); |
260 | | |
261 | | PASS; |
262 | | } |
263 | | |
264 | | /** |
265 | | * \test DetectFilesizeSetpTest01 is a test for setting up an valid filesize values |
266 | | * with valid "<>" operator and include spaces arround the given values. |
267 | | * In the test the values are setup with initializing the detection engine |
268 | | * context and setting up the signature itself. |
269 | | */ |
270 | | |
271 | | static int DetectFilesizeSetpTest01(void) |
272 | | { |
273 | | |
274 | | DetectU64Data *fsd = NULL; |
275 | | uint8_t res = 0; |
276 | | Signature *sig = NULL; |
277 | | DetectEngineCtx *de_ctx = NULL; |
278 | | |
279 | | res = DetectFilesizeInitTest(&de_ctx, &sig, &fsd, "1 <> 3 "); |
280 | | FAIL_IF(res == 0); |
281 | | |
282 | | FAIL_IF_NULL(fsd); |
283 | | FAIL_IF_NOT(fsd->arg1 == 1); |
284 | | FAIL_IF_NOT(fsd->arg2 == 3); |
285 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA); |
286 | | |
287 | | DetectFilesizeFree(NULL, fsd); |
288 | | DetectEngineCtxFree(de_ctx); |
289 | | |
290 | | PASS; |
291 | | } |
292 | | |
293 | | /** |
294 | | * \brief this function registers unit tests for DetectFilesize |
295 | | */ |
296 | | void DetectFilesizeRegisterTests(void) |
297 | | { |
298 | | UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01); |
299 | | UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02); |
300 | | UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03); |
301 | | UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04); |
302 | | UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05); |
303 | | UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01); |
304 | | } |
305 | | #endif /* UNITTESTS */ |