• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23411539685

22 Mar 2026 08:12PM UTC coverage: 76.654% (-2.7%) from 79.315%
23411539685

Pull #15087

github

web-flow
Merge e35430d56 into 6587e363a
Pull Request #15087: Encryption bypass 8336 v2

6 of 6 new or added lines in 3 files covered. (100.0%)

12686 existing lines in 284 files now uncovered.

245104 of 319754 relevant lines covered (76.65%)

3304880.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.25
/src/app-layer-frames.c
1
/* Copyright (C) 2007-2024 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
 */
24

25
#include "suricata-common.h"
26
#include "util-print.h"
27

28
#include "flow.h"
29
#include "stream-tcp.h"
30
#include "rust.h"
31
#include "app-layer-frames.h"
32
#include "app-layer-parser.h"
33

34
struct FrameConfig {
35
    SC_ATOMIC_DECLARE(uint64_t, types);
36
};
37
/* This array should be allocated to contain g_alproto_max protocols. */
38
static struct FrameConfig *frame_config;
39

40
void FrameConfigInit(void)
41
{
44✔
42
    frame_config = SCCalloc(g_alproto_max, sizeof(struct FrameConfig));
44✔
43
    if (unlikely(frame_config == NULL)) {
44✔
44
        FatalError("Unable to alloc frame_config.");
×
45
    }
×
46
    for (AppProto p = 0; p < g_alproto_max; p++) {
1,804✔
47
        SC_ATOMIC_INIT(frame_config[p].types);
1,760✔
48
    }
1,760✔
49
}
44✔
50

51
void FrameConfigDeInit(void)
52
{
30✔
53
    SCFree(frame_config);
30✔
54
}
30✔
55

56
void FrameConfigEnableAll(void)
UNCOV
57
{
×
UNCOV
58
    const uint64_t bits = UINT64_MAX;
×
UNCOV
59
    for (AppProto p = 0; p < g_alproto_max; p++) {
×
UNCOV
60
        struct FrameConfig *fc = &frame_config[p];
×
UNCOV
61
        SC_ATOMIC_OR(fc->types, bits);
×
UNCOV
62
    }
×
UNCOV
63
}
×
64

65
void FrameConfigEnable(const AppProto p, const uint8_t type)
66
{
36,441✔
67
    const uint64_t bits = BIT_U64(type);
36,441✔
68
    struct FrameConfig *fc = &frame_config[p];
36,441✔
69
    SC_ATOMIC_OR(fc->types, bits);
36,441✔
70
}
36,441✔
71

72
static inline bool FrameConfigTypeIsEnabled(const AppProto p, const uint8_t type)
73
{
3,013,150✔
74
    struct FrameConfig *fc = &frame_config[p];
3,013,150✔
75
    const uint64_t bits = BIT_U64(type);
3,013,150✔
76
    const bool enabled = (SC_ATOMIC_GET(fc->types) & bits) != 0;
3,013,150✔
77
    return enabled;
3,013,150✔
78
}
3,013,150✔
79

80
#ifdef DEBUG
81
static void FrameDebug(const char *prefix, const Frames *frames, const Frame *frame)
82
{
83
    const char *type_name = "unknown";
84
    if (frame->type == FRAME_STREAM_TYPE) {
85
        type_name = "stream";
86
    } else if (frames != NULL) {
87
        type_name = AppLayerParserGetFrameNameById(frames->ipproto, frames->alproto, frame->type);
88
    }
89
    SCLogDebug("[%s] %p: frame:%p type:%u/%s id:%" PRIi64 " flags:%02x offset:%" PRIu64
90
               ", len:%" PRIi64 ", inspect_progress:%" PRIu64 ", events:%u %u/%u/%u/%u",
91
            prefix, frames, frame, frame->type, type_name, frame->id, frame->flags, frame->offset,
92
            frame->len, frame->inspect_progress, frame->event_cnt, frame->events[0],
93
            frame->events[1], frame->events[2], frame->events[3]);
94
}
95
#else
96
#define FrameDebug(prefix, frames, frame)
97
#endif
98

99
/**
100
 * \note "open" means a frame that has no length set (len == -1)
101
 * \todo perhaps we can search backwards */
102
Frame *FrameGetLastOpenByType(Frames *frames, const uint8_t frame_type)
103
{
311,305✔
104
    Frame *candidate = NULL;
311,305✔
105

106
    SCLogDebug(
311,305✔
107
            "frames %p cnt %u, looking for last of type %" PRIu8, frames, frames->cnt, frame_type);
311,305✔
108
    for (uint16_t i = 0; i < frames->cnt; i++) {
1,552,188✔
109
        if (i < FRAMES_STATIC_CNT) {
1,240,883✔
110
            Frame *frame = &frames->sframes[i];
606,176✔
111
            FrameDebug("get_by_id(static)", frames, frame);
606,176✔
112
            if (frame->type == frame_type && frame->len == -1)
606,176✔
113
                candidate = frame;
8,160✔
114
        } else {
634,707✔
115
            const uint16_t o = i - FRAMES_STATIC_CNT;
634,707✔
116
            Frame *frame = &frames->dframes[o];
634,707✔
117
            FrameDebug("get_by_id(dynamic)", frames, frame);
634,707✔
118
            if (frame->type == frame_type && frame->len == -1)
634,707✔
119
                candidate = frame;
15✔
120
        }
634,707✔
121
    }
1,240,883✔
122
    return candidate;
311,305✔
123
}
311,305✔
124

