Coverage Report

Created: 2026-03-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-bsize.c
Line
Count
Source
1
/* Copyright (C) 2017-2022 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
#include "detect-engine-uint.h"
35
36
#include "detect-bsize.h"
37
38
#include "util-misc.h"
39
40
/*prototypes*/
41
static int DetectBsizeSetup (DetectEngineCtx *, Signature *, const char *);
42
static void DetectBsizeFree (DetectEngineCtx *, void *);
43
static int SigParseGetMaxBsize(DetectU64Data *bsz);
44
#ifdef UNITTESTS
45
static void DetectBsizeRegisterTests (void);
46
#endif
47
48
bool DetectBsizeValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b)
49
411k
{
50
411k
    int bsize = -1;
51
411k
    DetectU64Data *bsz;
52
902k
    for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
53
515k
        if (sm->type == DETECT_BSIZE) {
54
24.0k
            bsz = (DetectU64Data *)sm->ctx;
55
24.0k
            bsize = SigParseGetMaxBsize(bsz);
56
24.0k
            break;
57
24.0k
        }
58
515k
    }
59
60
411k
    if (bsize == -1) {
61
387k
        return true;
62
387k
    }
63
64
24.0k
    uint64_t needed;
65
24.0k
    if (bsize >= 0) {
66
21.9k
        int len, offset;
67
21.9k
        SigParseRequiredContentSize(s, bsize, b->head, &len, &offset);
68
21.9k
        SCLogDebug("bsize: %d; len: %d; offset: %d [%s]", bsize, len, offset, s->sig_str);
69
21.9k
        needed = len;
70
21.9k
        if (len > bsize) {
71
9.53k
            goto value_error;
72
9.53k
        }
73
12.3k
        if ((len + offset) > bsize) {
74
3.04k
            needed += offset;
75
3.04k
            goto value_error;
76
3.04k
        }
77
12.3k
    }
78
79
11.5k
    return true;
80
12.5k
value_error:
81
12.5k
    if (bsz->mode == DETECT_UINT_RA) {
82
1.77k
        SCLogError("signature can't match as required content length %" PRIu64
83
1.77k
                   " exceeds bsize range: %" PRIu64 "-%" PRIu64,
84
1.77k
                needed, bsz->arg1, bsz->arg2);
85
10.8k
    } else {
86
10.8k
        SCLogError("signature can't match as required content length %" PRIu64
87
10.8k
                   " exceeds bsize value: "
88
10.8k
                   "%" PRIu64,
89
10.8k
                needed, bsz->arg1);
90
10.8k
    }
91
12.5k
    return false;
92
24.0k
}
93
94
/**
95
 * \brief Registration function for bsize: keyword
96
 */
97
98
void DetectBsizeRegister(void)
99
73
{
100
73
    sigmatch_table[DETECT_BSIZE].name = "bsize";
101
73
    sigmatch_table[DETECT_BSIZE].desc = "match on the length of a buffer";
102
73
    sigmatch_table[DETECT_BSIZE].url = "/rules/payload-keywords.html#bsize";
103
73
    sigmatch_table[DETECT_BSIZE].Match = NULL;
104
73
    sigmatch_table[DETECT_BSIZE].Setup = DetectBsizeSetup;
105
73
    sigmatch_table[DETECT_BSIZE].Free = DetectBsizeFree;
106
#ifdef UNITTESTS
107
    sigmatch_table[DETECT_BSIZE].RegisterTests = DetectBsizeRegisterTests;
108
#endif
109
73
}
110
111
/** \brief bsize match function
112
 *
113
 *  \param ctx match ctx
114
 *  \param buffer_size size of the buffer
115
 *  \param eof is the buffer closed?
116
 *
117
 *  \retval r 1 match, 0 no match, -1 can't match
118
 */
