Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/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
12
{
63
12
    sigmatch_table[DETECT_FILESIZE].name = "filesize";
64
12
    sigmatch_table[DETECT_FILESIZE].desc = "match on the size of the file as it is being transferred";
65
12
    sigmatch_table[DETECT_FILESIZE].url = "/rules/file-keywords.html#filesize";
66
12
    sigmatch_table[DETECT_FILESIZE].FileMatch = DetectFilesizeMatch;
67
12
    sigmatch_table[DETECT_FILESIZE].Setup = DetectFilesizeSetup;
68
12
    sigmatch_table[DETECT_FILESIZE].Free = DetectFilesizeFree;
69
12
    sigmatch_table[DETECT_FILESIZE].flags = SIGMATCH_SUPPORT_DIR;
70
#ifdef UNITTESTS
71
    sigmatch_table[DETECT_FILESIZE].RegisterTests = DetectFilesizeRegisterTests;
72
#endif
73
74
12
    g_file_match_list_id = DetectBufferTypeRegister("files");
75
12
}
76
77
/**
78
 * \brief   This function is used to match filesize rule option.
79
 *
80
 * \param t thread local vars
81
 * \param det_ctx pattern matcher thread local data
82
 * \param f *LOCKED* flow
83
 * \param flags direction flags
84
 * \param file file being inspected
85
 * \param s signature being inspected
86
 * \param m sigmatch that we will cast into DetectU64Data
87
 *
88
 * \retval 0 no match
89
 * \retval 1 match
90
 */
91
static int DetectFilesizeMatch (DetectEngineThreadCtx *det_ctx, Flow *f,
92
        uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m)
93
127
{
94
127
    SCEnter();
95
96
127
    DetectU64Data *fsd = (DetectU64Data *)m;
97
127
    int ret = 0;
98
127
    uint64_t file_size = FileTrackedSize(file);
99
100
127
    SCLogDebug("file size %" PRIu64 ", check %" PRIu64, file_size, fsd->arg1);
101
102
127
    if (file->state == FILE_STATE_CLOSED) {
103
116
        return DetectU64Match(file_size, fsd);
104
        /* truncated, error: only see if what we have meets the GT condition */
105
116
    } else if (file->state > FILE_STATE_CLOSED) {
106
11
        if (fsd->mode == DETECT_UINT_GT || fsd->mode == DETECT_UINT_GTE) {
107
0
            ret = DetectU64Match(file_size, fsd);
108
0
        }
109
11
    }
110
127
    SCReturnInt(ret);
111
127
}
112
113
/**
114
 * \brief this function is used to parse filesize data into the current signature
115
 *
116
 * \param de_ctx pointer to the Detection Engine Context
117
 * \param s pointer to the Current Signature
118
 * \param str pointer to the user provided options
119
 *
120
 * \retval 0 on Success
121
 * \retval -1 on Failure
122
 */
123
static int DetectFilesizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
124
1.77k
{
125
1.77k
    SCEnter();
126
1.77k
    DetectU64Data *fsd = DetectU64Parse(str);
127
1.77k
    if (fsd == NULL)
128
1.37k
        SCReturnInt(-1);
129
130
397
    if (SCSigMatchAppendSMToList(
131
397
                de_ctx, s, DETECT_FILESIZE, (SigMatchCtx *)fsd, g_file_match_list_id) == NULL) {
132
0
        DetectFilesizeFree(de_ctx, fsd);
133
0
        SCReturnInt(-1);
134
0
    }
135
136
397
    s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_SIZE);
137
397
    SCReturnInt(0);
138
397
}
139
140
/**
141
 * \brief this function will free memory associated with DetectU64Data
142
 *
143
 * \param ptr pointer to DetectU64Data
144
 */
145
static void DetectFilesizeFree(DetectEngineCtx *de_ctx, void *ptr)
146
397
{
147
397
    SCDetectU64Free(ptr);
148
397
}
149
150
#ifdef UNITTESTS
151
#include "stream.h"
152
#include "stream-tcp-private.h"
153
#include "stream-tcp-reassemble.h"
154
#include "detect-engine-mpm.h"
155
#include "app-layer-parser.h"
156
157
/** \test   Test the Filesize keyword setup */
158
static int DetectFilesizeParseTest01(void)
159
{
160
    DetectU64Data *fsd = DetectU64Parse("10");
161
    FAIL_IF_NULL(fsd);
162
    FAIL_IF_NOT(fsd->arg1 == 10);
163
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_EQ);
164
    DetectFilesizeFree(NULL, fsd);