125
Frame *FrameGetById(Frames *frames, const int64_t id)
126
{
149,174✔
127
    SCLogDebug("frames %p cnt %u, looking for %" PRIi64, frames, frames->cnt, id);
149,174✔
128
    for (uint16_t i = 0; i < frames->cnt; i++) {
1,970,551✔
129
        if (i < FRAMES_STATIC_CNT) {
1,970,441✔
130
            Frame *frame = &frames->sframes[i];
367,503✔
131
            FrameDebug("get_by_id(static)", frames, frame);
367,503✔
132
            if (frame->id == id)
367,503✔
133
                return frame;
68,352✔
134
        } else {
1,602,938✔
135
            const uint16_t o = i - FRAMES_STATIC_CNT;
1,602,938✔
136
            Frame *frame = &frames->dframes[o];
1,602,938✔
137
            FrameDebug("get_by_id(dynamic)", frames, frame);
1,602,938✔
138
            if (frame->id == id)
1,602,938✔
139
                return frame;
80,712✔
140
        }
1,602,938✔
141
    }
1,970,441✔
142
    return NULL;
110✔
143
}
149,174✔
144

145
Frame *FrameGetByIndex(Frames *frames, const uint32_t idx)
146
{
11,165,769✔
147
    if (idx >= frames->cnt)
11,165,769✔
148
        return NULL;
×
149

150
    if (idx < FRAMES_STATIC_CNT) {
11,165,769✔
151
        Frame *frame = &frames->sframes[idx];
797,010✔
152
        FrameDebug("get_by_idx(s)", frames, frame);
797,010✔
153
        return frame;
797,010✔
154
    } else {
10,368,759✔
155
        const uint32_t o = idx - FRAMES_STATIC_CNT;
10,368,759✔
156
        Frame *frame = &frames->dframes[o];
10,368,759✔
157
        FrameDebug("get_by_idx(d)", frames, frame);
10,368,759✔
158
        return frame;
10,368,759✔
159
    }
10,368,759✔
160
}
11,165,769✔
161

162
static Frame *FrameNew(Frames *frames, uint64_t offset, int64_t len)
163
{
1,244,041✔
164
    DEBUG_VALIDATE_BUG_ON(frames == NULL);
1,244,041✔
165

166
    if (frames->cnt < FRAMES_STATIC_CNT) {
1,244,041✔
167
        Frame *frame = &frames->sframes[frames->cnt];
722,529✔
168
        frames->sframes[frames->cnt].offset = offset;
722,529✔
169
        frames->sframes[frames->cnt].len = len;
722,529✔
170
        frames->sframes[frames->cnt].id = ++frames->base_id;
722,529✔
171
        frames->cnt++;
722,529✔
172
        return frame;
722,529✔
173
    } else if (frames->dframes == NULL) {
722,529✔
174
        DEBUG_VALIDATE_BUG_ON(frames->dyn_size != 0);
8,820✔
175
        DEBUG_VALIDATE_BUG_ON(frames->cnt != FRAMES_STATIC_CNT);
8,820✔
176

177
        frames->dframes = SCCalloc(8, sizeof(Frame));
8,820✔
178
        if (frames->dframes == NULL) {
8,820✔
179
            return NULL;
×
180
        }
×
181
        frames->cnt++;
8,820✔
182
        DEBUG_VALIDATE_BUG_ON(frames->cnt != FRAMES_STATIC_CNT + 1);
8,820✔
183

184
        frames->dyn_size = 8;
8,820✔
185
        frames->dframes[0].offset = offset;
8,820✔
186
        frames->dframes[0].len = len;
8,820✔
187
        frames->dframes[0].id = ++frames->base_id;
8,820✔
188
        return &frames->dframes[0];
8,820✔
189
    } else {
512,692✔
190
        DEBUG_VALIDATE_BUG_ON(frames->cnt < FRAMES_STATIC_CNT);
512,692✔
191

192
        /* need to handle dynamic storage of frames now */
193
        const uint16_t dyn_cnt = frames->cnt - FRAMES_STATIC_CNT;
512,692✔
194
        if (dyn_cnt < frames->dyn_size) {
512,692✔
195
            DEBUG_VALIDATE_BUG_ON(frames->dframes == NULL);
403,130✔
196

197
            // fall through
198
        } else {
403,130✔
199
            if (frames->dyn_size == 256) {
109,562✔
200
                SCLogDebug("limit reached! 256 dynamic frames already");
102,097✔
201
                // limit reached
202
                // TODO figure out if this should lead to an event of sorts
203
                return NULL;
102,097✔
204
            }
102,097✔
205

206
            /* realloc time */
207
            uint16_t new_dyn_size = frames->dyn_size * 2;
7,465✔
208
            uint32_t new_alloc_size = new_dyn_size * sizeof(Frame);
7,465✔
209

210
            void *ptr = SCRealloc(frames->dframes, new_alloc_size);
7,465✔
211
            if (ptr == NULL) {
7,465✔
212
                return NULL;
×
213
            }
×
214

215
            memset((uint8_t *)ptr + (frames->dyn_size * sizeof(Frame)), 0x00,
7,465✔
216
                    (frames->dyn_size * sizeof(Frame)));
7,465✔
217
            frames->dframes = ptr;
7,465✔
218
            frames->dyn_size = new_dyn_size;
7,465✔
219
        }
7,465✔
220

221
        frames->cnt++;
410,595✔
222
        frames->dframes[dyn_cnt].offset = offset;
410,595✔
223
        frames->dframes[dyn_cnt].len = len;
410,595✔
224
        frames->dframes[dyn_cnt].id = ++frames->base_id;
410,595✔
225
        return &frames->dframes[dyn_cnt];
410,595✔
226
    }
512,692✔
227
}
1,244,041✔
228

