]>
Commit | Line | Data |
---|---|---|
75ec5283 PA |
1 | /* Copyright (C) 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 Philippe Antoine <p.antoine@catenacyber.fr> | |
22 | * | |
23 | */ | |
24 | ||
25 | #include "suricata-common.h" | |
26 | ||
27 | #include "util-byte.h" | |
28 | #include "detect-parse.h" | |
29 | #include "detect-engine-uint.h" | |
30 | ||
31 | /** | |
32 | * \brief Regex for parsing our options | |
33 | */ | |
34 | #define PARSE_REGEX "^\\s*([0-9]*)?\\s*([<>=-]+)?\\s*([0-9]+)?\\s*$" | |
35 | ||
4b0085b0 | 36 | static DetectParseRegex uint_pcre; |
75ec5283 PA |
37 | |
38 | ||
39 | int DetectU32Match(const uint32_t parg, const DetectU32Data *du32) | |
40 | { | |
41 | switch (du32->mode) { | |
42 | case DETECT_UINT_EQ: | |
43 | if (parg == du32->arg1) { | |
44 | return 1; | |
45 | } | |
46 | return 0; | |
47 | case DETECT_UINT_LT: | |
48 | if (parg < du32->arg1) { | |
49 | return 1; | |
50 | } | |
51 | return 0; | |
b80cdae1 | 52 | case DETECT_UINT_LTE: |
53 | if (parg <= du32->arg1) { | |
54 | return 1; | |
55 | } | |
56 | return 0; | |
75ec5283 PA |
57 | case DETECT_UINT_GT: |
58 | if (parg > du32->arg1) { | |
59 | return 1; | |
60 | } | |
61 | return 0; | |
b80cdae1 | 62 | case DETECT_UINT_GTE: |
63 | if (parg >= du32->arg1) { | |
64 | return 1; | |
65 | } | |
66 | return 0; | |
75ec5283 PA |
67 | case DETECT_UINT_RA: |
68 | if (parg > du32->arg1 && parg < du32->arg2) { | |
69 | return 1; | |
70 | } | |
71 | return 0; | |
72 | default: | |
73 | BUG_ON("unknown mode"); | |
74 | } | |
75 | return 0; | |
76 | } | |
77 | ||
3f15b249 PA |
78 | static int DetectU32Validate(DetectU32Data *du32) |
79 | { | |
80 | switch (du32->mode) { | |
81 | case DETECT_UINT_LT: | |
82 | if (du32->arg1 == 0) { | |
83 | return 1; | |
84 | } | |
85 | break; | |
86 | case DETECT_UINT_GT: | |
87 | if (du32->arg1 == UINT32_MAX) { | |
88 | return 1; | |
89 | } | |
90 | break; | |
91 | case DETECT_UINT_RA: | |
92 | if (du32->arg1 >= du32->arg2) { | |
93 | return 1; | |
94 | } | |
95 | // we need at least one value that can match parg > du32->arg1 && parg < du32->arg2 | |
96 | if (du32->arg1 + 1 >= du32->arg2) { | |
97 | return 1; | |
98 | } | |
99 | break; | |
100 | default: | |
101 | break; | |
102 | } | |
103 | return 0; | |
104 | } | |
75ec5283 PA |
105 | |
106 | /** | |
107 | * \brief This function is used to parse u32 options passed via some u32 keyword | |
108 | * | |
109 | * \param u32str Pointer to the user provided u32 options | |
110 | * | |
111 | * \retval DetectU32Data pointer to DetectU32Data on success | |
112 | * \retval NULL on failure | |
113 | */ | |
114 | ||
115 | DetectU32Data *DetectU32Parse (const char *u32str) | |
116 | { | |
5dc21b0e SS |
117 | /* We initialize these to please static checkers, these values will |
118 | either be updated or not used later on */ | |
119 | DetectU32Data u32da = {0, 0, 0}; | |
75ec5283 PA |
120 | DetectU32Data *u32d = NULL; |
121 | char arg1[16] = ""; | |
122 | char arg2[16] = ""; | |
123 | char arg3[16] = ""; | |
124 | ||
75ec5283 | 125 | int ret = 0, res = 0; |
3de99a21 | 126 | size_t pcre2len; |
75ec5283 | 127 | |
3de99a21 | 128 | ret = DetectParsePcreExec(&uint_pcre, u32str, 0, 0); |
75ec5283 PA |
129 | if (ret < 2 || ret > 4) { |
130 | SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); | |
131 | return NULL; | |
132 | } | |
133 | ||
3de99a21 PA |
134 | pcre2len = sizeof(arg1); |
135 | res = pcre2_substring_copy_bynumber(uint_pcre.match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); | |
75ec5283 | 136 | if (res < 0) { |
3de99a21 | 137 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed"); |
75ec5283 PA |
138 | return NULL; |
139 | } | |
140 | SCLogDebug("Arg1 \"%s\"", arg1); | |
141 | ||
142 | if (ret >= 3) { | |
3de99a21 PA |
143 | pcre2len = sizeof(arg2); |
144 | res = pcre2_substring_copy_bynumber(uint_pcre.match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len); | |
75ec5283 | 145 | if (res < 0) { |
3de99a21 | 146 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed"); |
75ec5283 PA |
147 | return NULL; |
148 | } | |
149 | SCLogDebug("Arg2 \"%s\"", arg2); | |
150 | ||
151 | if (ret >= 4) { | |
3de99a21 PA |
152 | pcre2len = sizeof(arg3); |
153 | res = pcre2_substring_copy_bynumber( | |
154 | uint_pcre.match, 3, (PCRE2_UCHAR8 *)arg3, &pcre2len); | |
75ec5283 | 155 | if (res < 0) { |
3de99a21 | 156 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed"); |
75ec5283 PA |
157 | return NULL; |
158 | } | |
159 | SCLogDebug("Arg3 \"%s\"", arg3); | |
160 | } | |
161 | } | |
162 | ||
163 | if (strlen(arg2) > 0) { | |
164 | /*set the values*/ | |
165 | switch(arg2[0]) { | |
166 | case '<': | |
167 | case '>': | |
168 | if (strlen(arg3) == 0) | |
169 | return NULL; | |
170 | ||
171 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg3), arg3) < 0) { | |
172 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | SCLogDebug("u32 is %"PRIu32"",u32da.arg1); | |
177 | if (strlen(arg1) > 0) | |
178 | return NULL; | |
179 | ||
180 | if (arg2[0] == '<') { | |
b80cdae1 | 181 | if (arg2[1] == '=') { |
182 | u32da.mode = DETECT_UINT_LTE; | |
183 | } else { | |
184 | u32da.mode = DETECT_UINT_LT; | |
185 | } | |
75ec5283 | 186 | } else { // arg2[0] == '>' |
b80cdae1 | 187 | if (arg2[1] == '=') { |
188 | u32da.mode = DETECT_UINT_GTE; | |
189 | } else { | |
190 | u32da.mode = DETECT_UINT_GT; | |
191 | } | |
75ec5283 PA |
192 | } |
193 | break; | |
194 | case '-': | |
195 | if (strlen(arg1)== 0) | |
196 | return NULL; | |
197 | if (strlen(arg3)== 0) | |
198 | return NULL; | |
199 | ||
200 | u32da.mode = DETECT_UINT_RA; | |
201 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) { | |
202 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
203 | return NULL; | |
204 | } | |
205 | if (ByteExtractStringUint32(&u32da.arg2, 10, strlen(arg3), arg3) < 0) { | |
206 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
207 | return NULL; | |
208 | } | |
209 | ||
210 | SCLogDebug("u32 is %"PRIu32" to %"PRIu32"", u32da.arg1, u32da.arg2); | |
211 | if (u32da.arg1 >= u32da.arg2) { | |
212 | SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid u32 range. "); | |
213 | return NULL; | |
214 | } | |
215 | break; | |
216 | default: | |
217 | u32da.mode = DETECT_UINT_EQ; | |
218 | ||
219 | if (strlen(arg2) > 0 || | |
220 | strlen(arg3) > 0 || | |
221 | strlen(arg1) == 0) | |
222 | return NULL; | |
223 | ||
224 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) { | |
225 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
226 | return NULL; | |
227 | } | |
228 | } | |
229 | } else { | |
230 | u32da.mode = DETECT_UINT_EQ; | |
231 | ||
232 | if (strlen(arg3) > 0 || | |
233 | strlen(arg1) == 0) | |
234 | return NULL; | |
235 | ||
236 | if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) { | |
237 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed"); | |
238 | return NULL; | |
239 | } | |
240 | } | |
3f15b249 PA |
241 | if (DetectU32Validate(&u32da)) { |
242 | SCLogError(SC_ERR_INVALID_VALUE, "Impossible value for uint32 condition : %s", u32str); | |
243 | return NULL; | |
244 | } | |
75ec5283 PA |
245 | u32d = SCCalloc(1, sizeof (DetectU32Data)); |
246 | if (unlikely(u32d == NULL)) | |
247 | return NULL; | |
248 | u32d->arg1 = u32da.arg1; | |
249 | u32d->arg2 = u32da.arg2; | |
250 | u32d->mode = u32da.mode; | |
251 | ||
252 | return u32d; | |
253 | } | |
254 | ||
255 | void | |
256 | PrefilterPacketU32Set(PrefilterPacketHeaderValue *v, void *smctx) | |
257 | { | |
258 | const DetectU32Data *a = smctx; | |
259 | v->u8[0] = a->mode; | |
260 | v->u32[1] = a->arg1; | |
261 | v->u32[2] = a->arg2; | |
262 | } | |
263 | ||
264 | bool | |
265 | PrefilterPacketU32Compare(PrefilterPacketHeaderValue v, void *smctx) | |
266 | { | |
267 | const DetectU32Data *a = smctx; | |
268 | if (v.u8[0] == a->mode && | |
269 | v.u32[1] == a->arg1 && | |
270 | v.u32[2] == a->arg2) | |
271 | return true; | |
272 | return false; | |
273 | } | |
274 | ||
a5572890 | 275 | static bool g_detect_uint_registered = false; |
75ec5283 | 276 | |
a5572890 | 277 | void DetectUintRegister(void) |
75ec5283 | 278 | { |
a5572890 | 279 | if (g_detect_uint_registered == false) { |
75ec5283 | 280 | // register only once |
4b0085b0 | 281 | DetectSetupParseRegexes(PARSE_REGEX, &uint_pcre); |
a5572890 | 282 | g_detect_uint_registered = true; |
75ec5283 PA |
283 | } |
284 | } | |
a5572890 PA |
285 | |
286 | //same as u32 but with u8 | |
287 | int DetectU8Match(const uint8_t parg, const DetectU8Data *du8) | |
288 | { | |
289 | switch (du8->mode) { | |
290 | case DETECT_UINT_EQ: | |
291 | if (parg == du8->arg1) { | |
292 | return 1; | |
293 | } | |
294 | return 0; | |
295 | case DETECT_UINT_LT: | |
296 | if (parg < du8->arg1) { | |
297 | return 1; | |
298 | } | |
299 | return 0; | |
b80cdae1 | 300 | case DETECT_UINT_LTE: |
301 | if (parg <= du8->arg1) { | |
302 | return 1; | |
303 | } | |
304 | return 0; | |
a5572890 PA |
305 | case DETECT_UINT_GT: |
306 | if (parg > du8->arg1) { | |
307 | return 1; | |
308 | } | |
309 | return 0; | |
b80cdae1 | 310 | case DETECT_UINT_GTE: |
311 | if (parg >= du8->arg1) { | |
312 | return 1; | |
313 | } | |
314 | return 0; | |
a5572890 PA |
315 | case DETECT_UINT_RA: |
316 | if (parg > du8->arg1 && parg < du8->arg2) { | |
317 | return 1; | |
318 | } | |
319 | return 0; | |
320 | default: | |
321 | BUG_ON("unknown mode"); | |
322 | } | |
323 | return 0; | |
324 | } | |
325 | ||
3f15b249 PA |
326 | static int DetectU8Validate(DetectU8Data *du8) |
327 | { | |
328 | switch (du8->mode) { | |
329 | case DETECT_UINT_LT: | |
330 | if (du8->arg1 == 0) { | |
331 | return 1; | |
332 | } | |
333 | break; | |
334 | case DETECT_UINT_GT: | |
335 | if (du8->arg1 == UINT8_MAX) { | |
336 | return 1; | |
337 | } | |
338 | break; | |
339 | case DETECT_UINT_RA: | |
340 | if (du8->arg1 >= du8->arg2) { | |
341 | return 1; | |
342 | } | |
343 | // we need at least one value that can match parg > du8->arg1 && parg < du8->arg2 | |
344 | if (du8->arg1 + 1 >= du8->arg2) { | |
345 | return 1; | |
346 | } | |
347 | break; | |
348 | default: | |
349 | break; | |
350 | } | |
351 | return 0; | |
352 | } | |
353 | ||
a5572890 PA |
354 | /** |
355 | * \brief This function is used to parse u8 options passed via some u8 keyword | |
356 | * | |
357 | * \param u8str Pointer to the user provided u8 options | |
358 | * | |
359 | * \retval DetectU8Data pointer to DetectU8Data on success | |
360 | * \retval NULL on failure | |
361 | */ | |
362 | ||
363 | DetectU8Data *DetectU8Parse (const char *u8str) | |
364 | { | |
5dc21b0e SS |
365 | /* We initialize these to please static checkers, these values will |
366 | either be updated or not used later on */ | |
367 | DetectU8Data u8da = {0, 0, 0}; | |
a5572890 PA |
368 | DetectU8Data *u8d = NULL; |
369 | char arg1[16] = ""; | |
370 | char arg2[16] = ""; | |
371 | char arg3[16] = ""; | |
372 | ||
373 | int ret = 0, res = 0; | |
3de99a21 | 374 | size_t pcre2len; |
a5572890 | 375 | |
3de99a21 | 376 | ret = DetectParsePcreExec(&uint_pcre, u8str, 0, 0); |
a5572890 PA |
377 | if (ret < 2 || ret > 4) { |
378 | SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret); | |
379 | return NULL; | |
380 | } | |
381 | ||
3de99a21 PA |
382 | pcre2len = sizeof(arg1); |
383 | res = pcre2_substring_copy_bynumber(uint_pcre.match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); | |
a5572890 | 384 | if (res < 0) { |
3de99a21 | 385 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed"); |
a5572890 PA |
386 | return NULL; |
387 | } | |
388 | SCLogDebug("Arg1 \"%s\"", arg1); | |
389 | ||
390 | if (ret >= 3) { | |
3de99a21 PA |
391 | pcre2len = sizeof(arg2); |
392 | res = pcre2_substring_copy_bynumber(uint_pcre.match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len); | |
a5572890 | 393 | if (res < 0) { |
3de99a21 | 394 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed"); |
a5572890 PA |
395 | return NULL; |
396 | } | |
397 | SCLogDebug("Arg2 \"%s\"", arg2); | |
398 | ||
399 | if (ret >= 4) { | |
3de99a21 PA |
400 | pcre2len = sizeof(arg3); |
401 | res = pcre2_substring_copy_bynumber( | |
402 | uint_pcre.match, 3, (PCRE2_UCHAR8 *)arg3, &pcre2len); | |
a5572890 | 403 | if (res < 0) { |
3de99a21 | 404 | SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed"); |
a5572890 PA |
405 | return NULL; |
406 | } | |
407 | SCLogDebug("Arg3 \"%s\"", arg3); | |
408 | } | |
409 | } | |
410 | ||
411 | if (strlen(arg2) > 0) { | |
412 | /*set the values*/ | |
413 | switch(arg2[0]) { | |
414 | case '<': | |
415 | case '>': | |
416 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg3), arg3) < 0) { | |
417 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
418 | return NULL; | |
419 | } | |
420 | ||
421 | SCLogDebug("u8 is %"PRIu8"",u8da.arg1); | |
422 | if (strlen(arg1) > 0) | |
423 | return NULL; | |
424 | ||
425 | if (arg2[0] == '<') { | |
b80cdae1 | 426 | if (arg2[1] == '=') { |
427 | u8da.mode = DETECT_UINT_LTE; | |
428 | } else { | |
429 | u8da.mode = DETECT_UINT_LT; | |
430 | } | |
a5572890 | 431 | } else { // arg2[0] == '>' |
b80cdae1 | 432 | if (arg2[1] == '=') { |
433 | u8da.mode = DETECT_UINT_GTE; | |
434 | } else { | |
435 | u8da.mode = DETECT_UINT_GT; | |
436 | } | |
a5572890 PA |
437 | } |
438 | break; | |
439 | case '-': | |
440 | u8da.mode = DETECT_UINT_RA; | |
441 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) { | |
442 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
443 | return NULL; | |
444 | } | |
445 | if (StringParseUint8(&u8da.arg2, 10, strlen(arg3), arg3) < 0) { | |
446 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
447 | return NULL; | |
448 | } | |
449 | ||
450 | SCLogDebug("u8 is %"PRIu8" to %"PRIu8"", u8da.arg1, u8da.arg2); | |
451 | if (u8da.arg1 >= u8da.arg2) { | |
452 | SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid u8 range. "); | |
453 | return NULL; | |
454 | } | |
455 | break; | |
456 | default: | |
457 | u8da.mode = DETECT_UINT_EQ; | |
458 | ||
459 | if (strlen(arg2) > 0 || | |
460 | strlen(arg3) > 0) | |
461 | return NULL; | |
462 | ||
463 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) { | |
464 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
465 | return NULL; | |
466 | } | |
467 | } | |
468 | } else { | |
469 | u8da.mode = DETECT_UINT_EQ; | |
470 | ||
471 | if (strlen(arg3) > 0) | |
472 | return NULL; | |
473 | ||
474 | if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) { | |
475 | SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed"); | |
476 | return NULL; | |
477 | } | |
478 | } | |
3f15b249 PA |
479 | if (DetectU8Validate(&u8da)) { |
480 | SCLogError(SC_ERR_INVALID_VALUE, "Impossible value for uint8 condition : %s", u8str); | |
481 | return NULL; | |
482 | } | |
a5572890 PA |
483 | u8d = SCCalloc(1, sizeof (DetectU8Data)); |
484 | if (unlikely(u8d == NULL)) | |
485 | return NULL; | |
486 | u8d->arg1 = u8da.arg1; | |
487 | u8d->arg2 = u8da.arg2; | |
488 | u8d->mode = u8da.mode; | |
489 | ||
490 | return u8d; | |
491 | } |