Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-filesize.c
Line
Count
Source
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
61
void DetectFilesizeRegister(void)
62
73
{
63
73
    sigmatch_table[DETECT_FILESIZE].name = "filesize";
64
73
    sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred";
65
73
    sigmatch_table[DETECT_FILESIZE].url = "/rules/file-keywords.html#filesize";
66
73
    sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch;
67
73
    sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup;
68
73
    sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree;
69
#ifdef UNITTESTS
70
    sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests;
71
#endif
72
73
73
    g_file_match_list_id = DetectBufferTypeRegister("files");
74
73
}
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
125
{
93
125
    SCEnter();
94
95
125
    DetectU64Data *fsd = (DetectU64Data *)m;
96
125
    int ret = 0;
97
125
    uint64_t file_size = FileTrackedSize(file);
98
99
125
    SCLogDebug("file size %" PRIu64 ", check %" PRIu64, file_size, fsd->arg1);
100
101
125
    if (file->state == FILE_STATE_CLOSED) {
102
125
        return DetectU64Match(file_size, fsd);
103
        /* truncated, error: only see if what we have meets the GT condition */
104
125
    } else if (file->state > FILE_STATE_CLOSED) {
105
0
        if (fsd->mode == DETECT_UINT_GT || fsd->mode == DETECT_UINT_GTE) {
106
0
            ret = DetectU64Match(file_size, fsd);
107
0
        }
108
0
    }
109
125
    SCReturnInt(ret);
110
125
}
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
1.04k
{
124
1.04k
    SCEnter();
125
1.04k
    DetectU64Data *fsd = NULL;
126
1.04k
    SigMatch *sm = NULL;
127
128
1.04k
    fsd = DetectU64Parse(str);
129
1.04k
    if (fsd == NULL)
130
532
        SCReturnInt(-1);
131
132
517
    sm = SigMatchAlloc();
133
517
    if (sm == NULL)
134
0
        goto error;
135
136
517
    sm->type = DETECT_FILESIZE;
137
517
    sm->ctx = (SigMatchCtx *)fsd;
138
139
517
    SigMatchAppendSMToList(s, sm, g_file_match_list_id);
140
141
517
    s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE);
142
517
    SCReturnInt(0);
143
144
0
error:
145
0
    if (fsd != NULL)
146
0
        DetectFilesizeFree(de_ctx, fsd);
147
0
    if (sm != NULL)
148
0
        SCFree(sm);
149
0
    SCReturnInt(-1);
150
517
}
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
839
{
159
839
    rs_detect_u64_free(ptr);
160
839
}
161
162
#ifdef UNITTESTS
163
#include "stream.h"
164
#include "stream-tcp-private.h"
165
#include "stream-tcp-reassemble.h"
166
#include "detect-engine-mpm.h"
167
#include "app-layer-parser.h"
168
169
/** \test   Test the Filesize keyword setup */
170
static int DetectFilesizeParseTest01(void)
171
{
172
    DetectU64Data *fsd = DetectU64Parse("10");
173
    FAIL_IF_NULL(fsd);
174
    FAIL_IF_NOT(fsd->arg1 == 10);
175
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_EQ);
176
    DetectFilesizeFree(NULL, fsd);
177
178
    PASS;
179
}
180
181
/** \test   Test the Filesize keyword setup */
182
static int DetectFilesizeParseTest02(void)
183
{
184
    DetectU64Data *fsd = DetectU64Parse(" < 10  ");
185
    FAIL_IF_NULL(fsd);
186
    FAIL_IF_NOT(fsd->arg1 == 10);
187
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_LT);
188
    DetectFilesizeFree(NULL, fsd);
189
190
    PASS;
191
}
192
193
/** \test   Test the Filesize keyword setup */
194
static int DetectFilesizeParseTest03(void)
195
{
196
    DetectU64Data *fsd = DetectU64Parse(" > 10 ");
197
    FAIL_IF_NULL(fsd);
198
    FAIL_IF_NOT(fsd->arg1 == 10);
199
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_GT);
200
    DetectFilesizeFree(NULL, fsd);
201
202
    PASS;
203
}
204
205
/** \test   Test the Filesize keyword setup */
206
static int DetectFilesizeParseTest04(void)
207
{
208
    DetectU64Data *fsd = DetectU64Parse(" 5 <> 10 ");
209
    FAIL_IF_NULL(fsd);
210
    FAIL_IF_NOT(fsd->arg1 == 5);
211
    FAIL_IF_NOT(fsd->arg2 == 10);
212
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA);
213
    DetectFilesizeFree(NULL, fsd);
214
215
    PASS;
216
}
217
218
/** \test   Test the Filesize keyword setup */
219
static int DetectFilesizeParseTest05(void)
220
{
221
    DetectU64Data *fsd = DetectU64Parse("5<>10");
222
    FAIL_IF_NULL(fsd);
223
    FAIL_IF_NOT(fsd->arg1 == 5);
224
    FAIL_IF_NOT(fsd->arg2 == 10);
225
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA);
226
    DetectFilesizeFree(NULL, fsd);
227
228
    PASS;
229
}
230
231
/**
232
 * \brief this function is used to initialize the detection engine context and
233
 *        setup the signature with passed values.
234
 *
235
 */
236
237
static int DetectFilesizeInitTest(
238
        DetectEngineCtx **de_ctx, Signature **sig, DetectU64Data **fsd, const char *str)
239
{
240
    char fullstr[1024];
241
    *de_ctx = NULL;
242
243
    *de_ctx = DetectEngineCtxInit();
244
    (*de_ctx)->flags |= DE_QUIET;
245
    FAIL_IF_NULL((*de_ctx));
246
247
    *sig = NULL;
248
249
    FAIL_IF(snprintf(fullstr, 1024,
250
                    "alert http any any -> any any (msg:\"Filesize "
251
                    "test\"; filesize:%s; sid:1;)",
252
                    str) >= 1024);
253
254
    Signature *s = DetectEngineAppendSig(*de_ctx, fullstr);
255
    FAIL_IF_NULL(s);
256
257
    *sig = (*de_ctx)->sig_list;
258
259
    *fsd = DetectU64Parse(str);
260
261
    PASS;
262
}
263
264
/**
265
 * \test DetectFilesizeSetpTest01 is a test for setting up an valid filesize values
266
 *       with valid "<>" operator and include spaces arround the given values.
267
 *       In the test the values are setup with initializing the detection engine
268
 *       context and setting up the signature itself.
269
 */
270
271
static int DetectFilesizeSetpTest01(void)
272
{
273
274
    DetectU64Data *fsd = NULL;
275
    uint8_t res = 0;
276
    Signature *sig = NULL;
277
    DetectEngineCtx *de_ctx = NULL;
278
279
    res = DetectFilesizeInitTest(&de_ctx, &sig, &fsd, "1 <> 3 ");
280
    FAIL_IF(res == 0);
281
282
    FAIL_IF_NULL(fsd);
283
    FAIL_IF_NOT(fsd->arg1 == 1);
284
    FAIL_IF_NOT(fsd->arg2 == 3);
285
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA);
286
287
    DetectFilesizeFree(NULL, fsd);
288
    DetectEngineCtxFree(de_ctx);
289
290
    PASS;
291
}
292
293
/**
294
 * \brief this function registers unit tests for DetectFilesize
295
 */
296
void DetectFilesizeRegisterTests(void)
297
{
298
    UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01);
299
    UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02);
300
    UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03);
301
    UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04);
302
    UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05);
303
    UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01);
304
}
305
#endif /* UNITTESTS */