229
static void FrameClean(Frame *frame)
230
{
1,160,215✔
231
    memset(frame, 0, sizeof(*frame));
1,160,215✔
232
}
1,160,215✔
233

234
static void FrameCopy(Frame *dst, Frame *src)
235
{
13,986,327✔
236
    memcpy(dst, src, sizeof(*dst));
13,986,327✔
237
}
13,986,327✔
238

239
#ifdef DEBUG
240
static void AppLayerFrameDumpForFrames(const char *prefix, const Frames *frames)
241
{
242
    SCLogDebug("prefix: %s", prefix);
243
    for (uint16_t i = 0; i < frames->cnt; i++) {
244
        if (i < FRAMES_STATIC_CNT) {
245
            const Frame *frame = &frames->sframes[i];
246
            FrameDebug(prefix, frames, frame);
247
        } else {
248
            const uint16_t o = i - FRAMES_STATIC_CNT;
249
            const Frame *frame = &frames->dframes[o];
250
            FrameDebug(prefix, frames, frame);
251
        }
252
    }
253
    SCLogDebug("prefix: %s", prefix);
254
}
255
#endif
256

257
static inline uint64_t FrameLeftEdge(const TcpStream *stream, const Frame *frame)
258
{
14,421,894✔
259
    const int64_t app_progress = STREAM_APP_PROGRESS(stream);
14,421,894✔
260

261
    const int64_t frame_offset = frame->offset;
14,421,894✔
262
    const int64_t frame_data = app_progress - frame_offset;
14,421,894✔
263

264
    SCLogDebug("frame_offset %" PRIi64 ", frame_data %" PRIi64 ", frame->len %" PRIi64,
14,421,894✔
265
            frame_offset, frame_data, frame->len);
14,421,894✔
266
    DEBUG_VALIDATE_BUG_ON(frame_offset > app_progress);
14,421,894✔
267

268
    /* length unknown, make sure to have at least 2500 */
269
    if (frame->len < 0) {
14,421,894✔
270
        if (frame_data <= 2500) {
203,334✔
271
            SCLogDebug("got <= 2500 bytes (%" PRIu64 "), returning offset %" PRIu64, frame_data,
125,934✔
272
                    frame_offset);
125,934✔
273
            return frame_offset;
125,934✔
274
        } else {
125,934✔
275
            SCLogDebug("got > 2500 bytes (%" PRIu64 "), returning offset %" PRIu64, frame_data,
77,400✔
276
                    (frame_offset + (frame_data - 2500)));
77,400✔
277
            return frame_offset + (frame_data - 2500);
77,400✔
278
        }
77,400✔
279

280
        /* length specified */
281
    } else {
14,218,560✔
282
        /* have all data for the frame, we can skip it */
283
        if (frame->len <= frame_data) {
14,218,560✔
284
            uint64_t x = frame_offset + frame_data;
14,193,384✔
285
            SCLogDebug("x %" PRIu64, x);
14,193,384✔
286
            return x;
14,193,384✔
287
            /*
288

289
                [ stream      <frame_data> ]
290
                             [ frame        .......]
291

292
             */
293
        } else if (frame_data < 2500) {
14,193,384✔
294
            uint64_t x = frame_offset;
14,004✔
295
            SCLogDebug("x %" PRIu64, x);
14,004✔
296
            return x;
14,004✔
297
        } else {
14,004✔
298
            uint64_t x = frame_offset + (frame_data - 2500);
11,172✔
299
            SCLogDebug("x %" PRIu64, x);
11,172✔
300
            return x;
11,172✔
301
        }
11,172✔
302
    }
14,218,560✔
303
}
14,421,894✔
304

305
/** Stream buffer slides forward, we need to update and age out
306
 *  frame offsets/frames. Aging out means we move existing frames
307
 *  into the slots we'd free up.
308
 *
309
 *  Start:
310
 *
311
 *  [ stream ]
312
 *    [ frame   ...........]
313
 *      offset: 2
314
 *      len: 19
315
 *
316
 *  Slide:
317
 *         [ stream ]
318
 *    [ frame ....          .]
319
 *      offset: 2
320
 *       len: 19
321
 *
322
 *  Slide:
323
 *                [ stream ]
324
 *    [ frame ...........    ]
325
 *      offset: 2
326
 *      len: 19
327
 */
