suricata
detect-mark.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-2021 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 Eric Leblond <eric@regit.org>
22  *
23  * Implements the mark keyword. Based on detect-gid
24  * by Breno Silva <breno.silva@gmail.com>
25  */
26 
27 #include "suricata-common.h"
28 #include "suricata.h"
29 #include "decode.h"
30 #include "detect.h"
31 #include "flow-var.h"
32 #include "decode-events.h"
33 
34 #include "detect-mark.h"
35 #include "detect-parse.h"
36 
37 #include "util-unittest.h"
38 #include "util-byte.h"
39 #include "util-debug.h"
40 
41 #define PARSE_REGEX "([0x]*[0-9a-f]+)/([0x]*[0-9a-f]+)"
42 
43 static DetectParseRegex parse_regex;
44 
45 static int DetectMarkSetup (DetectEngineCtx *, Signature *, const char *);
46 static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p,
47  const Signature *s, const SigMatchCtx *ctx);
48 void DetectMarkDataFree(DetectEngineCtx *, void *ptr);
49 #if defined UNITTESTS && defined NFQ
50 static void MarkRegisterTests(void);
51 #endif
52 
53 /**
54  * \brief Registration function for nfq_set_mark: keyword
55  */
56 
57 void DetectMarkRegister (void)
58 {
59  sigmatch_table[DETECT_MARK].name = "nfq_set_mark";
60  sigmatch_table[DETECT_MARK].Match = DetectMarkPacket;
61  sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup;
63 #if defined UNITTESTS && defined NFQ
64  sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests;
65 #endif
66  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
67 }
68 
69 #ifdef NFQ
70 /**
71  * \internal
72  * \brief This function is used to parse mark options passed via mark: keyword
73  *
74  * \param rawstr Pointer to the user provided mark options
75  *
76  * \retval 0 on success
77  * \retval < 0 on failure
78  */
79 static void * DetectMarkParse (const char *rawstr)
80 {
81  int res = 0;
82  size_t pcre2_len;
83  const char *str_ptr = NULL;
84  char *ptr = NULL;
85  uint32_t mark;
86  uint32_t mask;
87  DetectMarkData *data;
88 
89  pcre2_match_data *match = NULL;
90  int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
91  if (ret < 1) {
92  SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
93  pcre2_match_data_free(match);
94  return NULL;
95  }
96 
97  res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
98  if (res < 0) {
99  SCLogError("pcre2_substring_get_bynumber failed");
100  goto error;
101  }
102 
103  ptr = (char *)str_ptr;
104 
105  if (ptr == NULL)
106  goto error;
107 
108  if (ByteExtractStringUint32(&mark, 0, strlen(ptr), ptr) <= 0) {
109  SCLogError("invalid input as arg to nfq_set_mark keyword");
110  pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
111  goto error;
112  }
113 
114  res = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
115  if (res < 0) {
116  SCLogError("pcre2_substring_get_bynumber failed");
117  goto error;
118  }
119 
120  pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
121  ptr = (char *)str_ptr;
122 
123  if (ptr == NULL) {
124  data = SCMalloc(sizeof(DetectMarkData));
125  if (unlikely(data == NULL)) {
126  goto error;
127  }
128  data->mark = mark;
129  data->mask = 0xffff;
130  pcre2_match_data_free(match);
131  return data;
132  }
133 
134  if (ByteExtractStringUint32(&mask, 0, strlen(ptr), ptr) <= 0) {
135  SCLogError("invalid input as arg to nfq_set_mark keyword");
136  pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
137  goto error;
138  }
139 
140  SCLogDebug("Rule will set mark 0x%x with mask 0x%x", mark, mask);
141  pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
142 
143  data = SCMalloc(sizeof(DetectMarkData));
144  if (unlikely(data == NULL)) {
145  goto error;
146  }
147  data->mark = mark;
148  data->mask = mask;
149  pcre2_match_data_free(match);
150  return data;
151 
152 error:
153  if (match) {
154  pcre2_match_data_free(match);
155  }
156  return NULL;
157 }
158 
159 #endif /* NFQ */
160 
161 /**
162  * \internal
163  * \brief this function is used to add the parsed mark into the current signature
164  *
165  * \param de_ctx pointer to the Detection Engine Context
166  * \param s pointer to the Current Signature
167  * \param rawstr pointer to the user provided mark options
168  *
169  * \retval 0 on Success
170  * \retval -1 on Failure
171  */
172 static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
173 {
174 #ifndef NFQ
175  return 0;
176 #else
177  DetectMarkData *data = DetectMarkParse(rawstr);
178  if (data == NULL) {
179  return -1;
180  }
181 
182  /* Append it to the list of post match, so the mark is set if the
183  * full signature matches. */
185  de_ctx, s, DETECT_MARK, (SigMatchCtx *)data, DETECT_SM_LIST_POSTMATCH) == NULL) {
186  DetectMarkDataFree(de_ctx, data);
187  return -1;
188  }
189  return 0;
190 #endif
191 }
192 
194 {
195  DetectMarkData *data = (DetectMarkData *)ptr;
196  SCFree(data);
197 }
198 
199 
200 static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p,
201  const Signature *s, const SigMatchCtx *ctx)
202 {
203 #ifdef NFQ
204  const DetectMarkData *nf_data = (const DetectMarkData *)ctx;
205  if (nf_data->mask) {
206  if (PacketIsNotTunnel(p)) {
207  /* for a non-tunnel packet we don't need a lock,
208  * and if we're here we can't turn into a tunnel
209  * packet anymore. */
210 
211  /* coverity[missing_lock] */
212  p->nfq_v.mark = (nf_data->mark & nf_data->mask)
213  | (p->nfq_v.mark & ~(nf_data->mask));
214  /* coverity[missing_lock] */
215  p->nfq_v.mark_modified = true;
216  } else {
217  /* real tunnels may have multiple flows inside them, so marking
218  * might 'mark' too much. Rebuilt packets from IP fragments
219  * are fine. */
220  if (p->flags & PKT_REBUILT_FRAGMENT) {
221  Packet *tp = p->root ? p->root : p;
223  tp->nfq_v.mark = (nf_data->mark & nf_data->mask)
224  | (tp->nfq_v.mark & ~(nf_data->mask));
225  tp->nfq_v.mark_modified = true;
227  }
228  }
229  }
230 #endif
231  return 1;
232 }
233 
234 /*
235  * ONLY TESTS BELOW THIS COMMENT
236  */
237 
238 #if defined UNITTESTS && defined NFQ
239 /**
240  * \test MarkTestParse01 is a test for a valid mark value
241  *
242  */
243 static int MarkTestParse01 (void)
244 {
245  DetectMarkData *data;
246 
247  data = DetectMarkParse("1/1");
248 
249  FAIL_IF_NULL(data);
250  FAIL_IF(data->mark != 1);
251  FAIL_IF(data->mask != 1);
252 
253  DetectMarkDataFree(NULL, data);
254  PASS;
255 }
256 
257 /**
258  * \test MarkTestParse02 is a test for an invalid mark value
259  *
260  */
261 static int MarkTestParse02 (void)
262 {
263  DetectMarkData *data;
264 
265  data = DetectMarkParse("4");
266 
267  FAIL_IF_NOT_NULL(data);
268 
269  DetectMarkDataFree(NULL, data);
270  PASS;
271 }
272 
273 /**
274  * \test MarkTestParse03 is a test for a valid mark value
275  *
276  */
277 static int MarkTestParse03 (void)
278 {
279  DetectMarkData *data;
280 
281  data = DetectMarkParse("0x10/0xff");
282  FAIL_IF(data->mark != 0x10);
283  FAIL_IF(data->mask != 0xff);
284 
285  FAIL_IF_NULL(data);
286 
287  DetectMarkDataFree(NULL, data);
288  PASS;
289 }
290 
291 /**
292  * \test MarkTestParse04 is a test for a invalid mark value
293  *
294  */
295 static int MarkTestParse04 (void)
296 {
297  DetectMarkData *data;
298 
299  data = DetectMarkParse("0x1g/0xff");
300 
301  FAIL_IF_NOT_NULL(data);
302 
303  DetectMarkDataFree(NULL, data);
304  PASS;
305 }
306 
307 /**
308  * \brief this function registers unit tests for Mark
309  */
310 static void MarkRegisterTests(void)
311 {
312  UtRegisterTest("MarkTestParse01", MarkTestParse01);
313  UtRegisterTest("MarkTestParse02", MarkTestParse02);
314  UtRegisterTest("MarkTestParse03", MarkTestParse03);
315  UtRegisterTest("MarkTestParse04", MarkTestParse04);
316 }
317 #endif /* UNITTESTS */
util-byte.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1446
DetectParseRegex
Definition: detect-parse.h:93
SigTableElmt_::name
const char * name
Definition: detect.h:1459
detect-mark.h
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:275
PARSE_REGEX
#define PARSE_REGEX
Definition: detect-mark.c:41
Packet_::flags
uint32_t flags
Definition: decode.h:544
DETECT_MARK
@ DETECT_MARK
Definition: detect-engine-register.h:124
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
DetectMarkData_
Definition: detect-mark.h:41
SCSpinLock
#define SCSpinLock
Definition: threads-debug.h:235
Packet_::persistent
struct Packet_::@39 persistent
ByteExtractStringUint32
int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:239
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3491
NFQPacketVars_::mark
uint32_t mark
Definition: source-nfq.h:46
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1441
util-unittest.h
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:127
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1244
Packet_::tunnel_lock
SCSpinlock tunnel_lock
Definition: decode.h:683
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3617
SCSigMatchAppendSMToList
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:388
detect.h
SCSpinUnlock
#define SCSpinUnlock
Definition: threads-debug.h:237
Packet_
Definition: decode.h:501
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1421
DetectMarkRegister
void DetectMarkRegister(void)
Registration function for nfq_set_mark: keyword.
Definition: detect-mark.c:57
decode-events.h
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
Packet_::nfq_v
NFQPacketVars nfq_v
Definition: decode.h:563
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
DetectMarkDataFree
void DetectMarkDataFree(DetectEngineCtx *, void *ptr)
Definition: detect-mark.c:193
suricata-common.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
Packet_::root
struct Packet_ * root
Definition: decode.h:653
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1302
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:267
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
NFQPacketVars_::mark_modified
bool mark_modified
Definition: source-nfq.h:44
suricata.h
DetectMarkData_::mark
uint32_t mark
Definition: detect-mark.h:42
DetectMarkData_::mask
uint32_t mask
Definition: detect-mark.h:43
flow-var.h
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1448