/src/suricata8/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 | 12 | { |
63 | 12 | sigmatch_table[DETECT_FILESIZE].name = "filesize"; |
64 | 12 | sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred"; |
65 | 12 | sigmatch_table[DETECT_FILESIZE].url = "/rules/file-keywords.html#filesize"; |
66 | 12 | sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch; |
67 | 12 | sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup; |
68 | 12 | sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree; |
69 | 12 | sigmatch_table[DETECT_FILESIZE].flags = SIGMATCH_SUPPORT_DIR; |
70 | | #ifdef UNITTESTS |
71 | | sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests; |
72 | | #endif |
73 | | |
74 | 12 | g_file_match_list_id = DetectBufferTypeRegister("files"); |
75 | 12 | } |
76 | | |
77 | | /** |
78 | | * \brief This function is used to match filesize rule option. |
79 | | * |
80 | | * \param t thread local vars |
81 | | * \param det_ctx pattern matcher thread local data |
82 | | * \param f *LOCKED* flow |
83 | | * \param flags direction flags |
84 | | * \param file file being inspected |
85 | | * \param s signature being inspected |
86 | | * \param m sigmatch that we will cast into DetectU64Data |
87 | | * |
88 | | * \retval 0 no match |
89 | | * \retval 1 match |
90 | | */ |
91 | | static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f, |
92 | | uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m) |
93 | 127 | { |
94 | 127 | SCEnter(); |
95 | | |
96 | 127 | DetectU64Data *fsd = (DetectU64Data *)m; |
97 | 127 | int ret = 0; |
98 | 127 | uint64_t file_size = FileTrackedSize(file); |
99 | | |
100 | 127 | SCLogDebug("file size %" PRIu64 ", check %" PRIu64, file_size, fsd->arg1); |
101 | | |
102 | 127 | if (file->state == FILE_STATE_CLOSED) { |
103 | 116 | return DetectU64Match(file_size, fsd); |
104 | | /* truncated, error: only see if what we have meets the GT condition */ |
105 | 116 | } else if (file->state > FILE_STATE_CLOSED) { |
106 | 11 | if (fsd->mode == DETECT_UINT_GT || fsd->mode == DETECT_UINT_GTE) { |
107 | 0 | ret = DetectU64Match(file_size, fsd); |
108 | 0 | } |
109 | 11 | } |
110 | 127 | SCReturnInt(ret); |
111 | 127 | } |
112 | | |
113 | | /** |
114 | | * \brief this function is used to parse filesize data into the current signature |
115 | | * |
116 | | * \param de_ctx pointer to the Detection Engine Context |
117 | | * \param s pointer to the Current Signature |
118 | | * \param str pointer to the user provided options |
119 | | * |
120 | | * \retval 0 on Success |
121 | | * \retval -1 on Failure |
122 | | */ |
123 | | static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str) |
124 | 1.77k | { |
125 | 1.77k | SCEnter(); |
126 | 1.77k | DetectU64Data *fsd = DetectU64Parse(str); |
127 | 1.77k | if (fsd == NULL) |
128 | 1.37k | SCReturnInt(-1); |
129 | | |
130 | 397 | if (SCSigMatchAppendSMToList( |
131 | 397 | de_ctx, s, DETECT_FILESIZE, (SigMatchCtx *)fsd, g_file_match_list_id) == NULL) { |
132 | 0 | DetectFilesizeFree(de_ctx, fsd); |
133 | 0 | SCReturnInt(-1); |
134 | 0 | } |
135 | | |
136 | 397 | s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE); |
137 | 397 | SCReturnInt(0); |
138 | 397 | } |
139 | | |
140 | | /** |
141 | | * \brief this function will free memory associated with DetectU64Data |
142 | | * |
143 | | * \param ptr pointer to DetectU64Data |
144 | | */ |
145 | | static void DetectFilesizeFree(DetectEngineCtx *de_ctx, void *ptr) |
146 | 397 | { |
147 | 397 | SCDetectU64Free(ptr); |
148 | 397 | } |
149 | | |
150 | | #ifdef UNITTESTS |
151 | | #include "stream.h" |
152 | | #include "stream-tcp-private.h" |
153 | | #include "stream-tcp-reassemble.h" |
154 | | #include "detect-engine-mpm.h" |
155 | | #include "app-layer-parser.h" |
156 | | |
157 | | /** \test Test the Filesize keyword setup */ |
158 | | static int DetectFilesizeParseTest01(void) |
159 | | { |
160 | | DetectU64Data *fsd = DetectU64Parse("10"); |
161 | | FAIL_IF_NULL(fsd); |
162 | | FAIL_IF_NOT(fsd->arg1 == 10); |
163 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_EQ); |
164 | | DetectFilesizeFree(NULL, fsd); |
165 | | |
166 | | PASS; |
167 | | } |
168 | | |
169 | | /** \test Test the Filesize keyword setup */ |
170 | | static int DetectFilesizeParseTest02(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_LT); |
176 | | DetectFilesizeFree(NULL, fsd); |
177 | | |
178 | | PASS; |
179 | | } |
180 | | |
181 | | /** \test Test the Filesize keyword setup */ |
182 | | static int DetectFilesizeParseTest03(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_GT); |
188 | | DetectFilesizeFree(NULL, fsd); |
189 | | |
190 | | PASS; |
191 | | } |
192 | | |
193 | | /** \test Test the Filesize keyword setup */ |
194 | | static int DetectFilesizeParseTest04(void) |
195 | | { |
196 | | DetectU64Data *fsd = DetectU64Parse(" 5 <> 10 "); |
197 | | FAIL_IF_NULL(fsd); |
198 | | FAIL_IF_NOT(fsd->arg1 == 5); |
199 | | FAIL_IF_NOT(fsd->arg2 == 10); |
200 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA); |
201 | | DetectFilesizeFree(NULL, fsd); |
202 | | |
203 | | PASS; |
204 | | } |
205 | | |
206 | | /** \test Test the Filesize keyword setup */ |
207 | | static int DetectFilesizeParseTest05(void) |
208 | | { |
209 | | DetectU64Data *fsd = DetectU64Parse("5<>10"); |
210 | | FAIL_IF_NULL(fsd); |
211 | | FAIL_IF_NOT(fsd->arg1 == 5); |
212 | | FAIL_IF_NOT(fsd->arg2 == 10); |
213 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA); |
214 | | DetectFilesizeFree(NULL, fsd); |
215 | | |
216 | | PASS; |
217 | | } |
218 | | |
219 | | /** |
220 | | * \brief this function is used to initialize the detection engine context and |
221 | | * setup the signature with passed values. |
222 | | * |
223 | | */ |
224 | | |
225 | | static int DetectFilesizeInitTest( |
226 | | DetectEngineCtx **de_ctx, Signature **sig, DetectU64Data **fsd, const char *str) |
227 | | { |
228 | | char fullstr[1024]; |
229 | | *de_ctx = NULL; |
230 | | |
231 | | *de_ctx = DetectEngineCtxInit(); |
232 | | (*de_ctx)->flags |= DE_QUIET; |
233 | | FAIL_IF_NULL((*de_ctx)); |
234 | | |
235 | | *sig = NULL; |
236 | | |
237 | | FAIL_IF(snprintf(fullstr, 1024, |
238 | | "alert http any any -> any any (msg:\"Filesize " |
239 | | "test\"; filesize:%s; sid:1;)", |
240 | | str) >= 1024); |
241 | | |
242 | | Signature *s = DetectEngineAppendSig(*de_ctx, fullstr); |
243 | | FAIL_IF_NULL(s); |
244 | | |
245 | | *sig = (*de_ctx)->sig_list; |
246 | | |
247 | | *fsd = DetectU64Parse(str); |
248 | | |
249 | | PASS; |
250 | | } |
251 | | |
252 | | /** |
253 | | * \test DetectFilesizeSetpTest01 is a test for setting up an valid filesize values |
254 | | * with valid "<>" operator and include spaces arround the given values. |
255 | | * In the test the values are setup with initializing the detection engine |
256 | | * context and setting up the signature itself. |
257 | | */ |
258 | | |
259 | | static int DetectFilesizeSetpTest01(void) |
260 | | { |
261 | | |
262 | | DetectU64Data *fsd = NULL; |
263 | | uint8_t res = 0; |
264 | | Signature *sig = NULL; |
265 | | DetectEngineCtx *de_ctx = NULL; |
266 | | |
267 | | res = DetectFilesizeInitTest(&de_ctx, &sig, &fsd, "1 <> 3 "); |
268 | | FAIL_IF(res == 0); |
269 | | |
270 | | FAIL_IF_NULL(fsd); |
271 | | FAIL_IF_NOT(fsd->arg1 == 1); |
272 | | FAIL_IF_NOT(fsd->arg2 == 3); |
273 | | FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA); |
274 | | |
275 | | DetectFilesizeFree(NULL, fsd); |
276 | | DetectEngineCtxFree(de_ctx); |
277 | | |
278 | | PASS; |
279 | | } |
280 | | |
281 | | /** |
282 | | * \brief this function registers unit tests for DetectFilesize |
283 | | */ |
284 | | void DetectFilesizeRegisterTests(void) |
285 | | { |
286 | | UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01); |
287 | | UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02); |
288 | | UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03); |
289 | | UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04); |
290 | | UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05); |
291 | | UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01); |
292 | | } |
293 | | #endif /* UNITTESTS */ |