Coverage Report

Created: 2026-03-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata/src/detect-frame.c
Line
Count
Source
1
/* Copyright (C) 2021-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
22
#include "suricata-common.h"
23
#include "threads.h"
24
#include "decode.h"
25
#include "detect.h"
26
27
#include "rust.h"
28
#include "app-layer-frames.h"
29
#include "app-layer-parser.h"
30
31
#include "detect-parse.h"
32
#include "detect-engine.h"
33
#include "detect-engine-buffer.h"
34
#include "detect-engine-mpm.h"
35
#include "detect-engine-prefilter.h"
36
#include "detect-content.h"
37
#include "detect-engine-content-inspection.h"
38
#include "detect-frame.h"
39
40
#include "flow.h"
41
#include "flow-util.h"
42
#include "flow-var.h"
43
44
#include "conf.h"
45
#include "conf-yaml-loader.h"
46
47
#include "util-debug.h"
48
#include "util-unittest.h"
49
#include "util-spm.h"
50
#include "util-print.h"
51
52
static int DetectFrameSetup(DetectEngineCtx *, Signature *, const char *);
53
54
/**
55
 * \brief this function setup the sticky buffer used in the rule
56
 *
57
 * \param de_ctx Pointer to the Detection Engine Context
58
 * \param s      Pointer to the Signature to which the current keyword belongs
59
 * \param str    The frame name. Can be short name 'pdu' or full name 'sip.pdu'
60
 *
61
 * \retval 0  On success
62
 * \retval -1 On failure
63
 */