328
static int FrameSlide(const char *ds, Frames *frames, const TcpStream *stream, const uint32_t slide)
329
{
15,070✔
330
    SCLogDebug("start: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64
15,070✔
331
               ", next %" PRIu64,
15,070✔
332
            (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream), frames->left_edge_rel,
15,070✔
333
            STREAM_BASE_OFFSET(stream), STREAM_BASE_OFFSET(stream) + slide);
15,070✔
334
    DEBUG_VALIDATE_BUG_ON(frames == NULL);
15,070✔
335
    SCLogDebug("%s frames %p: sliding %u bytes", ds, frames, slide);
15,070✔
336
    uint64_t le = STREAM_APP_PROGRESS(stream);
15,070✔
337
    const uint64_t next_base = STREAM_BASE_OFFSET(stream) + slide;
15,070✔
338
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
339
    const uint16_t start = frames->cnt;
340
    uint16_t removed = 0;
341
#endif
342
    uint16_t x = 0;
15,070✔
343
    for (uint16_t i = 0; i < frames->cnt; i++) {
456,853✔
344
        if (i < FRAMES_STATIC_CNT) {
441,783✔
345
            Frame *frame = &frames->sframes[i];
11,307✔
346
            FrameDebug("slide(s)", frames, frame);
11,307✔
347
            if (frame->len >= 0 && frame->offset + frame->len <= next_base) {
11,307✔
348
                // remove by not incrementing 'x'
349
                SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
189✔
350
                FrameClean(frame);
189✔
351
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
352
                removed++;
353
#endif
354
            } else {
11,118✔
355
                Frame *nframe = &frames->sframes[x];
11,118✔
356
                FrameCopy(nframe, frame);
11,118✔
357
                if (frame != nframe) {
11,118✔
358
                    FrameClean(frame);
10✔
359
                }
10✔
360
                le = MIN(le, FrameLeftEdge(stream, nframe));
11,118✔
361
                x++;
11,118✔
362
            }
11,118✔
363
        } else {
430,476✔
364
            const uint16_t o = i - FRAMES_STATIC_CNT;
430,476✔
365
            Frame *frame = &frames->dframes[o];
430,476✔
366
            FrameDebug("slide(d)", frames, frame);
430,476✔
367
            if (frame->len >= 0 && frame->offset + frame->len <= next_base) {
430,476✔
368
                // remove by not incrementing 'x'
369
                SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
5,837✔
370
                FrameClean(frame);
5,837✔
371
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
372
                removed++;
373
#endif
374
            } else {
424,639✔
375
                Frame *nframe;
424,639✔
376
                if (x >= FRAMES_STATIC_CNT) {
424,639✔
377
                    nframe = &frames->dframes[x - FRAMES_STATIC_CNT];
424,478✔
378
                } else {
424,478✔
379
                    nframe = &frames->sframes[x];
161✔
380
                }
161✔
381
                FrameCopy(nframe, frame);
424,639✔
382
                if (frame != nframe) {
424,639✔
383
                    FrameClean(frame);
6,323✔
384
                }
6,323✔
385
                le = MIN(le, FrameLeftEdge(stream, nframe));
424,639✔
386
                x++;
424,639✔
387
            }
424,639✔
388
        }
430,476✔
389
    }
441,783✔
390
    frames->cnt = x;
15,070✔
391
    uint64_t o = STREAM_BASE_OFFSET(stream) + slide;
15,070✔
392
    DEBUG_VALIDATE_BUG_ON(o > le);
15,070✔
393
    DEBUG_VALIDATE_BUG_ON(le - o > UINT32_MAX);
15,070✔
394
    frames->left_edge_rel = (uint32_t)(le - o);
15,070✔
395

396
#ifdef DEBUG
397
    SCLogDebug("end: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64
398
               " (+slide), cnt %u, removed %u, start %u",
399
            (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream) + slide,
400
            frames->left_edge_rel, STREAM_BASE_OFFSET(stream) + slide, frames->cnt, removed, start);
401
    char pf[32] = "";
402
    snprintf(pf, sizeof(pf), "%s:post_slide", ds);
403
    AppLayerFrameDumpForFrames(pf, frames);
404
#endif
405
    DEBUG_VALIDATE_BUG_ON(x != start - removed);
15,070✔
406
    return 0;
15,070✔
407
}
15,070✔
408

409
void AppLayerFramesSlide(Flow *f, const uint32_t slide, const uint8_t direction)
410
{
34,462✔
411
    FramesContainer *frames_container = AppLayerFramesGetContainer(f);
34,462✔
412
    if (frames_container == NULL)
34,462✔
413
        return;
19,394✔
414
    Frames *frames;
2,147,498,717✔
415
    TcpSession *ssn = f->protoctx;
2,147,498,717✔
416
    TcpStream *stream;
2,147,498,717✔
417
    if (direction == STREAM_TOSERVER) {
2,147,498,717✔
418
        stream = &ssn->client;
6,988✔
419
        frames = &frames_container->toserver;
6,988✔
420
        FrameSlide("toserver", frames, stream, slide);
6,988✔
421
    } else {
2,147,491,729✔
422
        stream = &ssn->server;
2,147,491,729✔
423
        frames = &frames_container->toclient;
2,147,491,729✔
424
        FrameSlide("toclient", frames, stream, slide);
2,147,491,729✔
425
    }
2,147,491,729✔
426
}
2,147,498,717✔
427

428
static void FrameFreeSingleFrame(Frames *frames, Frame *r)
429
{
180,761✔
430
    FrameDebug("free", frames, r);
180,761✔
431
    FrameClean(r);
180,761✔
432
}
180,761✔
433

434
static void FramesClear(Frames *frames)
435
{
82,026✔
436
    DEBUG_VALIDATE_BUG_ON(frames == NULL);
82,026✔
437

438
    SCLogDebug("frames %u", frames->cnt);
82,026✔
439
    for (uint16_t i = 0; i < frames->cnt; i++) {
262,787✔
440
        if (i < FRAMES_STATIC_CNT) {
180,761✔
441
            Frame *r = &frames->sframes[i];
66,195✔
442
            SCLogDebug("removing frame %p", r);
66,195✔
443
            FrameFreeSingleFrame(frames, r);
66,195✔
444
        } else {
114,566✔
445
            const uint16_t o = i - FRAMES_STATIC_CNT;
114,566✔
446
            Frame *r = &frames->dframes[o];
114,566✔
447
            SCLogDebug("removing frame %p", r);
114,566✔
448
            FrameFreeSingleFrame(frames, r);
114,566✔
449
        }
114,566✔
450
    }
180,761✔
451
    frames->cnt = 0;
82,026✔
452
}
82,026✔
453

454
void FramesFree(Frames *frames)
455
{
55,386✔
456
    DEBUG_VALIDATE_BUG_ON(frames == NULL);
55,386✔
457
    FramesClear(frames);
55,386✔
458
    SCFree(frames->dframes);
55,386✔
459
    frames->dframes = NULL;
55,386✔
460
}
55,386✔
461