165
166
    PASS;
167
}
168
169
/** \test   Test the Filesize keyword setup */
170
static int DetectFilesizeParseTest02(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_LT);
176
    DetectFilesizeFree(NULL, fsd);
177
178
    PASS;
179
}
180
181
/** \test   Test the Filesize keyword setup */
182
static int DetectFilesizeParseTest03(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_GT);
188
    DetectFilesizeFree(NULL, fsd);
189
190
    PASS;
191
}
192
193
/** \test   Test the Filesize keyword setup */
194
static int DetectFilesizeParseTest04(void)
195
{
196
    DetectU64Data *fsd = DetectU64Parse(" 5 <> 10 ");
197
    FAIL_IF_NULL(fsd);
198
    FAIL_IF_NOT(fsd->arg1 == 5);
199
    FAIL_IF_NOT(fsd->arg2 == 10);
200
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA);
201
    DetectFilesizeFree(NULL, fsd);
202
203
    PASS;
204
}
205
206
/** \test   Test the Filesize keyword setup */
207
static int DetectFilesizeParseTest05(void)
208
{
209
    DetectU64Data *fsd = DetectU64Parse("5<>10");
210
    FAIL_IF_NULL(fsd);
211
    FAIL_IF_NOT(fsd->arg1 == 5);
212
    FAIL_IF_NOT(fsd->arg2 == 10);
213
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA);
214
    DetectFilesizeFree(NULL, fsd);
215
216
    PASS;
217
}
218
219
/**
220
 * \brief this function is used to initialize the detection engine context and
221
 *        setup the signature with passed values.
222
 *
223
 */
224
225
static int DetectFilesizeInitTest(
226
        DetectEngineCtx **de_ctx, Signature **sig, DetectU64Data **fsd, const char *str)
227
{
228
    char fullstr[1024];
229
    *de_ctx = NULL;
230
231
    *de_ctx = DetectEngineCtxInit();
232
    (*de_ctx)->flags |= DE_QUIET;
233
    FAIL_IF_NULL((*de_ctx));
234
235
    *sig = NULL;
236
237
    FAIL_IF(snprintf(fullstr, 1024,
238
                    "alert http any any -> any any (msg:\"Filesize "
239
                    "test\"; filesize:%s; sid:1;)",
240
                    str) >= 1024);
241
242
    Signature *s = DetectEngineAppendSig(*de_ctx, fullstr);
243
    FAIL_IF_NULL(s);
244
245
    *sig = (*de_ctx)->sig_list;
246
247
    *fsd = DetectU64Parse(str);
248
249
    PASS;
250
}
251
252
/**
253
 * \test DetectFilesizeSetpTest01 is a test for setting up an valid filesize values
254
 *       with valid "<>" operator and include spaces arround the given values.
255
 *       In the test the values are setup with initializing the detection engine
256
 *       context and setting up the signature itself.
257
 */
258
259
static int DetectFilesizeSetpTest01(void)
260
{
261
262
    DetectU64Data *fsd = NULL;
263
    uint8_t res = 0;
264
    Signature *sig = NULL;
265
    DetectEngineCtx *de_ctx = NULL;
266
267
    res = DetectFilesizeInitTest(&de_ctx, &sig, &fsd, "1 <> 3 ");
268
    FAIL_IF(res == 0);
269
270
    FAIL_IF_NULL(fsd);
271
    FAIL_IF_NOT(fsd->arg1 == 1);
272
    FAIL_IF_NOT(fsd->arg2 == 3);
273
    FAIL_IF_NOT(fsd->mode == DETECT_UINT_RA);
274
275
    DetectFilesizeFree(NULL, fsd);
276
    DetectEngineCtxFree(de_ctx);
277
278
    PASS;
279
}
280
281
/**
282
 * \brief this function registers unit tests for DetectFilesize
283
 */
284
void DetectFilesizeRegisterTests(void)
285
{
286
    UtRegisterTest("DetectFilesizeParseTest01", DetectFilesizeParseTest01);
287
    UtRegisterTest("DetectFilesizeParseTest02", DetectFilesizeParseTest02);
288
    UtRegisterTest("DetectFilesizeParseTest03", DetectFilesizeParseTest03);
289
    UtRegisterTest("DetectFilesizeParseTest04", DetectFilesizeParseTest04);
290
    UtRegisterTest("DetectFilesizeParseTest05", DetectFilesizeParseTest05);
291
    UtRegisterTest("DetectFilesizeSetpTest01", DetectFilesizeSetpTest01);
292
}
293
#endif /* UNITTESTS */