suricata
detect-mark.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-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 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-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 
49 /**
50  * \brief Registration function for nfq_set_mark: keyword
51  */
52 
53 void DetectMarkRegister (void)
54 {
55  sigmatch_table[DETECT_MARK].name = "nfq_set_mark";
56  sigmatch_table[DETECT_MARK].Match = DetectMarkPacket;
57  sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup;
60 
61  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
62 }
63 
64 #ifdef NFQ
65 /**
66  * \internal
67  * \brief This function is used to parse mark options passed via mark: keyword
68  *
69  * \param rawstr Pointer to the user provided mark options
70  *
71  * \retval 0 on success
72  * \retval < 0 on failure
73  */
74 static void * DetectMarkParse (const char *rawstr)
75 {
76  int ret = 0, res = 0;
77  int ov[MAX_SUBSTRINGS];
78  const char *str_ptr = NULL;
79  char *ptr = NULL;
80  char *endptr = NULL;
81  uint32_t mark;
82  uint32_t mask;
83  DetectMarkData *data;
84 
85  ret = DetectParsePcreExec(&parse_regex, rawstr, 0, 0, ov, MAX_SUBSTRINGS);
86  if (ret < 1) {
87  SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
88  return NULL;
89  }
90 
91  res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
92  if (res < 0) {
93  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
94  return NULL;
95  }
96 
97  ptr = (char *)str_ptr;
98 
99  if (ptr == NULL)
100  return NULL;
101 
102  errno = 0;
103  mark = strtoul(ptr, &endptr, 0);
104  if (errno == ERANGE) {
105  SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range");
106  SCFree(ptr);
107  return NULL;
108  } /* If there is no numeric value in the given string then strtoull(), makes
109  endptr equals to ptr and return 0 as result */
110  else if (endptr == ptr && mark == 0) {
111  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "No numeric value");
112  SCFree(ptr);
113  return NULL;
114  } else if (endptr == ptr) {
115  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value");
116  SCFree(ptr);
117  return NULL;
118  }
119 
120  res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
121  if (res < 0) {
122  SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
123  return NULL;
124  }
125 
126  SCFree(ptr);
127  ptr = (char *)str_ptr;
128 
129  if (ptr == NULL) {
130  data = SCMalloc(sizeof(DetectMarkData));
131  if (unlikely(data == NULL)) {
132  return NULL;
133  }
134  data->mark = mark;
135  data->mask = 0xffff;
136  return data;
137  }
138 
139  errno = 0;
140  mask = strtoul(ptr, &endptr, 0);
141  if (errno == ERANGE) {
142  SCLogError(SC_ERR_NUMERIC_VALUE_ERANGE, "Numeric value out of range");
143  SCFree(ptr);
144  return NULL;
145  } /* If there is no numeric value in the given string then strtoull(), makes
146  endptr equals to ptr and return 0 as result */
147  else if (endptr == ptr && mask == 0) {
148  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "No numeric value");
149  SCFree(ptr);
150  return NULL;
151  }
152  else if (endptr == ptr) {
153  SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "Invalid numeric value");
154  SCFree(ptr);
155  return NULL;
156  }
157 
158  SCLogDebug("Rule will set mark 0x%x with mask 0x%x", mark, mask);
159  SCFree(ptr);
160 
161  data = SCMalloc(sizeof(DetectMarkData));
162  if (unlikely(data == NULL)) {
163  return NULL;
164  }
165  data->mark = mark;
166  data->mask = mask;
167  return data;
168 }
169 
170 #endif /* NFQ */
171 
172 /**
173  * \internal
174  * \brief this function is used to add the parsed mark into the current signature
175  *
176  * \param de_ctx pointer to the Detection Engine Context
177  * \param s pointer to the Current Signature
178  * \param rawstr pointer to the user provided mark options
179  *
180  * \retval 0 on Success
181  * \retval -1 on Failure
182  */
183 static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
184 {
185 #ifndef NFQ
186  return 0;
187 #else
188  DetectMarkData *data = DetectMarkParse(rawstr);
189  if (data == NULL) {
190  return -1;
191  }
192  SigMatch *sm = SigMatchAlloc();
193  if (sm == NULL) {
194  DetectMarkDataFree(de_ctx, data);
195  return -1;
196  }
197 
198  sm->type = DETECT_MARK;
199  sm->ctx = (SigMatchCtx *)data;
200 
201  /* Append it to the list of post match, so the mark is set if the
202  * full signature matches. */
204  return 0;
205 #endif
206 }
207 
209 {
210  DetectMarkData *data = (DetectMarkData *)ptr;
211  SCFree(data);
212 }
213 
214 
215 static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p,
216  const Signature *s, const SigMatchCtx *ctx)
217 {
218 #ifdef NFQ
219  const DetectMarkData *nf_data = (const DetectMarkData *)ctx;
220  if (nf_data->mask) {
221  if (!(IS_TUNNEL_PKT(p))) {
222  /* coverity[missing_lock] */
223  p->nfq_v.mark = (nf_data->mark & nf_data->mask)
224  | (p->nfq_v.mark & ~(nf_data->mask));
225  p->flags |= PKT_MARK_MODIFIED;
226  } else {
227  /* real tunnels may have multiple flows inside them, so marking
228  * might 'mark' too much. Rebuilt packets from IP fragments
229  * are fine. */
230  if (p->flags & PKT_REBUILT_FRAGMENT) {
231  Packet *tp = p->root ? p->root : p;
233  tp->nfq_v.mark = (nf_data->mark & nf_data->mask)
234  | (tp->nfq_v.mark & ~(nf_data->mask));
235  tp->flags |= PKT_MARK_MODIFIED;
237  }
238  }
239  }
240 #endif
241  return 1;
242 }
243 
244 /*
245  * ONLY TESTS BELOW THIS COMMENT
246  */
247 
248 #if defined UNITTESTS && defined NFQ
249 /**
250  * \test MarkTestParse01 is a test for a valid mark value
251  *
252  * \retval 1 on succces
253  * \retval 0 on failure
254  */
255 static int MarkTestParse01 (void)
256 {
257  DetectMarkData *data;
258 
259  data = DetectMarkParse("1/1");
260 
261  if (data == NULL) {
262  return 0;
263  }
264 
265  DetectMarkDataFree(NULL, data);
266  return 1;
267 }
268 
269 /**
270  * \test MarkTestParse02 is a test for an invalid mark value
271  *
272  * \retval 1 on succces
273  * \retval 0 on failure
274  */
275 static int MarkTestParse02 (void)
276 {
277  DetectMarkData *data;
278 
279  data = DetectMarkParse("4");
280 
281  if (data == NULL) {
282  return 1;
283  }
284 
285  DetectMarkDataFree(NULL, data);
286  return 0;
287 }
288 
289 /**
290  * \test MarkTestParse03 is a test for a valid mark value
291  *
292  * \retval 1 on succces
293  * \retval 0 on failure
294  */
295 static int MarkTestParse03 (void)
296 {
297  DetectMarkData *data;
298 
299  data = DetectMarkParse("0x10/0xff");
300 
301  if (data == NULL) {
302  return 0;
303  }
304 
305  DetectMarkDataFree(NULL, data);
306  return 1;
307 }
308 
309 /**
310  * \test MarkTestParse04 is a test for a invalid mark value
311  *
312  * \retval 1 on succces
313  * \retval 0 on failure
314  */
315 static int MarkTestParse04 (void)
316 {
317  DetectMarkData *data;
318 
319  data = DetectMarkParse("0x1g/0xff");
320 
321  if (data == NULL) {
322  return 1;
323  }
324 
325  DetectMarkDataFree(NULL, data);
326  return 0;
327 }
328 
329 
330 
331 #endif /* UNITTESTS */
332 
333 /**
334  * \brief this function registers unit tests for Mark
335  */
337 {
338 #if defined UNITTESTS && defined NFQ
339  UtRegisterTest("MarkTestParse01", MarkTestParse01);
340  UtRegisterTest("MarkTestParse02", MarkTestParse02);
341  UtRegisterTest("MarkTestParse03", MarkTestParse03);
342  UtRegisterTest("MarkTestParse04", MarkTestParse04);
343 #endif /* UNITTESTS */
344 }
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1200
SigTableElmt_::name
const char * name
Definition: detect.h:1209
detect-mark.h
MAX_SUBSTRINGS
#define MAX_SUBSTRINGS
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:298
PARSE_REGEX
#define PARSE_REGEX
Definition: detect-mark.c:40
Packet_::flags
uint32_t flags
Definition: decode.h:446
DETECT_MARK
@ DETECT_MARK
Definition: detect-engine-register.h:102
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:766
DetectMarkData_
Definition: detect-mark.h:44
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
NFQPacketVars_::mark
uint32_t mark
Definition: source-nfq.h:45
SC_ERR_PCRE_GET_SUBSTRING
@ SC_ERR_PCRE_GET_SUBSTRING
Definition: util-error.h:34
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1195
util-unittest.h
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:98
decode.h
util-debug.h
SC_ERR_PCRE_MATCH
@ SC_ERR_PCRE_MATCH
Definition: util-error.h:32
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1009
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:2470
detect.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:322
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, const char *str, int start_offset, int options, int *ovector, int ovector_size)
Definition: detect-parse.c:2400
Packet_
Definition: decode.h:411
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1178
IS_TUNNEL_PKT
#define IS_TUNNEL_PKT(p)
Definition: decode.h:874
DetectMarkRegister
void DetectMarkRegister(void)
Registration function for nfq_set_mark: keyword.
Definition: detect-mark.c:53
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
decode-events.h
SigMatch_::type
uint8_t type
Definition: detect.h:320
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:314
Packet_::nfq_v
NFQPacketVars nfq_v
Definition: decode.h:462
MarkRegisterTests
void MarkRegisterTests(void)
this function registers unit tests for Mark
Definition: detect-mark.c:336
DetectMarkDataFree
void DetectMarkDataFree(DetectEngineCtx *, void *ptr)
Definition: detect-mark.c:208
suricata-common.h
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectParseRegex_
Definition: detect-parse.h:42
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
Packet_::root
struct Packet_ * root
Definition: decode.h:580
PKT_REBUILT_FRAGMENT
#define PKT_REBUILT_FRAGMENT
Definition: decode.h:1114
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SC_ERR_NUMERIC_VALUE_ERANGE
@ SC_ERR_NUMERIC_VALUE_ERANGE
Definition: util-error.h:91
detect-parse.h
Signature_
Signature container.
Definition: detect.h:527
SigMatch_
a single match condition for a signature
Definition: detect.h:319
suricata.h
PKT_MARK_MODIFIED
#define PKT_MARK_MODIFIED
Definition: decode.h:1090
SC_ERR_INVALID_NUMERIC_VALUE
@ SC_ERR_INVALID_NUMERIC_VALUE
Definition: util-error.h:90
DetectMarkData_::mark
uint32_t mark
Definition: detect-mark.h:45
DetectMarkData_::mask
uint32_t mask
Definition: detect-mark.h:46
flow-var.h
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:349
Packet_::tunnel_mutex
SCMutex tunnel_mutex
Definition: decode.h:590
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1201