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