462
/** \brief create new frame using a pointer to start of the frame
463
 */
464
Frame *AppLayerFrameNewByPointer(Flow *f, const StreamSlice *stream_slice,
465
        const uint8_t *frame_start, const int64_t len, int dir, uint8_t frame_type)
466
{
166,172✔
467
    SCLogDebug("frame_start:%p stream_slice->input:%p stream_slice->offset:%" PRIu64, frame_start,
166,172✔
468
            stream_slice->input, stream_slice->offset);
166,172✔
469

470
    if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
166,172✔
471
        return NULL;
113,025✔
472

473
        /* workarounds for many (unit|fuzz)tests not handling TCP data properly */
474
#if defined(UNITTESTS) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
53,163✔
475
    if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
53,163✔
476
        return NULL;
24✔
477
    if (frame_start < stream_slice->input ||
53,139✔
478
            frame_start > stream_slice->input + stream_slice->input_len)
53,139✔
479
        return NULL;
480
#endif
53,139✔
481
    DEBUG_VALIDATE_BUG_ON(frame_start < stream_slice->input);
2,147,536,786✔
482
    DEBUG_VALIDATE_BUG_ON(stream_slice->input == NULL);
2,147,536,786✔
483
    DEBUG_VALIDATE_BUG_ON(f->proto == IPPROTO_TCP && f->protoctx == NULL);
2,147,536,786✔
484

485
    ptrdiff_t ptr_offset = frame_start - stream_slice->input;
2,147,536,786✔
486
#ifdef DEBUG
487
    uint64_t offset = ptr_offset + stream_slice->offset;
488
    SCLogDebug("flow %p direction %s frame %p starting at %" PRIu64 " len %" PRIi64
489
               " (offset %" PRIu64 ")",
490
            f, dir == 0 ? "toserver" : "toclient", frame_start, offset, len, stream_slice->offset);
491
#endif
492
    DEBUG_VALIDATE_BUG_ON(f->alparser == NULL);
2,147,536,786✔
493

494
    FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
2,147,536,786✔
495
    if (frames_container == NULL)
2,147,536,786✔
496
        return NULL;
×
497

498
    Frames *frames;
2,147,536,786✔
499
    if (dir == 0) {
2,147,536,786✔
500
        frames = &frames_container->toserver;
24,735✔
501
    } else {
2,147,512,051✔
502
        frames = &frames_container->toclient;
2,147,512,051✔
503
    }
2,147,512,051✔
504

505
    uint64_t abs_frame_offset = stream_slice->offset + ptr_offset;
2,147,536,786✔
506

507
    Frame *r = FrameNew(frames, abs_frame_offset, len);
2,147,536,786✔
508
    if (r != NULL) {
2,147,536,786✔
509
        r->type = frame_type;
52,133✔
510
        FrameDebug("new_by_ptr", frames, r);
52,133✔
511
    }
52,133✔
512
    return r;
2,147,536,786✔
513
}
2,147,536,786✔
514

515
static Frame *AppLayerFrameUdp(
516
        Flow *f, const uint32_t frame_start_rel, const int64_t len, int dir, uint8_t frame_type)
517
{
32,109✔
518
    DEBUG_VALIDATE_BUG_ON(f->proto != IPPROTO_UDP);
32,109✔
519

520
    if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
32,109✔
521
        return NULL;
×
522

523
    FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
32,109✔
524
    if (frames_container == NULL)
32,109✔
525
        return NULL;
×
526

527
    Frames *frames;
32,109✔
528
    if (dir == 0) {
32,109✔
529
        frames = &frames_container->toserver;
25,644✔
530
    } else {
25,644✔
531
        frames = &frames_container->toclient;
6,465✔
532
    }
6,465✔
533

534
    Frame *r = FrameNew(frames, frame_start_rel, len);
32,109✔
535
    if (r != NULL) {
32,109✔
536
        r->type = frame_type;
32,109✔
537
    }
32,109✔
538
    return r;
32,109✔
539
}
32,109✔
540

541
/** \brief create new frame using a relative offset from the start of the stream slice
542
 */
543
Frame *SCAppLayerFrameNewByRelativeOffset(Flow *f, const void *ss, const uint32_t frame_start_rel,
544
        const int64_t len, int dir, uint8_t frame_type)
