Coverage Report

Created: 2026-05-16 07:38

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
447k
{
50
447k
    int bsize = -1;
51
447k
    DetectU64Data *bsz;
52
973k
    for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
53
550k
        if (sm->type == DETECT_BSIZE) {
54
24.1k
            bsz = (DetectU64Data *)sm->ctx;
55
24.1k
            bsize = SigParseGetMaxBsize(bsz);
56
24.1k
            break;
57
24.1k
        }
58
550k
    }
59
60
447k
    if (bsize == -1) {
61
422k
        return true;
62
422k
    }
63
64
24.1k
    uint64_t needed;
65
24.1k
    if (bsize >= 0) {
66
22.0k
        int len, offset;
67
22.0k
        SigParseRequiredContentSize(s, bsize, b->head, &len, &offset);
68
22.0k
        SCLogDebug("bsize: %d; len: %d; offset: %d [%s]", bsize, len, offset, s->sig_str);
69
22.0k
        needed = len;
70
22.0k
        if (len > bsize) {
71
10.1k
            goto value_error;
72
10.1k
        }
73
11.8k
        if ((len + offset) > bsize) {
74
3.27k
            needed += offset;
75
3.27k
            goto value_error;
76
3.27k
        }
77
11.8k
    }
78
79
10.7k
    return true;
80
13.4k
value_error:
81
13.4k
    if (bsz->mode == DETECT_UINT_RA) {
82
1.91k
        SCLogError("signature can't match as required content length %" PRIu64
83
1.91k
                   " exceeds bsize range: %" PRIu64 "-%" PRIu64,
84
1.91k
                needed, bsz->arg1, bsz->arg2);
85
11.5k
    } else {
86
11.5k
        SCLogError("signature can't match as required content length %" PRIu64
87
11.5k
                   " exceeds bsize value: "
88
11.5k
                   "%" PRIu64,
89
11.5k
                needed, bsz->arg1);
90
11.5k
    }
91
13.4k
    return false;
92
24.1k
}
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
3.25k
{
121
3.25k
    const DetectU64Data *bsz = (const DetectU64Data *)ctx;
122
3.25k
    if (DetectU64Match(buffer_size, bsz)) {
123
1.07k
        return 1;
124
1.07k
    }
125
2.18k
    switch (bsz->mode) {
126
0
        case DETECT_UINT_LTE:
127
0
            return -1;
128
2
        case DETECT_UINT_LT:
129
2
            return -1;
130
131
0
        case DETECT_UINT_GTE:
132
            // fallthrough
133
160
        case DETECT_UINT_GT:
134
160
            if (eof) {
135
155
                return -1;
136
155
            }
137
5
            return 0;
138
139
1.92k
        case DETECT_UINT_EQ:
140
1.92k
            if (buffer_size > bsz->arg1) {
141
74
                return -1;
142
1.84k
            } else if (eof) {
143
981
                return -1;
144
981
            } else {
145
865
                return 0;
146
865
            }
147
148
99
        case DETECT_UINT_RA:
149
99
            if (buffer_size <= bsz->arg1 && eof) {
150
59
                return -1;
151
59
            } else if (buffer_size <= bsz->arg1) {
152
31
                return 0;
153
31
            } else if (buffer_size >= bsz->arg2) {
154
9
                return -1;
155
9
            }
156
2.18k
    }
157
0
    return 0;
158
2.18k
}
159
160
static int SigParseGetMaxBsize(DetectU64Data *bsz)
161
34.0k
{
162
34.0k
    switch (bsz->mode) {
163
6.03k
        case DETECT_UINT_LT:
164
23.0k
        case DETECT_UINT_EQ:
165
23.0k
            return bsz->arg1;
166
7.79k
        case DETECT_UINT_RA:
167
7.79k
            return bsz->arg2;
168
3.00k
        case DETECT_UINT_GT:
169
3.22k
        default:
170
3.22k
            SCReturnInt(-2);
171
34.0k
    }
172
34.0k
    SCReturnInt(-1);
173
34.0k
}
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
50.9k
{
187
50.9k
    SCEnter();
188
50.9k
    SigMatch *sm = NULL;
189
190
50.9k
    if (DetectBufferGetActiveList(de_ctx, s) == -1)
191
3
        SCReturnInt(-1);
192
193
50.8k
    int list = s->init_data->list;
194
50.8k
    if (list == DETECT_SM_LIST_NOTSET)
195
384
        SCReturnInt(-1);
196
197
50.5k
    DetectU64Data *bsz = DetectU64Parse(sizestr);
198
50.5k
    if (bsz == NULL)
199
6.04k
        SCReturnInt(-1);
200
201
44.4k
    sm = SigMatchAlloc();
202
44.4k
    if (sm == NULL)
203
0
        goto error;
204
44.4k
    sm->type = DETECT_BSIZE;
205
44.4k
    sm->ctx = (void *)bsz;
206
207
44.4k
    SigMatchAppendSMToList(s, sm, list);
208
209
44.4k
    SCReturnInt(0);
210
211
0
error:
212
0
    DetectBsizeFree(de_ctx, bsz);
213
0
    SCReturnInt(-1);
214
44.4k
}
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
44.4k
{
223
44.4k
    if (ptr == NULL)
224
0
        return;
225
226
44.4k
    DetectU64Data *bsz = (DetectU64Data *)ptr;
227
44.4k
    rs_detect_u64_free(bsz);
228
44.4k
}
229
230
#ifdef UNITTESTS
231
#include "tests/detect-bsize.c"
232
#endif