]> git.ipfire.org Git - people/ms/suricata.git/blame - src/detect-engine-uint.c
detect: errors for rule with impossible conditions
[people/ms/suricata.git] / src / detect-engine-uint.c
CommitLineData
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 36static DetectParseRegex uint_pcre;
75ec5283
PA
37
38
39int 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
78static 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
115DetectU32Data *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
255void
256PrefilterPacketU32Set(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
264bool
265PrefilterPacketU32Compare(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 275static bool g_detect_uint_registered = false;
75ec5283 276
a5572890 277void 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
287int 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
326static 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
363DetectU8Data *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}