suricata
detect-filesize.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-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 Victor Julien <victor@inliniac.net>
22  *
23  * Implements the filesize keyword
24  */
25 
26 #include "suricata-common.h"
27 #include "app-layer-protos.h"
28 #include "app-layer-htp.h"
29 #include "util-unittest.h"
30 #include "util-unittest-helper.h"
31 #include "util-misc.h"
32 
33 #include "detect.h"
34 #include "detect-parse.h"
35 #include "detect-engine.h"
36 #include "detect-engine-state.h"
37 #include "detect-engine-uint.h"
38 #include "detect-engine-build.h"
39 
40 #include "detect-filesize.h"
41 #include "util-debug.h"
42 #include "util-byte.h"
43 #include "flow-util.h"
44 #include "stream-tcp.h"
45 
46 
47 /*prototypes*/
48 static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f,
49  uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m);
50 static int DetectFilesizeSetup (DetectEngineCtx *, Signature *, const char *);
51 static void DetectFilesizeFree (DetectEngineCtx *, void *);
52 #ifdef UNITTESTS
53 static void DetectFilesizeRegisterTests (void);
54 #endif
55 static int g_file_match_list_id = 0;
56 
57 /**
58  * \brief Registration function for filesize: keyword
59  */
60 
62 {
63  sigmatch_table[DETECT_FILESIZE].name = "filesize";
64  sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred";
65  sigmatch_table[DETECT_FILESIZE].url = "/rules/file-keywords.html#filesize";
66  sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch;
67  sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup;
68  sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree;
69 #ifdef UNITTESTS
70  sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests;
71 #endif
72 
73  g_file_match_list_id = DetectBufferTypeRegister("files");
74 }
75 
76 /**
77  * \brief This function is used to match filesize rule option.
78  *
79  * \param t thread local vars
80  * \param det_ctx pattern matcher thread local data
81  * \param f *LOCKED* flow
82  * \param flags direction flags
83  * \param file file being inspected
84  * \param s signature being inspected
85  * \param m sigmatch that we will cast into DetectU64Data
86  *
87  * \retval 0 no match
88  * \retval 1 match
89  */
90 static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f,
91  uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m)
92 {
93  SCEnter();
94 
95  DetectU64Data *fsd = (DetectU64Data *)m;
96  int ret = 0;
97  uint64_t file_size = FileTrackedSize(file);
98 
99  SCLogDebug("file size %" PRIu64 ", check %" PRIu64, file_size, fsd->arg1);
100 
101  if (file->state == FILE_STATE_CLOSED) {
102  return DetectU64Match(file_size, fsd);
103  /* truncated, error: only see if what we have meets the GT condition */
104  } else if (file->state > FILE_STATE_CLOSED) {
105  if (fsd->mode == DETECT_UINT_GT || fsd->mode == DETECT_UINT_GTE) {
106  ret = DetectU64Match(file_size, fsd);
107  }
108  }
109  SCReturnInt(ret);
110 }
111 
112 /**
113  * \brief this function is used to parse filesize data into the current signature
114  *
115  * \param de_ctx pointer to the Detection Engine Context
116  * \param s pointer to the Current Signature
117  * \param str pointer to the user provided options
118  *
119  * \retval 0 on Success
120  * \retval -1 on Failure
121  */
122 static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
123 {
124  SCEnter();
125  DetectU64Data *fsd = NULL;
126  SigMatch *sm = NULL;
127 
128  fsd = DetectU64Parse(str);
129  if (fsd == NULL)
130  goto error;
131 
132  sm = SigMatchAlloc();
133  if (sm == NULL)
134  goto error;
135 
136  sm->type = DETECT_FILESIZE;
137  sm->ctx = (SigMatchCtx *)fsd;
138 
139  SigMatchAppendSMToList(s, sm, g_file_match_list_id);
140 
142  SCReturnInt(0);
143 
144 error:
145  if (fsd != NULL)
146  DetectFilesizeFree(de_ctx, fsd);
147  if (sm != NULL)
148  SCFree(sm);
149  SCReturnInt(-1);
150 }
151 
152 /**
153  * \brief this function will free memory associated with DetectU64Data
154  *
155  * \param ptr pointer to DetectU64Data
156  */
157 static void DetectFilesizeFree(DetectEngineCtx *de_ctx, void *ptr)
158 {
159  rs_detect_u64_free(ptr);
160 }
161 
162 #ifdef UNITTESTS
163 #include "stream.h"
164 #include "stream-tcp-private.h"
165 #include "stream-tcp-reassemble.h"
166 #include "detect-engine.h"
167 #include "detect-engine-mpm.h"
168 #include "app-layer-parser.h"
169 
170 /** \test Test the Filesize keyword setup */
171 static int DetectFilesizeParseTest01(void)
172 {
173  int ret = 0;
174  DetectU64Data *fsd = NULL;
175 
176  fsd = DetectU64Parse("10");
177  if (fsd != NULL) {
178  if (fsd->arg1 == 10 && fsd->mode == DETECT_UINT_EQ)
179  ret = 1;
180 
181  DetectFilesizeFree(NULL, fsd);
182  }
183  return ret;
184 }
185 
186 /** \test Test the Filesize keyword setup */
187 static int DetectFilesizeParseTest02(void)
188 {
189  int ret = 0;
190  DetectU64Data *fsd = NULL;
191 
192  fsd = DetectU64Parse(" < 10 ");
193  if (fsd != NULL) {
194  if (fsd->arg1 == 10 && fsd->mode == DETECT_UINT_LT)
195  ret = 1;
196 
197  DetectFilesizeFree(NULL, fsd);
198  }
199  return ret;
200 }
201 
202 /** \test Test the Filesize keyword setup */
203 static int DetectFilesizeParseTest03(void)
204 {
205  int ret = 0;
206  DetectU64Data *fsd = NULL;
207 
208  fsd = DetectU64Parse(" > 10 ");
209  if (fsd != NULL) {
210  if (fsd->arg1 == 10 && fsd->mode == DETECT_UINT_GT)
211  ret = 1;
212 
213  DetectFilesizeFree(NULL, fsd);
214  }
215  return ret;
216 }
217 
218 /** \test Test the Filesize keyword setup */
219 static int DetectFilesizeParseTest04(void)
220 {
221  int ret = 0;
222  DetectU64Data *fsd = NULL;
223 
224  fsd = DetectU64Parse(" 5 <> 10 ");
225  if (fsd != NULL) {
226  if (fsd->arg1 == 5 && fsd->arg2 == 10 && fsd->mode == DETECT_UINT_RA)
227  ret = 1;
228 
229  DetectFilesizeFree(NULL, fsd);
230  }
231  return ret;
232 }
233 
234 /** \test Test the Filesize keyword setup */
235 static int DetectFilesizeParseTest05(void)
236 {
237  int ret = 0;
238  DetectU64Data *fsd = NULL;
239 
240  fsd = DetectU64Parse("5<>10");
241  if (fsd != NULL) {
242  if (fsd->arg1 == 5 && fsd->arg2 == 10 && fsd->mode == DETECT_UINT_RA)
243  ret = 1;
244 
245  DetectFilesizeFree(NULL, fsd);
246  }
247  return ret;
248 }
249 
250 /**
251  * \brief this function is used to initialize the detection engine context and
252  * setup the signature with passed values.
253  *
254  */
255 
256 static int DetectFilesizeInitTest(
257  DetectEngineCtx **de_ctx, Signature **sig, DetectU64Data **fsd, const char *str)
258 {
259  char fullstr[1024];
260  int result = 0;
261 
262  *de_ctx = NULL;
263  *sig = NULL;
264 
265  if (snprintf(fullstr, 1024, "alert http any any -> any any (msg:\"Filesize "
266  "test\"; filesize:%s; sid:1;)", str) >= 1024) {
267  goto end;
268  }
269 
271  if (*de_ctx == NULL) {
272  goto end;
273  }
274 
275  (*de_ctx)->flags |= DE_QUIET;
276 
277  (*de_ctx)->sig_list = SigInit(*de_ctx, fullstr);
278  if ((*de_ctx)->sig_list == NULL) {
279  goto end;
280  }
281 
282  *sig = (*de_ctx)->sig_list;
283 
284  *fsd = DetectU64Parse(str);
285 
286  result = 1;
287 
288 end:
289  return result;
290 }
291 
292 /**
293  * \test DetectFilesizeSetpTest01 is a test for setting up an valid filesize values
294  * with valid "<>" operator and include spaces arround the given values.
295  * In the test the values are setup with initializing the detection engine
296  * context and setting up the signature itself.
297  */
298 
299 static int DetectFilesizeSetpTest01(void)
300 {
301 
302  DetectU64Data *fsd = NULL;
303  uint8_t res = 0;
304  Signature *sig = NULL;
305  DetectEngineCtx *de_ctx = NULL;
306 
307  res = DetectFilesizeInitTest(&de_ctx, &sig, &fsd, "1 <> 3 ");
308  if (res == 0) {
309  goto end;
310  }
311 
312  if(fsd == NULL)
313  goto cleanup;
314 
315  if (fsd != NULL) {
316  if (fsd->arg1 == 1 && fsd->arg2 == 3 && fsd->mode == DETECT_UINT_RA)
317  res = 1;
318  }
319 
320 cleanup:
321  if (fsd)
322  DetectFilesizeFree(NULL, fsd);
326 end:
327  return res;
328 }
329 
330 /**
331  * \brief this function registers unit tests for DetectFilesize
332  */
333 void DetectFilesizeRegisterTests(void)
334 {
335  UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01);
336  UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02);
337  UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03);
338  UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04);
339  UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05);
340  UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01);
341 }
342 #endif /* UNITTESTS */
util-byte.h
detect-engine-uint.h
SigTableElmt_::url
const char * url
Definition: detect.h:1248
detect-engine.h
SigTableElmt_::desc
const char * desc
Definition: detect.h:1247
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1235
flow-util.h
SigTableElmt_::name
const char * name
Definition: detect.h:1245
stream-tcp.h
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
DETECT_UINT_LT
#define DETECT_UINT_LT
Definition: detect-engine-uint.h:37
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:296
Flow_
Flow data structure.
Definition: flow.h:353
SigInit
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2116
SigTableElmt_::FileMatch
int(* FileMatch)(DetectEngineThreadCtx *, Flow *, uint8_t flags, File *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1221
File_::state
FileState state
Definition: util-file.h:78
DetectFilesizeRegister
void DetectFilesizeRegister(void)
Registration function for filesize: keyword.
Definition: detect-filesize.c:61
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:785
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2445
DETECT_UINT_EQ
#define DETECT_UINT_EQ
Definition: detect-engine-uint.h:35
DE_QUIET
#define DE_QUIET
Definition: detect.h:288
stream-tcp-reassemble.h
m
SCMutex m
Definition: flow-hash.h:6
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:45
DETECT_UINT_GT
#define DETECT_UINT_GT
Definition: detect-engine-uint.h:32
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1230
util-unittest.h
util-unittest-helper.h
DETECT_FILESIZE
@ DETECT_FILESIZE
Definition: detect-engine-register.h:213
app-layer-htp.h
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1034
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
SCEnter
#define SCEnter(...)
Definition: util-debug.h:298
detect-engine-mpm.h
detect.h
FileTrackedSize
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition: util-file.c:310
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:317
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2021
stream.h
detect-engine-build.h
DETECT_UINT_GTE
#define DETECT_UINT_GTE
Definition: detect-engine-uint.h:33
stream-tcp-private.h
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:235
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:309
FILE_STATE_CLOSED
@ FILE_STATE_CLOSED
Definition: util-file.h:67
File_
Definition: util-file.h:75
DetectBufferTypeRegister
int DetectBufferTypeRegister(const char *name)
Definition: detect-engine.c:1032
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
SigMatch_::type
uint16_t type
Definition: detect.h:315
Signature_::file_flags
uint8_t file_flags
Definition: detect.h:555
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
DetectU64Parse
DetectUintData_u64 * DetectU64Parse(const char *u64str)
Definition: detect-engine-uint.c:147
str
#define str(s)
Definition: suricata-common.h:272
DetectU64Data
DetectUintData_u64 DetectU64Data
Definition: detect-engine-uint.h:40
SCFree
#define SCFree(p)
Definition: util-mem.h:61
detect-parse.h
Signature_
Signature container.
Definition: detect.h:540
SigMatch_
a single match condition for a signature
Definition: detect.h:314
DetectU64Match
int DetectU64Match(const uint64_t parg, const DetectUintData_u64 *du64)
Definition: detect-engine-uint.c:142
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2406
detect-filesize.h
app-layer-protos.h
FILE_SIG_NEED_FILE
#define FILE_SIG_NEED_FILE
Definition: detect.h:278
util-misc.h
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:302
SigMatchAppendSMToList
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:349
DETECT_UINT_RA
#define DETECT_UINT_RA
Definition: detect-engine-uint.h:34
FILE_SIG_NEED_SIZE
#define FILE_SIG_NEED_SIZE
Definition: detect.h:285
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1237