545
{
2,312,880✔
546
    // need to hide StreamSlice argument
547
    // as we cannot bindgen a C function with an argument whose type
548
    // is defined in rust (at least before a suricata_core crate)
549
    const StreamSlice *stream_slice = (const StreamSlice *)ss;
2,312,880✔
550
    if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
2,312,880✔
551
        return NULL;
1,165,083✔
552

553
        /* workarounds for many (unit|fuzz)tests not handling TCP data properly */
554
#if defined(UNITTESTS) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
1,147,807✔
555
    if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
1,147,807✔
556
        return NULL;
557
    if (stream_slice->input == NULL)
1,147,807✔
558
        return NULL;
559
#else
560
    DEBUG_VALIDATE_BUG_ON(stream_slice->input == NULL);
2,147,483,647✔
561
#endif
2,147,483,647✔
562
    DEBUG_VALIDATE_BUG_ON(f->proto == IPPROTO_TCP && f->protoctx == NULL);
2,148,631,454✔
563
    DEBUG_VALIDATE_BUG_ON(f->alparser == NULL);
2,148,631,454✔
564

565
    if (f->proto == IPPROTO_UDP) {
2,148,631,454✔
566
        return AppLayerFrameUdp(f, frame_start_rel, len, dir, frame_type);
32,109✔
567
    }
32,109✔
568

569
    FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
2,148,599,345✔
570
    if (frames_container == NULL)
2,148,599,345✔
571
        return NULL;
×
572

573
    Frames *frames;
2,148,599,345✔
574
    if (dir == 0) {
2,148,599,345✔
575
        frames = &frames_container->toserver;
555,396✔
576
    } else {
2,148,043,949✔
577
        frames = &frames_container->toclient;
2,148,043,949✔
578
    }
2,148,043,949✔
579

580
    const uint64_t frame_abs_offset = (uint64_t)frame_start_rel + stream_slice->offset;
2,148,599,345✔
581
#ifdef DEBUG_VALIDATION
582
    const TcpSession *ssn = f->protoctx;
583
    const TcpStream *stream = dir == 0 ? &ssn->client : &ssn->server;
584
    BUG_ON(stream_slice->offset != STREAM_APP_PROGRESS(stream));
585
    BUG_ON(frame_abs_offset > STREAM_APP_PROGRESS(stream) + stream_slice->input_len);
586
#endif
587
    Frame *r = FrameNew(frames, frame_abs_offset, len);
2,148,599,345✔
588
    if (r != NULL) {
2,148,599,345✔
589
        r->type = frame_type;
1,014,607✔
590
    }
1,014,607✔
591
    return r;
2,148,599,345✔
592
}
2,148,599,345✔
593

594
void AppLayerFrameDump(Flow *f)
595
{
537,479✔
596
#ifdef DEBUG
597
    if (f->proto == IPPROTO_TCP && f->protoctx && f->alparser) {
598
        FramesContainer *frames_container = AppLayerFramesGetContainer(f);
599
        if (frames_container != NULL) {
600
            AppLayerFrameDumpForFrames("toserver::dump", &frames_container->toserver);
601
            AppLayerFrameDumpForFrames("toclient::dump", &frames_container->toclient);
602
        }
603
    }
604
#endif
605
}
537,479✔
606

607
/** \brief create new frame using the absolute offset from the start of the stream
608
 */
609
Frame *AppLayerFrameNewByAbsoluteOffset(Flow *f, const StreamSlice *stream_slice,
610
        const uint64_t frame_start, const int64_t len, int dir, uint8_t frame_type)
611
{
76,408✔
612
    if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
76,408✔
613
        return NULL;
33,316✔
614

615
        /* workarounds for many (unit|fuzz)tests not handling TCP data properly */
616
#if defined(UNITTESTS) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
43,096✔
617
    if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
43,096✔
618
        return NULL;
619
    if (stream_slice->input == NULL)
43,096✔
620
        return NULL;
1✔
621
#else
622
    DEBUG_VALIDATE_BUG_ON(stream_slice->input == NULL);
2,147,483,647✔
623
#endif
2,147,483,647✔
624
    DEBUG_VALIDATE_BUG_ON(f->proto == IPPROTO_TCP && f->protoctx == NULL);
2,147,526,742✔
625
    DEBUG_VALIDATE_BUG_ON(f->alparser == NULL);
2,147,526,742✔
626
    DEBUG_VALIDATE_BUG_ON(frame_start < stream_slice->offset);
2,147,526,742✔
627
    DEBUG_VALIDATE_BUG_ON(frame_start - stream_slice->offset >= (uint64_t)INT_MAX);
2,147,526,742✔
628

629
    FramesContainer *frames_container = AppLayerFramesSetupContainer(f);
2,147,526,742✔
630
    if (frames_container == NULL)
2,147,526,742✔
631
        return NULL;
×
632

633
    Frames *frames;
2,147,526,742✔
634
    if (dir == 0) {
2,147,526,742✔
635
        frames = &frames_container->toserver;
22,873✔
636
    } else {
2,147,506,520✔
637
        frames = &frames_container->toclient;
2,147,503,869✔
638
    }
2,147,503,869✔
639

640
    SCLogDebug("flow %p direction %s frame type %u offset %" PRIu64 " len %" PRIi64
2,147,526,742✔
641
               " (slice offset %" PRIu64 ")",
2,147,526,742✔
642
            f, dir == 0 ? "toserver" : "toclient", frame_type, frame_start, len,
2,147,526,742✔
643
            stream_slice->offset);
2,147,526,742✔
644
    Frame *r = FrameNew(frames, frame_start, len);
2,147,526,742✔
645
    if (r != NULL) {
2,147,526,742✔
646
        r->type = frame_type;
43,095✔
647
    }
43,095✔
648
    return r;
2,147,526,742✔
649
}
2,147,526,742✔
650

651
void AppLayerFrameAddEvent(Frame *r, uint8_t e)
652
{
143✔
653
    if (r != NULL) {
143✔
654
        if (r->event_cnt < 4) { // TODO
143✔
655
            r->events[r->event_cnt++] = e;
143✔
656
        }
143✔
657
        FrameDebug("add_event", NULL, r);
143✔
658
    }
143✔
659
}
143✔
660

661
void SCAppLayerFrameAddEventById(const Flow *f, const int dir, const FrameId id, uint8_t e)
662
{
143✔
663
    Frame *frame = AppLayerFrameGetById(f, dir, id);
143✔
664
    AppLayerFrameAddEvent(frame, e);
143✔
665
}
143✔
666

667
void AppLayerFrameSetLength(Frame *frame, int64_t len)
668
{
45✔
669
    if (frame != NULL) {
45✔
670
        frame->len = len;
45✔
671
        FrameDebug("set_length", NULL, frame);
45✔
672
    }
45✔
673
}
45✔
674