64
static int DetectFrameSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
65
52.9k
{
66
52.9k
    char value[256] = "";
67
52.9k
    strlcpy(value, str, sizeof(value));
68
52.9k
    char buffer_name[512] = ""; // for registering in detect API we always need <proto>.<frame>.
69
70
52.9k
    const bool is_tcp = DetectProtoContainsProto(&s->proto, IPPROTO_TCP);
71
52.9k
    const bool is_udp = DetectProtoContainsProto(&s->proto, IPPROTO_UDP);
72
52.9k
    if (!(is_tcp || is_udp)) {
73
72
        SCLogError("'frame' keyword only supported for TCP and UDP");
74
72
        return -1;
75
72
    }
76
77
52.8k
    char *dot = strchr(value, '.');
78
52.8k
    if (dot != NULL)
79
37.8k
        *dot++ = '\0';
80
52.8k
    const char *val = dot ? dot : value;
81
52.8k
    const char *proto = dot ? value : NULL;
82
83
52.8k
    bool is_short = false;
84
52.8k
    AppProto keyword_alproto = ALPROTO_UNKNOWN;
85
52.8k
    AppProto rule_alproto = s->alproto;
86
87
52.8k
    if (proto != NULL) {
88
37.8k
        keyword_alproto = StringToAppProto(proto);
89
37.8k
        if (!AppProtoIsValid(keyword_alproto)) {
90
22.8k
            is_short = true;
91
22.8k
            keyword_alproto = rule_alproto;
92
22.8k
        }
93
37.8k
    } else {
94
15.0k
        is_short = true;
95
15.0k
        keyword_alproto = rule_alproto;
96
15.0k
    }
97
98
52.8k
    if (is_short && rule_alproto == ALPROTO_UNKNOWN) {
99
633
        SCLogError("rule protocol unknown, can't use shorthand notation for frame '%s'", str);
100
633
        return -1;
101
52.2k
    } else if (rule_alproto == ALPROTO_UNKNOWN) {
102
1.57k
        if (SCDetectSignatureSetAppProto(s, keyword_alproto) < 0)
103
2
            return -1;
104
50.6k
    } else if (!AppProtoEquals(rule_alproto, keyword_alproto)) {
105
63
        SCLogError("frame '%s' protocol '%s' mismatch with rule protocol '%s'", str,
106
63
                AppProtoToString(keyword_alproto), AppProtoToString(s->alproto));
107
63
        return -1;
108
63
    }
109
110
52.1k
    const char *frame_str = is_short ? str : val;
111
52.1k
    int raw_frame_type = -1;
112
52.1k
    if (is_tcp) {
113
49.8k
        if (strcmp(frame_str, "stream") == 0) {
114
2.20k
            raw_frame_type = FRAME_STREAM_TYPE;
115
47.6k
        } else {
116
47.6k
            raw_frame_type =
117
47.6k
                    AppLayerParserGetFrameIdByName(IPPROTO_TCP, keyword_alproto, frame_str);
118
47.6k
        }
119
49.8k
    }
120
52.1k
    if (is_udp && raw_frame_type < 0)
121
3.23k
        raw_frame_type = AppLayerParserGetFrameIdByName(IPPROTO_UDP, keyword_alproto, frame_str);
122
52.1k
    if (raw_frame_type < 0) {
123
10.1k
        SCLogError("unknown frame '%s' for protocol '%s'", frame_str, proto);
124
10.1k
        return -1;
125
10.1k
    }
126
42.0k
    BUG_ON(raw_frame_type > UINT8_MAX);
127
128
42.0k
    if (is_short) {
129
30.9k
        snprintf(buffer_name, sizeof(buffer_name), "%s.%s", AppProtoToString(s->alproto), str);
130
30.9k
        SCLogDebug("short name: %s", buffer_name);
131
30.9k
    } else {
132
11.1k
        strlcpy(buffer_name, str, sizeof(buffer_name));
133
11.1k
        SCLogDebug("long name: %s", buffer_name);
134
11.1k
    }
135
136
42.0k
    uint8_t frame_type = (uint8_t)raw_frame_type;
137
    /* TODO we can have TS and TC specific frames */
138
42.0k
    const int buffer_id = DetectEngineBufferTypeRegisterWithFrameEngines(de_ctx, buffer_name,
139
42.0k
            SIG_FLAG_TOSERVER | SIG_FLAG_TOCLIENT, keyword_alproto, frame_type);
140
42.0k
    if (buffer_id < 0)
141
0
        return -1;
142
143
42.0k
    if (SCDetectBufferSetActiveList(de_ctx, s, buffer_id) < 0)
144
46
        return -1;
145
146
41.9k
    FrameConfigEnable(keyword_alproto, frame_type);
147
41.9k
    return 0;
148
42.0k
}
149
150
#ifdef UNITTESTS
151
152
static int DetectFrameTestBadRules(void)
153
{
154
    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
155
    FAIL_IF_NULL(de_ctx);
156
157
    const char *sigs[] = {
158
        "alert tcp-pkt any any -> any any (frame:tls.pdu; content:\"a\"; sid:1;)",
159
        "alert udp any any -> any any (frame:tls.pdu; content:\"a\"; sid:2;)",
160
        "alert smb any any -> any any (frame:tls.pdu; content:\"a\"; sid:3;)",
161
        "alert tcp any any -> any any (frame:tls; content:\"a\"; sid:4;)",
162
        "alert tls any any -> any any (content:\"abc\"; frame:tls.pdu; content:\"a\"; sid:5;)",
163
        "alert tls any any -> any any (tls.version:1.0; frame:tls.pdu; content:\"a\"; sid:6;)",
164
        "alert tls any any -> any any (frame:smb1.pdu; content:\"a\"; sid:7;)",
165
        NULL,
166
    };
167
168
    const char **sig = sigs;
169
    while (*sig) {
170
        SCLogDebug("sig %s", *sig);
171
        Signature *s = DetectEngineAppendSig(de_ctx, *sig);
172
        FAIL_IF_NOT_NULL(s);
173
        sig++;
174
    }
175
176
    DetectEngineCtxFree(de_ctx);
177
    PASS;
178
}
179
180
static void DetectFrameRegisterTests(void)
181
{
182
    UtRegisterTest("DetectFrameTestBadRules", DetectFrameTestBadRules);
183
}
184
#endif
185
186
/**
187
 * \brief Registration function for keyword: ja3_hash
188
 */
189
void DetectFrameRegister(void)
190
73
{
191
73
    sigmatch_table[DETECT_FRAME].name = "frame";
192
73
    sigmatch_table[DETECT_FRAME].desc = "sticky buffer for inspecting app-layer frames";
193
73
    sigmatch_table[DETECT_FRAME].Setup = DetectFrameSetup;
194
73
    sigmatch_table[DETECT_FRAME].flags = SIGMATCH_INFO_STICKY_BUFFER;
195
#ifdef UNITTESTS
196
    sigmatch_table[DETECT_FRAME].RegisterTests = DetectFrameRegisterTests;
197
#endif
198
73
}