suricata
detect-bsize.c
Go to the documentation of this file.
1 /* Copyright (C) 2017 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 Victor Julien <victor@inliniac.net>
22  *
23  * Implements the bsize generic buffer length keyword
24  */
25 
26 #include "suricata-common.h"
27 #include "util-unittest.h"
28 #include "util-unittest-helper.h"
29 
30 #include "detect.h"
31 #include "detect-parse.h"
32 #include "detect-engine.h"
33 #include "detect-content.h"
34 
35 #include "detect-bsize.h"
36 
37 #include "util-misc.h"
38 
39 /*prototypes*/
40 static int DetectBsizeSetup (DetectEngineCtx *, Signature *, const char *);
41 static void DetectBsizeFree (void *);
42 #ifdef UNITTESTS
43 static void DetectBsizeRegisterTests (void);
44 #endif
45 
46 /**
47  * \brief Registration function for bsize: keyword
48  */
49 
51 {
52  sigmatch_table[DETECT_BSIZE].name = "bsize";
53  sigmatch_table[DETECT_BSIZE].desc = "match on the length of a buffer";
54  sigmatch_table[DETECT_BSIZE].url = DOC_URL DOC_VERSION "/rules/payload-keywords.html#bsize";
56  sigmatch_table[DETECT_BSIZE].Setup = DetectBsizeSetup;
57  sigmatch_table[DETECT_BSIZE].Free = DetectBsizeFree;
58 #ifdef UNITTESTS
59  sigmatch_table[DETECT_BSIZE].RegisterTests = DetectBsizeRegisterTests;
60 #endif
61 }
62 
63 #define DETECT_BSIZE_LT 0
64 #define DETECT_BSIZE_GT 1
65 #define DETECT_BSIZE_RA 2
66 #define DETECT_BSIZE_EQ 3
67 
68 typedef struct DetectBsizeData {
69  uint8_t mode;
70  uint64_t lo;
71  uint64_t hi;
73 
74 /** \brief bsize match function
75  *
76  * \param ctx match ctx
77  * \param buffer_size size of the buffer
78  * \param eof is the buffer closed?
79  *
80  * \retval r 1 match, 0 no match, -1 can't match
81  *
82  * \todo check logic around < vs <=
83  */
84 int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof)
85 {
86  const DetectBsizeData *bsz = (const DetectBsizeData *)ctx;
87  switch (bsz->mode) {
88  case DETECT_BSIZE_LT:
89  if (buffer_size < bsz->lo) {
90  return 1;
91  }
92  return -1;
93 
94  case DETECT_BSIZE_GT:
95  if (buffer_size > bsz->lo) {
96  return 1;
97  } else if (eof) {
98  return -1;
99  }
100  return 0;
101 
102  case DETECT_BSIZE_EQ:
103  if (buffer_size == bsz->lo) {
104  return 1;
105  } else if (buffer_size > bsz->lo) {
106  return -1;
107  } else if (eof) {
108  return -1;
109  } else {
110  return 0;
111  }
112 
113  case DETECT_BSIZE_RA:
114  if (buffer_size > bsz->lo && buffer_size < bsz->hi) {
115  return 1;
116  } else if (buffer_size <= bsz->lo && eof) {
117  return -1;
118  } else if (buffer_size <= bsz->lo) {
119  return 0;
120  } else if (buffer_size >= bsz->hi) {
121  return -1;
122  }
123  }
124  return 0;
125 }
126 
127 #define ERR(...) do { \
128  char _buf[2048]; \
129  snprintf(_buf, sizeof(_buf), __VA_ARGS__); \
130  SCLogError(SC_ERR_INVALID_RULE_ARGUMENT, "bsize: bad input, %s", _buf); \
131 } while(0)
132 
133 /**
134  * \brief This function is used to parse bsize options passed via bsize: keyword
135  *
136  * \param bsizestr Pointer to the user provided bsize options
137  *
138  * \retval bsized pointer to DetectBsizeData on success
139  * \retval NULL on failure
140  */
141 
142 static DetectBsizeData *DetectBsizeParse (const char *str)
143 {
144  uint32_t lo = 0;
145  uint32_t hi = 0;
146 
147  if (str == NULL)
148  return NULL;
149 
150  size_t len = strlen(str);
151  if (len == 0)
152  return NULL;
153 
154  /* allow for leading spaces */
155  while (isspace(*str))
156  (str++);
157  len = strlen(str);
158  if (len == 0)
159  return NULL;
160 
161  int mode = DETECT_BSIZE_EQ;
162  switch (*str) {
163  case '>':
164  mode = DETECT_BSIZE_GT;
165  str++;
166  break;
167  case '<':
168  mode = DETECT_BSIZE_LT;
169  str++;
170  break;
171  }
172 
173  /* allow for spaces between mode and value */
174  while (isspace(*str))
175  (str++);
176 
177  char str1[11], *p = str1;
178  memset(str1, 0, sizeof(str1));
179  while (*str && isdigit(*str)) {
180  if (p - str1 >= (int)sizeof(str1))
181  return NULL;
182  *p++ = *str++;
183  }
184  /* skip trailing space */
185  while (*str && isspace(*str)) {
186  str++;
187  }
188  if (*str == '\0') {
189  // done
190  SCLogDebug("str1 '%s'", str1);
191 
192  uint64_t val = 0;
193  if (ParseSizeStringU64(str1, &val) < 0) {
194  return NULL;
195  }
196  lo = val;
197 
198  } else if (*str == '<') {
199  str++;
200  if (*str != '>') {
201  ERR("only '<>' allowed");
202  return NULL;
203  }
204  str++;
205 
206  // range
207  if (mode != DETECT_BSIZE_EQ) {
208  ERR("mode already set");
209  return NULL;
210  }
211  mode = DETECT_BSIZE_RA;
212 
213  uint64_t val = 0;
214  if (ParseSizeStringU64(str1, &val) < 0) {
215  return NULL;
216  }
217  lo = val;
218 
219  /* allow for spaces between mode and value */
220  while (*str && isspace(*str))
221  (str++);
222 
223  char str2[11];
224  p = str2;
225  memset(str2, 0, sizeof(str2));
226  while (*str && isdigit(*str)) {
227  if (p - str2 >= (int)sizeof(str2))
228  return NULL;
229  *p++ = *str++;
230  }
231  /* skip trailing space */
232  while (*str && isspace(*str)) {
233  str++;
234  }
235  if (*str == '\0') {
236  // done
237  SCLogDebug("str2 '%s'", str2);
238 
239  if (ParseSizeStringU64(str2, &val) < 0) {
240  ERR("'%s' is not a valid u32", str2);
241  return NULL;
242  }
243  hi = val;
244  if (lo >= hi) {
245  ERR("%u > %u", lo, hi);
246  return NULL;
247  }
248 
249  } else {
250  ERR("trailing data");
251  return NULL;
252  }
253 
254  } else {
255  ERR("'%s'", str);
256  return NULL;
257  }
258 
259  DetectBsizeData *bsz = SCCalloc(1, sizeof(*bsz));
260  if (bsz == NULL) {
261  return NULL;
262  }
263  bsz->mode = (uint8_t)mode;
264  bsz->lo = lo;
265  bsz->hi = hi;
266  return bsz;
267 }
268 
269 /**
270  * \brief this function is used to parse bsize data into the current signature
271  *
272  * \param de_ctx pointer to the Detection Engine Context
273  * \param s pointer to the Current Signature
274  * \param bsizestr pointer to the user provided bsize options
275  *
276  * \retval 0 on Success
277  * \retval -1 on Failure
278  */
279 static int DetectBsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *sizestr)
280 {
281  SCEnter();
282  SigMatch *sm = NULL;
283 
284  if (DetectBufferGetActiveList(de_ctx, s) == -1)
285  SCReturnInt(-1);
286 
287  int list = s->init_data->list;
288  if (list == DETECT_SM_LIST_NOTSET)
289  SCReturnInt(-1);
290 
291  DetectBsizeData *bsz = DetectBsizeParse(sizestr);
292  if (bsz == NULL)
293  goto error;
294  sm = SigMatchAlloc();
295  if (sm == NULL)
296  goto error;
297  sm->type = DETECT_BSIZE;
298  sm->ctx = (void *)bsz;
299 
300  SigMatchAppendSMToList(s, sm, list);
301 
302  SCReturnInt(0);
303 
304 error:
305  DetectBsizeFree(bsz);
306  SCReturnInt(-1);
307 }
308 
309 /**
310  * \brief this function will free memory associated with DetectBsizeData
311  *
312  * \param ptr pointer to DetectBsizeData
313  */
314 void DetectBsizeFree(void *ptr)
315 {
316  if (ptr == NULL)
317  return;
318 
319  DetectBsizeData *bsz = (DetectBsizeData *)ptr;
320  SCFree(bsz);
321 }
322 
323 #ifdef UNITTESTS
324 #include "tests/detect-bsize.c"
325 #endif
#define DETECT_BSIZE_LT
Definition: detect-bsize.c:63
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1448
SignatureInitData * init_data
Definition: detect.h:591
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1186
#define SCLogDebug(...)
Definition: util-debug.h:335
#define ERR(...)
Definition: detect-bsize.c:127
const char * name
Definition: detect.h:1200
Signature container.
Definition: detect.h:522
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:313
main detection engine ctx
Definition: detect.h:761
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:203
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
#define DETECT_BSIZE_EQ
Definition: detect-bsize.c:66
#define str(s)
#define SCCalloc(nm, a)
Definition: util-mem.h:253
void(* Free)(void *)
Definition: detect.h:1191
#define DETECT_BSIZE_RA
Definition: detect-bsize.c:65
#define SCEnter(...)
Definition: util-debug.h:337
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:115
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1170
uint8_t type
Definition: detect.h:319
#define SCReturnInt(x)
Definition: util-debug.h:341
const char * desc
Definition: detect.h:1202
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:346
SigMatchCtx * ctx
Definition: detect.h:321
#define SCFree(a)
Definition: util-mem.h:322
void DetectBsizeRegister(void)
Registration function for bsize: keyword.
Definition: detect-bsize.c:50
#define DETECT_BSIZE_GT
Definition: detect-bsize.c:64
const char * url
Definition: detect.h:1203
int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof)
bsize match function
Definition: detect-bsize.c:84
#define DOC_URL
Definition: suricata.h:86
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
uint8_t len
#define DOC_VERSION
Definition: suricata.h:91
struct DetectBsizeData DetectBsizeData
void(* RegisterTests)(void)
Definition: detect.h:1192
a single match condition for a signature
Definition: detect.h:318