675
void SCAppLayerFrameSetLengthById(const Flow *f, const int dir, const FrameId id, int64_t len)
676
{
45✔
677
    Frame *frame = AppLayerFrameGetById(f, dir, id);
45✔
678
    AppLayerFrameSetLength(frame, len);
45✔
679
}
45✔
680

681
void AppLayerFrameSetTxId(Frame *r, uint64_t tx_id)
682
{
162,693✔
683
    if (r != NULL) {
162,693✔
684
        r->flags |= FRAME_FLAG_TX_ID_SET;
162,693✔
685
        r->tx_id = tx_id;
162,693✔
686
        FrameDebug("set_txid", NULL, r);
162,693✔
687
    }
162,693✔
688
}
162,693✔
689

690
void SCAppLayerFrameSetTxIdById(const Flow *f, const int dir, const FrameId id, uint64_t tx_id)
691
{
127,011✔
692
    Frame *frame = AppLayerFrameGetById(f, dir, id);
127,011✔
693
    AppLayerFrameSetTxId(frame, tx_id);
127,011✔
694
}
127,011✔
695

696
Frame *AppLayerFrameGetById(const Flow *f, const int dir, const FrameId frame_id)
697
{
147,456✔
698
    FramesContainer *frames_container = AppLayerFramesGetContainer(f);
147,456✔
699
    SCLogDebug("get frame_id %" PRIi64 " direction %u/%s frames_container %p", frame_id, dir,
147,456✔
700
            dir == 0 ? "toserver" : "toclient", frames_container);
147,456✔
701
    if (frames_container == NULL)
147,456✔
702
        return NULL;
×
703

704
    Frames *frames;
147,456✔
705
    if (dir == 0) {
147,456✔
706
        frames = &frames_container->toserver;
87,561✔
707
    } else {
87,561✔
708
        frames = &frames_container->toclient;
59,895✔
709
    }
59,895✔
710
    SCLogDebug("frames %p", frames);
147,456✔
711
    return FrameGetById(frames, frame_id);
147,456✔
712
}
147,456✔
713

714
Frame *AppLayerFrameGetLastOpenByType(Flow *f, const int dir, const uint8_t frame_type)
715
{
425,599✔
716
    if (!(FrameConfigTypeIsEnabled(f->alproto, frame_type)))
425,599✔
717
        return NULL;
102,990✔
718

719
    FramesContainer *frames_container = AppLayerFramesGetContainer(f);
2,147,806,261✔
720
    SCLogDebug("get frame_type %" PRIu8 " direction %u/%s frames_container %p", frame_type, dir,
2,147,806,261✔
721
            dir == 0 ? "toserver" : "toclient", frames_container);
2,147,806,261✔
722
    if (frames_container == NULL)
2,147,806,261✔
723
        return NULL;
11,309✔
724

725
    Frames *frames;
2,147,794,952✔
726
    if (dir == 0) {
2,147,794,952✔
727
        frames = &frames_container->toserver;
291,767✔
728
    } else {
2,147,775,414✔
729
        frames = &frames_container->toclient;
2,147,503,185✔
730
    }
2,147,503,185✔
731
    SCLogDebug("frames %p", frames);
2,147,794,952✔
732
    return FrameGetLastOpenByType(frames, frame_type);
2,147,794,952✔
733
}
2,147,806,261✔
734

735
static inline bool FrameIsDone(const Frame *frame, const uint64_t abs_right_edge)
736
{
14,451,865✔
737
    /* frame with negative length means we don't know the size yet. */
738
    if (frame->len < 0)
14,451,865✔
739
        return false;
197,129✔
740

741
    const int64_t frame_abs_offset = frame->offset;
14,254,736✔
742
    const int64_t frame_right_edge = frame_abs_offset + frame->len;
14,254,736✔
743
    if ((uint64_t)frame_right_edge <= abs_right_edge) {
14,254,736✔
744
        SCLogDebug("frame %p id %" PRIi64 " is done", frame, frame->id);
901,295✔
745
        return true;
901,295✔
746
    }
901,295✔
747
    return false;
13,353,441✔
748
}
14,254,736✔
749