119
int DetectBsizeMatch(const SigMatchCtx *ctx, const uint64_t buffer_size, bool eof)
120
2.61k
{
121
2.61k
    const DetectU64Data *bsz = (const DetectU64Data *)ctx;
122
2.61k
    if (DetectU64Match(buffer_size, bsz)) {
123
1.39k
        return 1;
124
1.39k
    }
125
1.22k
    switch (bsz->mode) {
126
0
        case DETECT_UINT_LTE:
127
0
            return -1;
128
8
        case DETECT_UINT_LT:
129
8
            return -1;
130
131
0
        case DETECT_UINT_GTE:
132
            // fallthrough
133
51
        case DETECT_UINT_GT:
134
51
            if (eof) {
135
48
                return -1;
136
48
            }
137
3
            return 0;
138
139
1.00k
        case DETECT_UINT_EQ:
140
1.00k
            if (buffer_size > bsz->arg1) {
141
40
                return -1;
142
967
            } else if (eof) {
143
967
                return -1;
144
967
            } else {
145
0
                return 0;
146
0
            }
147
148
160
        case DETECT_UINT_RA:
149
160
            if (buffer_size <= bsz->arg1 && eof) {
150
152
                return -1;
151
152
            } else if (buffer_size <= bsz->arg1) {
152
0
                return 0;
153
8
            } else if (buffer_size >= bsz->arg2) {
154
8
                return -1;
155
8
            }
156
1.22k
    }
157
0
    return 0;
158
1.22k
}
159
160
static int SigParseGetMaxBsize(DetectU64Data *bsz)
161
43.8k
{
162
43.8k
    switch (bsz->mode) {
163
8.15k
        case DETECT_UINT_LT:
164
29.8k
        case DETECT_UINT_EQ:
165
29.8k
            return bsz->arg1;
166
9.76k
        case DETECT_UINT_RA:
167
9.76k
            return bsz->arg2;
168
3.90k
        case DETECT_UINT_GT:
169
4.15k
        default:
170
4.15k
            SCReturnInt(-2);
171
43.8k
    }
172
43.8k
    SCReturnInt(-1);
173
43.8k
}
174
175
/**
176
 * \brief this function is used to parse bsize data into the current signature
177
 *
178
 * \param de_ctx pointer to the Detection Engine Context
179
 * \param s pointer to the Current Signature
180
 * \param sizestr pointer to the user provided bsize options
181
 *
182
 * \retval 0 on Success
183
 * \retval -1 on Failure
184
 */
185
static int DetectBsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *sizestr)
186
62.5k
{
187
62.5k
    SCEnter();
188
62.5k
    SigMatch *sm = NULL;
189
190
62.5k
    if (DetectBufferGetActiveList(de_ctx, s) == -1)
191
4
        SCReturnInt(-1);
192
193
62.5k
    int list = s->init_data->list;
194
62.5k
    if (list == DETECT_SM_LIST_NOTSET)
195
375
        SCReturnInt(-1);
196
197
62.1k
    DetectU64Data *bsz = DetectU64Parse(sizestr);
198
62.1k
    if (bsz == NULL)
199
7.28k
        SCReturnInt(-1);
200
201
54.8k
    sm = SigMatchAlloc();
202
54.8k
    if (sm == NULL)
203
0
        goto error;
204
54.8k
    sm->type = DETECT_BSIZE;
205
54.8k
    sm->ctx = (void *)bsz;
206
207
54.8k
    SigMatchAppendSMToList(s, sm, list);
208
209
54.8k
    SCReturnInt(0);
210
211
0
error:
212
0
    DetectBsizeFree(de_ctx, bsz);
213
0
    SCReturnInt(-1);
214
54.8k
}
215
216
/**
217
 * \brief this function will free memory associated with DetectU64Data
218
 *
219
 * \param ptr pointer to DetectU64Data
220
 */
221
void DetectBsizeFree(DetectEngineCtx *de_ctx, void *ptr)
222
54.8k
{
223
54.8k
    if (ptr == NULL)
224
0
        return;
225
226
54.8k
    DetectU64Data *bsz = (DetectU64Data *)ptr;
227
54.8k
    rs_detect_u64_free(bsz);
228
54.8k
}
229
230
#ifdef UNITTESTS
231
#include "tests/detect-bsize.c"
232
#endif