Coverage Report

Created: 2025-11-16 07:09

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
119k
{
50
119k
    int bsize = -1;
51
119k
    DetectU64Data *bsz;
52
300k
    for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
53
187k
        if (sm->type == DETECT_BSIZE) {
54
5.46k
            bsz = (DetectU64Data *)sm->ctx;
55
5.46k
            bsize = SigParseGetMaxBsize(bsz);
56
5.46k
            break;
57
5.46k
        }
58
187k
    }
59
60
119k
    if (bsize == -1) {
61
113k
        return true;
62
113k
    }
63
64
5.46k
    uint64_t needed;
65
5.46k
    if (bsize >= 0) {
66
4.54k
        int len, offset;
67
4.54k
        SigParseRequiredContentSize(s, bsize, b->head, &len, &offset);
68
4.54k
        SCLogDebug("bsize: %d; len: %d; offset: %d [%s]", bsize, len, offset, s->sig_str);
69
4.54k
        needed = len;
70
4.54k
        if (len > bsize) {
71
1.73k
            goto value_error;
72
1.73k
        }
73
2.80k
        if ((len + offset) > bsize) {
74
536
            needed += offset;
75
536
            goto value_error;
76
536
        }
77
2.80k
    }
78
79
3.19k
    return true;
80
2.27k
value_error:
81
2.27k
    if (bsz->mode == DETECT_UINT_RA) {
82
346
        SCLogError("signature can't match as required content length %" PRIu64
83
346
                   " exceeds bsize range: %" PRIu64 "-%" PRIu64,
84
346
                needed, bsz->arg1, bsz->arg2);
85
1.92k
    } else {
86
1.92k
        SCLogError("signature can't match as required content length %" PRIu64
87
1.92k
                   " exceeds bsize value: "
88
1.92k
                   "%" PRIu64,
89
1.92k
                needed, bsz->arg1);
90
1.92k
    }
91
2.27k
    return false;
92
5.46k
}
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.08k
{
121
2.08k
    const DetectU64Data *bsz = (const DetectU64Data *)ctx;
122
2.08k
    if (DetectU64Match(buffer_size, bsz)) {
123
1.13k
        return 1;
124
1.13k
    }
125
950
    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
45
        case DETECT_UINT_GT:
134
45
            if (eof) {
135
43
                return -1;
136
43
            }
137
2
            return 0;
138
139
807
        case DETECT_UINT_EQ:
140
807
            if (buffer_size > bsz->arg1) {
141
58
                return -1;
142
749
            } else if (eof) {
143
749
                return -1;
144
749
            } else {
145
0
                return 0;
146
0
            }
147
148
96
        case DETECT_UINT_RA:
149
96
            if (buffer_size <= bsz->arg1 && eof) {
150
88
                return -1;
151
88
            } else if (buffer_size <= bsz->arg1) {
152
5
                return 0;
153
5
            } else if (buffer_size >= bsz->arg2) {
154
3
                return -1;
155
3
            }
156
950
    }
157
0
    return 0;
158
950
}
159
160
static int SigParseGetMaxBsize(DetectU64Data *bsz)
161
26.6k
{
162
26.6k
    switch (bsz->mode) {
163
4.75k
        case DETECT_UINT_LT:
164
18.3k
        case DETECT_UINT_EQ:
165
18.3k
            return bsz->arg1;
166
5.38k
        case DETECT_UINT_RA:
167
5.38k
            return bsz->arg2;
168
2.67k
        case DETECT_UINT_GT:
169
2.93k
        default:
170
2.93k
            SCReturnInt(-2);
171
26.6k
    }
172
26.6k
    SCReturnInt(-1);
173
26.6k
}
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
42.1k
{
187
42.1k
    SCEnter();
188
42.1k
    SigMatch *sm = NULL;
189
190
42.1k
    if (DetectBufferGetActiveList(de_ctx, s) == -1)
191
3
        SCReturnInt(-1);
192
193
42.1k
    int list = s->init_data->list;
194
42.1k
    if (list == DETECT_SM_LIST_NOTSET)
195
342
        SCReturnInt(-1);
196
197
41.7k
    DetectU64Data *bsz = DetectU64Parse(sizestr);
198
41.7k
    if (bsz == NULL)
199
3.37k
        SCReturnInt(-1);
200
201
38.4k
    sm = SigMatchAlloc();
202
38.4k
    if (sm == NULL)
203
0
        goto error;
204
38.4k
    sm->type = DETECT_BSIZE;
205
38.4k
    sm->ctx = (void *)bsz;
206
207
38.4k
    SigMatchAppendSMToList(s, sm, list);
208
209
38.4k
    SCReturnInt(0);
210
211
0
error:
212
0
    DetectBsizeFree(de_ctx, bsz);
213
0
    SCReturnInt(-1);
214
38.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
38.4k
{
223
38.4k
    if (ptr == NULL)
224
0
        return;
225
226
38.4k
    DetectU64Data *bsz = (DetectU64Data *)ptr;
227
38.4k
    rs_detect_u64_free(bsz);
228
38.4k
}
229
230
#ifdef UNITTESTS
231
#include "tests/detect-bsize.c"
232
#endif