750
static void FramePrune(Frames *frames, const TcpStream *stream, const bool eof)
751
{
635,627✔
752
#ifdef DEBUG_VALIDATION
753
    const uint64_t frames_le_start = (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream);
754
#endif
755
    SCLogDebug("start: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64,
635,627✔
756
            (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream), frames->left_edge_rel,
635,627✔
757
            STREAM_BASE_OFFSET(stream));
635,627✔
758
    const uint64_t acked = StreamTcpGetUsable(stream, eof);
635,627✔
759
    uint64_t le = STREAM_APP_PROGRESS(stream);
635,627✔
760

761
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
762
    const uint16_t start = frames->cnt;
763
    uint16_t removed = 0;
764
#endif
765
    uint16_t x = 0;
635,627✔
766
    for (uint16_t i = 0; i < frames->cnt; i++) {
15,141,354✔
767
        if (i < FRAMES_STATIC_CNT) {
14,505,727✔
768
            Frame *frame = &frames->sframes[i];
1,134,541✔
769
            FrameDebug("prune(s)", frames, frame);
1,134,541✔
770
            if (eof || FrameIsDone(frame, acked)) {
1,134,541✔
771
                // remove by not incrementing 'x'
772
                SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
663,185✔
773
                FrameDebug("remove(s)", frames, frame);
663,185✔
774
                FrameClean(frame);
663,185✔
775
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
776
                removed++;
777
#endif
778
            } else {
663,185✔
779
                const uint64_t fle = FrameLeftEdge(stream, frame);
471,356✔
780
                le = MIN(le, fle);
471,356✔
781
                SCLogDebug("le %" PRIu64 ", frame fle %" PRIu64, le, fle);
471,356✔
782
                Frame *nframe = &frames->sframes[x];
471,356✔
783
                FrameCopy(nframe, frame);
471,356✔
784
                if (frame != nframe) {
471,356✔
785
                    FrameClean(frame);
3,169✔
786
                }
3,169✔
787
                x++;
471,356✔
788
            }
471,356✔
789
        } else {
13,371,186✔
790
            const uint16_t o = i - FRAMES_STATIC_CNT;
13,371,186✔
791
            Frame *frame = &frames->dframes[o];
13,371,186✔
792
            FrameDebug("prune(d)", frames, frame);
13,371,186✔
793
            if (eof || FrameIsDone(frame, acked)) {
13,371,186✔
794
                // remove by not incrementing 'x'
795
                SCLogDebug("removing %p id %" PRIi64, frame, frame->id);
291,972✔
796
                FrameDebug("remove(d)", frames, frame);
291,972✔
797
                FrameClean(frame);
291,972✔
798
#if defined(DEBUG) || defined(DEBUG_VALIDATION)
799
                removed++;
800
#endif
801
            } else {
13,079,214✔
802
                const uint64_t fle = FrameLeftEdge(stream, frame);
13,079,214✔
803
                le = MIN(le, fle);
13,079,214✔
804
                SCLogDebug("le %" PRIu64 ", frame fle %" PRIu64, le, fle);
13,079,214✔
805
                Frame *nframe;
13,079,214✔
806
                if (x >= FRAMES_STATIC_CNT) {
13,079,214✔
807
                    nframe = &frames->dframes[x - FRAMES_STATIC_CNT];
13,072,335✔
808
                } else {
13,072,335✔
809
                    nframe = &frames->sframes[x];
6,879✔
810
                }
6,879✔
811
                FrameCopy(nframe, frame);
13,079,214✔
812
                if (frame != nframe) {
13,079,214✔
813
                    FrameClean(frame);
8,769✔
814
                }
8,769✔
815
                x++;
13,079,214✔
816
            }
13,079,214✔
817
        }
13,371,186✔
818
    }
14,505,727✔
819
    frames->cnt = x;
635,627✔
820
    DEBUG_VALIDATE_BUG_ON(le < STREAM_BASE_OFFSET(stream));
635,627✔
821
    DEBUG_VALIDATE_BUG_ON(le - STREAM_BASE_OFFSET(stream) > UINT32_MAX);
635,627✔
822
    frames->left_edge_rel = (uint32_t)(le - STREAM_BASE_OFFSET(stream));
635,627✔
823
#ifdef DEBUG
824
    SCLogDebug("end: left edge %" PRIu64 ", left_edge_rel %u, stream base %" PRIu64
825
               ", cnt %u, removed %u, start %u",
826
            (uint64_t)frames->left_edge_rel + STREAM_BASE_OFFSET(stream), frames->left_edge_rel,
827
            STREAM_BASE_OFFSET(stream), frames->cnt, removed, start);
828
    AppLayerFrameDumpForFrames("post_slide", frames);
829
#endif
830
    if (frames->cnt > 0) { // if we removed all this can fail
635,627✔
831
        DEBUG_VALIDATE_BUG_ON(frames_le_start > le);
226,478✔
832
    }
226,478✔
833
    DEBUG_VALIDATE_BUG_ON(x != start - removed);
635,627✔
834
}
635,627✔
835

836
void FramesPrune(Flow *f, Packet *p)
837
{
851,019✔
838
    if (f->proto == IPPROTO_TCP && f->protoctx == NULL)
851,019✔
839
        return;
×
840
    FramesContainer *frames_container = AppLayerFramesGetContainer(f);
851,019✔
841
    if (frames_container == NULL)
851,019✔
842
        return;
186,910✔
843

844
    Frames *frames;
2,148,147,768✔
845

846
    if (p->proto == IPPROTO_UDP) {
2,148,147,768✔
847
        SCLogDebug("clearing all UDP frames");
26,640✔
848
        if (PKT_IS_TOSERVER(p)) {
26,640✔
849
            frames = &frames_container->toserver;
21,312✔
850
        } else {
21,312✔
851
            frames = &frames_container->toclient;
5,328✔
852
        }
5,328✔
853
        FramesClear(frames);
26,640✔
854
        return;
26,640✔
855
    }
26,640✔
856

857
    TcpSession *ssn = f->protoctx;
2,148,121,128✔
858

859
    if (ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) {
2,148,121,128✔
860
        AppLayerFramesFreeContainer(f);
1,854✔
861
        return;
1,854✔
862
    }
1,854✔
863

864
    TcpStream *stream;
2,148,119,274✔
865
    if (PKT_IS_TOSERVER(p)) {
2,148,119,274✔
866
        stream = &ssn->client;
320,462✔
867
        frames = &frames_container->toserver;
320,462✔
868
    } else {
2,147,804,109✔
869
        stream = &ssn->server;
2,147,798,812✔
870
        frames = &frames_container->toclient;
2,147,798,812✔
871
    }
2,147,798,812✔
872

873
    const bool eof = ssn->state == TCP_CLOSED || PKT_IS_PSEUDOPKT(p);
2,148,119,274✔
874
    SCLogDebug("eof %s", eof ? "TRUE" : "false");
2,148,119,274✔
875
    FramePrune(frames, stream, eof);
2,148,119,274✔
876
}
2,148,119,274✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc