]> git.ipfire.org Git - people/ms/suricata.git/blob - src/detect-engine-uint.c
d44c6bfaf2e11766f8b955b9a075d10f06704ae1
[people/ms/suricata.git] / src / detect-engine-uint.c
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
36 static DetectParseRegex uint_pcre;
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;
52 case DETECT_UINT_LTE:
53 if (parg <= du32->arg1) {
54 return 1;
55 }
56 return 0;
57 case DETECT_UINT_GT:
58 if (parg > du32->arg1) {
59 return 1;
60 }
61 return 0;
62 case DETECT_UINT_GTE:
63 if (parg >= du32->arg1) {
64 return 1;
65 }
66 return 0;
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
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 }
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 {
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};
120 DetectU32Data *u32d = NULL;
121 char arg1[16] = "";
122 char arg2[16] = "";
123 char arg3[16] = "";
124
125 int ret = 0, res = 0;
126 size_t pcre2len;
127
128 ret = DetectParsePcreExec(&uint_pcre, u32str, 0, 0);
129 if (ret < 2 || ret > 4) {
130 SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
131 return NULL;
132 }
133
134 pcre2len = sizeof(arg1);
135 res = pcre2_substring_copy_bynumber(uint_pcre.match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len);
136 if (res < 0) {
137 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed");
138 return NULL;
139 }
140 SCLogDebug("Arg1 \"%s\"", arg1);
141
142 if (ret >= 3) {
143 pcre2len = sizeof(arg2);
144 res = pcre2_substring_copy_bynumber(uint_pcre.match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len);
145 if (res < 0) {
146 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed");
147 return NULL;
148 }
149 SCLogDebug("Arg2 \"%s\"", arg2);
150
151 if (ret >= 4) {
152 pcre2len = sizeof(arg3);
153 res = pcre2_substring_copy_bynumber(
154 uint_pcre.match, 3, (PCRE2_UCHAR8 *)arg3, &pcre2len);
155 if (res < 0) {
156 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed");
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(arg2) == 1) {
169 if (strlen(arg3) == 0)
170 return NULL;
171
172 if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg3), arg3) < 0) {
173 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed");
174 return NULL;
175 }
176
177 SCLogDebug("u32 is %" PRIu32 "", u32da.arg1);
178 if (strlen(arg1) > 0)
179 return NULL;
180
181 if (arg2[0] == '<') {
182 u32da.mode = DETECT_UINT_LT;
183 } else { // arg2[0] == '>'
184 u32da.mode = DETECT_UINT_GT;
185 }
186 break;
187 } else if (strlen(arg2) == 2) {
188 if (arg2[0] == '<' && arg2[1] == '=') {
189 u32da.mode = DETECT_UINT_LTE;
190 break;
191 } else if (arg2[0] == '>' || arg2[1] == '=') {
192 u32da.mode = DETECT_UINT_GTE;
193 break;
194 } else if (arg2[0] != '<' || arg2[1] != '>') {
195 return NULL;
196 }
197 } else {
198 return NULL;
199 }
200 // fall through
201 case '-':
202 if (strlen(arg1)== 0)
203 return NULL;
204 if (strlen(arg3)== 0)
205 return NULL;
206
207 u32da.mode = DETECT_UINT_RA;
208 if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) {
209 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed");
210 return NULL;
211 }
212 if (ByteExtractStringUint32(&u32da.arg2, 10, strlen(arg3), arg3) < 0) {
213 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed");
214 return NULL;
215 }
216
217 SCLogDebug("u32 is %"PRIu32" to %"PRIu32"", u32da.arg1, u32da.arg2);
218 if (u32da.arg1 >= u32da.arg2) {
219 SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid u32 range. ");
220 return NULL;
221 }
222 break;
223 default:
224 u32da.mode = DETECT_UINT_EQ;
225
226 if (strlen(arg2) > 0 ||
227 strlen(arg3) > 0 ||
228 strlen(arg1) == 0)
229 return NULL;
230
231 if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) {
232 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed");
233 return NULL;
234 }
235 }
236 } else {
237 u32da.mode = DETECT_UINT_EQ;
238
239 if (strlen(arg3) > 0 ||
240 strlen(arg1) == 0)
241 return NULL;
242
243 if (ByteExtractStringUint32(&u32da.arg1, 10, strlen(arg1), arg1) < 0) {
244 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint32 failed");
245 return NULL;
246 }
247 }
248 if (DetectU32Validate(&u32da)) {
249 SCLogError(SC_ERR_INVALID_VALUE, "Impossible value for uint32 condition : %s", u32str);
250 return NULL;
251 }
252 u32d = SCCalloc(1, sizeof (DetectU32Data));
253 if (unlikely(u32d == NULL))
254 return NULL;
255 u32d->arg1 = u32da.arg1;
256 u32d->arg2 = u32da.arg2;
257 u32d->mode = u32da.mode;
258
259 return u32d;
260 }
261
262 void
263 PrefilterPacketU32Set(PrefilterPacketHeaderValue *v, void *smctx)
264 {
265 const DetectU32Data *a = smctx;
266 v->u8[0] = a->mode;
267 v->u32[1] = a->arg1;
268 v->u32[2] = a->arg2;
269 }
270
271 bool
272 PrefilterPacketU32Compare(PrefilterPacketHeaderValue v, void *smctx)
273 {
274 const DetectU32Data *a = smctx;
275 if (v.u8[0] == a->mode &&
276 v.u32[1] == a->arg1 &&
277 v.u32[2] == a->arg2)
278 return true;
279 return false;
280 }
281
282 static bool g_detect_uint_registered = false;
283
284 void DetectUintRegister(void)
285 {
286 if (g_detect_uint_registered == false) {
287 // register only once
288 DetectSetupParseRegexes(PARSE_REGEX, &uint_pcre);
289 g_detect_uint_registered = true;
290 }
291 }
292
293 //same as u32 but with u8
294 int DetectU8Match(const uint8_t parg, const DetectU8Data *du8)
295 {
296 switch (du8->mode) {
297 case DETECT_UINT_EQ:
298 if (parg == du8->arg1) {
299 return 1;
300 }
301 return 0;
302 case DETECT_UINT_LT:
303 if (parg < du8->arg1) {
304 return 1;
305 }
306 return 0;
307 case DETECT_UINT_LTE:
308 if (parg <= du8->arg1) {
309 return 1;
310 }
311 return 0;
312 case DETECT_UINT_GT:
313 if (parg > du8->arg1) {
314 return 1;
315 }
316 return 0;
317 case DETECT_UINT_GTE:
318 if (parg >= du8->arg1) {
319 return 1;
320 }
321 return 0;
322 case DETECT_UINT_RA:
323 if (parg > du8->arg1 && parg < du8->arg2) {
324 return 1;
325 }
326 return 0;
327 default:
328 BUG_ON("unknown mode");
329 }
330 return 0;
331 }
332
333 static int DetectU8Validate(DetectU8Data *du8)
334 {
335 switch (du8->mode) {
336 case DETECT_UINT_LT:
337 if (du8->arg1 == 0) {
338 return 1;
339 }
340 break;
341 case DETECT_UINT_GT:
342 if (du8->arg1 == UINT8_MAX) {
343 return 1;
344 }
345 break;
346 case DETECT_UINT_RA:
347 if (du8->arg1 >= du8->arg2) {
348 return 1;
349 }
350 // we need at least one value that can match parg > du8->arg1 && parg < du8->arg2
351 if (du8->arg1 + 1 >= du8->arg2) {
352 return 1;
353 }
354 break;
355 default:
356 break;
357 }
358 return 0;
359 }
360
361 /**
362 * \brief This function is used to parse u8 options passed via some u8 keyword
363 *
364 * \param u8str Pointer to the user provided u8 options
365 *
366 * \retval DetectU8Data pointer to DetectU8Data on success
367 * \retval NULL on failure
368 */
369
370 DetectU8Data *DetectU8Parse (const char *u8str)
371 {
372 /* We initialize these to please static checkers, these values will
373 either be updated or not used later on */
374 DetectU8Data u8da = {0, 0, 0};
375 DetectU8Data *u8d = NULL;
376 char arg1[16] = "";
377 char arg2[16] = "";
378 char arg3[16] = "";
379
380 int ret = 0, res = 0;
381 size_t pcre2len;
382
383 ret = DetectParsePcreExec(&uint_pcre, u8str, 0, 0);
384 if (ret < 2 || ret > 4) {
385 SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
386 return NULL;
387 }
388
389 pcre2len = sizeof(arg1);
390 res = pcre2_substring_copy_bynumber(uint_pcre.match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len);
391 if (res < 0) {
392 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed");
393 return NULL;
394 }
395 SCLogDebug("Arg1 \"%s\"", arg1);
396
397 if (ret >= 3) {
398 pcre2len = sizeof(arg2);
399 res = pcre2_substring_copy_bynumber(uint_pcre.match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len);
400 if (res < 0) {
401 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed");
402 return NULL;
403 }
404 SCLogDebug("Arg2 \"%s\"", arg2);
405
406 if (ret >= 4) {
407 pcre2len = sizeof(arg3);
408 res = pcre2_substring_copy_bynumber(
409 uint_pcre.match, 3, (PCRE2_UCHAR8 *)arg3, &pcre2len);
410 if (res < 0) {
411 SCLogError(SC_ERR_PCRE_COPY_SUBSTRING, "pcre2_substring_copy_bynumber failed");
412 return NULL;
413 }
414 SCLogDebug("Arg3 \"%s\"", arg3);
415 }
416 }
417
418 if (strlen(arg2) > 0) {
419 /*set the values*/
420 switch(arg2[0]) {
421 case '<':
422 case '>':
423 if (strlen(arg2) == 1) {
424 if (StringParseUint8(&u8da.arg1, 10, strlen(arg3), arg3) < 0) {
425 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed");
426 return NULL;
427 }
428
429 SCLogDebug("u8 is %" PRIu8 "", u8da.arg1);
430 if (strlen(arg1) > 0)
431 return NULL;
432
433 if (arg2[0] == '<') {
434 u8da.mode = DETECT_UINT_LT;
435 } else { // arg2[0] == '>'
436 u8da.mode = DETECT_UINT_GT;
437 }
438 break;
439 } else if (strlen(arg2) == 2) {
440 if (arg2[0] == '<' && arg2[1] == '=') {
441 u8da.mode = DETECT_UINT_LTE;
442 break;
443 } else if (arg2[0] == '>' || arg2[1] == '=') {
444 u8da.mode = DETECT_UINT_GTE;
445 break;
446 } else if (arg2[0] != '<' || arg2[1] != '>') {
447 return NULL;
448 }
449 } else {
450 return NULL;
451 }
452 // fall through
453 case '-':
454 u8da.mode = DETECT_UINT_RA;
455 if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) {
456 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed");
457 return NULL;
458 }
459 if (StringParseUint8(&u8da.arg2, 10, strlen(arg3), arg3) < 0) {
460 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed");
461 return NULL;
462 }
463
464 SCLogDebug("u8 is %"PRIu8" to %"PRIu8"", u8da.arg1, u8da.arg2);
465 if (u8da.arg1 >= u8da.arg2) {
466 SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid u8 range. ");
467 return NULL;
468 }
469 break;
470 default:
471 u8da.mode = DETECT_UINT_EQ;
472
473 if (strlen(arg2) > 0 ||
474 strlen(arg3) > 0)
475 return NULL;
476
477 if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) {
478 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed");
479 return NULL;
480 }
481 }
482 } else {
483 u8da.mode = DETECT_UINT_EQ;
484
485 if (strlen(arg3) > 0)
486 return NULL;
487
488 if (StringParseUint8(&u8da.arg1, 10, strlen(arg1), arg1) < 0) {
489 SCLogError(SC_ERR_BYTE_EXTRACT_FAILED, "ByteExtractStringUint8 failed");
490 return NULL;
491 }
492 }
493 if (DetectU8Validate(&u8da)) {
494 SCLogError(SC_ERR_INVALID_VALUE, "Impossible value for uint8 condition : %s", u8str);
495 return NULL;
496 }
497 u8d = SCCalloc(1, sizeof (DetectU8Data));
498 if (unlikely(u8d == NULL))
499 return NULL;
500 u8d->arg1 = u8da.arg1;
501 u8d->arg2 = u8da.arg2;
502 u8d->mode = u8da.mode;
503
504 return u8d;
505 }