Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-app-layer-event.c
Line
Count
Source
1
/* Copyright (C) 2007-2023 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22
 */
23
24
#include "suricata-common.h"
25
#include "threads.h"
26
#include "decode.h"
27
28
#include "app-layer.h"
29
#include "app-layer-protos.h"
30
#include "app-layer-parser.h"
31
#include "app-layer-smtp.h"
32
#include "detect.h"
33
#include "detect-parse.h"
34
#include "detect-engine.h"
35
#include "detect-engine-state.h"
36
#include "detect-engine-build.h"
37
#include "detect-app-layer-event.h"
38
39
#include "flow.h"
40
#include "flow-var.h"
41
#include "flow-util.h"
42
43
#include "decode-events.h"
44
#include "util-byte.h"
45
#include "util-debug.h"
46
#include "util-enum.h"
47
#include "util-profiling.h"
48
#include "util-unittest.h"
49
#include "util-unittest-helper.h"
50
#include "stream-tcp-util.h"
51
52
5.64k
#define MAX_ALPROTO_NAME 50
53
54
typedef struct DetectAppLayerEventData_ {
55
    AppProto alproto;
56
    uint8_t event_id;
57
} DetectAppLayerEventData;
58
59
static int DetectAppLayerEventPktMatch(DetectEngineThreadCtx *det_ctx,
60
                                       Packet *p, const Signature *s, const SigMatchCtx *ctx);
61
static int DetectAppLayerEventSetup(DetectEngineCtx *, Signature *, const char *);
62
static void DetectAppLayerEventFree(DetectEngineCtx *, void *);
63
static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
64
        const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
65
        uint8_t flags, void *alstate, void *tx, uint64_t tx_id);
66
static int g_applayer_events_list_id = 0;
67
68
/**
69
 * \brief Registers the keyword handlers for the "app-layer-event" keyword.
70
 */
71
void DetectAppLayerEventRegister(void)
72
73
{
73
73
    sigmatch_table[DETECT_AL_APP_LAYER_EVENT].name = "app-layer-event";
74
73
    sigmatch_table[DETECT_AL_APP_LAYER_EVENT].desc = "match on events generated by the App Layer Parsers and the protocol detection engine";
75
73
    sigmatch_table[DETECT_AL_APP_LAYER_EVENT].url = "/rules/app-layer.html#app-layer-event";
76
73
    sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Match =
77
73
        DetectAppLayerEventPktMatch;
78
73
    sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Setup = DetectAppLayerEventSetup;
79
73
    sigmatch_table[DETECT_AL_APP_LAYER_EVENT].Free = DetectAppLayerEventFree;
80
81
73
    DetectAppLayerInspectEngineRegister2("app-layer-events", ALPROTO_UNKNOWN, SIG_FLAG_TOSERVER, 0,
82
73
            DetectEngineAptEventInspect, NULL);
83
73
    DetectAppLayerInspectEngineRegister2("app-layer-events", ALPROTO_UNKNOWN, SIG_FLAG_TOCLIENT, 0,
84
73
            DetectEngineAptEventInspect, NULL);
85
86
73
    g_applayer_events_list_id = DetectBufferTypeGetByName("app-layer-events");
87
73
}
88
89
static uint8_t DetectEngineAptEventInspect(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
90
        const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
91
        uint8_t flags, void *alstate, void *tx, uint64_t tx_id)
92
50.3k
{
93
50.3k
    int r = 0;
94
50.3k
    const AppProto alproto = f->alproto;
95
50.3k
    AppLayerDecoderEvents *decoder_events =
96
50.3k
        AppLayerParserGetEventsByTx(f->proto, alproto, tx);
97
50.3k
    if (decoder_events == NULL) {
98
41.4k
        goto end;
99
41.4k
    }
100
8.84k
    SigMatchData *smd = engine->smd;
101
8.84k
    while (1) {
102
8.84k
        DetectAppLayerEventData *aled = (DetectAppLayerEventData *)smd->ctx;
103
8.84k
        KEYWORD_PROFILING_START;
104
105
8.84k
        if (AppLayerDecoderEventsIsEventSet(decoder_events, aled->event_id)) {
106
528
            KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
107
108
528
            if (smd->is_last)
109
528
                break;
110
0
            smd++;
111
0
            continue;
112
528
        }
113
114
8.31k
        KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
115
8.31k
        goto end;
116
8.84k
    }
117
118
528
    r = 1;
119
120
50.3k
 end:
121
50.3k
    if (r == 1) {
122
528
        return DETECT_ENGINE_INSPECT_SIG_MATCH;
123
49.7k
    } else {
124
49.7k
        if (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) ==
125
49.7k
            AppLayerParserGetStateProgressCompletionStatus(alproto, flags))
126
34.1k
        {
127
34.1k
            return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
128
34.1k
        } else {
129
15.6k
            return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
130
15.6k
        }
131
49.7k
    }
132
50.3k
}
133
134
135
static int DetectAppLayerEventPktMatch(DetectEngineThreadCtx *det_ctx,
136
                                Packet *p, const Signature *s, const SigMatchCtx *ctx)
137
36.4k
{
138
36.4k
    const DetectAppLayerEventData *aled = (const DetectAppLayerEventData *)ctx;
139
140
36.4k
    return AppLayerDecoderEventsIsEventSet(p->app_layer_events,
141
36.4k
                                           aled->event_id);
142
36.4k
}
143
144
static DetectAppLayerEventData *DetectAppLayerEventParsePkt(const char *arg,
145
                                                            AppLayerEventType *event_type)
146
843
{
147
843
    int event_id = 0;
148
843
    int r = AppLayerGetPktEventInfo(arg, &event_id);
149
843
    if (r < 0 || r > UINT8_MAX) {
150
213
        SCLogError("app-layer-event keyword "
151
213
                   "supplied with packet based event - \"%s\" that isn't "
152
213
                   "supported yet.",
153
213
                arg);
154
213
        return NULL;
155
213
    }
156
157
630
    DetectAppLayerEventData *aled = SCCalloc(1, sizeof(DetectAppLayerEventData));
158
630
    if (unlikely(aled == NULL))
159
0
        return NULL;
160
630
    aled->event_id = (uint8_t)event_id;
161
630
    *event_type = APP_LAYER_EVENT_TYPE_PACKET;
162
163
630
    return aled;
164
630
}
165
166
static bool OutdatedEvent(const char *raw)
167
93.6k
{
168
93.6k
    if (strcmp(raw, "tls.certificate_missing_element") == 0 ||
169
93.0k
            strcmp(raw, "tls.certificate_unknown_element") == 0 ||
170
92.4k
            strcmp(raw, "tls.certificate_invalid_string") == 0) {
171
1.91k
        return true;
172
1.91k
    }
173
91.7k
    return false;
174
93.6k
}
175
176
static AppProto AppLayerEventGetProtoByName(char *alproto_name)
177
95.6k
{
178
95.6k
    AppProto alproto = AppLayerGetProtoByName(alproto_name);
179
95.6k
    if (alproto == ALPROTO_HTTP) {
180
        // app-layer events http refer to http1
181
10.9k
        alproto = ALPROTO_HTTP1;
182
10.9k
    }
183
95.6k
    return alproto;
184
95.6k
}
185
186
static int DetectAppLayerEventSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
187
6.48k
{
188
6.48k
    if (arg == NULL) {
189
0
        SCLogError("app-layer-event keyword supplied "
190
0
                   "with no arguments.  This keyword needs an argument.");
191
0
        return -1;
192
0
    }
193
194
7.51k
    while (*arg != '\0' && isspace((unsigned char)*arg))
195
1.02k
        arg++;
196
197
6.48k
    AppLayerEventType event_type;
198
6.48k
    DetectAppLayerEventData *data = NULL;
199
200
6.48k
    if (strchr(arg, '.') == NULL) {
201
843
        data = DetectAppLayerEventParsePkt(arg, &event_type);
202
843
        if (data == NULL)
203
213
            return -1;
204
5.64k
    } else {
205
5.64k
        SCLogDebug("parsing %s", arg);
206
5.64k
        char alproto_name[MAX_ALPROTO_NAME];
207
5.64k
        bool needs_detctx = false;
208
209
5.64k
        const char *p_idx = strchr(arg, '.');
210
5.64k
        if (strlen(arg) > MAX_ALPROTO_NAME) {
211
35
            SCLogError("app-layer-event keyword is too long or malformed");
212
35
            return -1;
213
35
        }
214
5.61k
        const char *event_name = p_idx + 1; // skip .
215
        /* + 1 for trailing \0 */
216
5.61k
        strlcpy(alproto_name, arg, p_idx - arg + 1);
217
218
5.61k
        const AppProto alproto = AppLayerEventGetProtoByName(alproto_name);
219
5.61k
        if (alproto == ALPROTO_UNKNOWN) {
220
270
            if (!strcmp(alproto_name, "file")) {
221
2
                needs_detctx = true;
222
268
            } else {
223
268
                SCLogError("app-layer-event keyword "
224
268
                           "supplied with unknown protocol \"%s\"",
225
268
                        alproto_name);
226
268
                return -1;
227
268
            }
228
270
        }
229
5.34k
        if (OutdatedEvent(arg)) {
230
176
            if (SigMatchStrictEnabled(DETECT_AL_APP_LAYER_EVENT)) {
231
0
                SCLogError("app-layer-event keyword no longer supports event \"%s\"", arg);
232
0
                return -1;
233
176
            } else {
234
176
                SCLogWarning("app-layer-event keyword no longer supports event \"%s\"", arg);
235
176
                return -3;
236
176
            }
237
176
        }
238
239
5.16k
        uint8_t ipproto = 0;
240
5.16k
        if (s->proto.proto[IPPROTO_TCP / 8] & 1 << (IPPROTO_TCP % 8)) {
241
4.91k
            ipproto = IPPROTO_TCP;
242
4.91k
        } else if (s->proto.proto[IPPROTO_UDP / 8] & 1 << (IPPROTO_UDP % 8)) {
243
252
            ipproto = IPPROTO_UDP;
244
252
        } else {
245
1
            SCLogError("protocol %s is disabled", alproto_name);
246
1
            return -1;
247
1
        }
248
249
5.16k
        int r;
250
5.16k
        int event_id = 0;
251
5.16k
        if (!needs_detctx) {
252
5.16k
            r = AppLayerParserGetEventInfo(ipproto, alproto, event_name, &event_id, &event_type);
253
5.16k
        } else {
254
2
            r = DetectEngineGetEventInfo(event_name, &event_id, &event_type);
255
2
        }
256
5.16k
        if (r < 0) {
257
1.62k
            if (SigMatchStrictEnabled(DETECT_AL_APP_LAYER_EVENT)) {
258
0
                SCLogError("app-layer-event keyword's "
259
0
                           "protocol \"%s\" doesn't have event \"%s\" registered",
260
0
                        alproto_name, event_name);
261
0
                return -1;
262
1.62k
            } else {
263
1.62k
                SCLogWarning("app-layer-event keyword's "
264
1.62k
                             "protocol \"%s\" doesn't have event \"%s\" registered",
265
1.62k
                        alproto_name, event_name);
266
1.62k
                return -3;
267
1.62k
            }
268
1.62k
        }
269
3.54k
        if (event_id > UINT8_MAX) {
270
0
            SCLogWarning("app-layer-event keyword's id has invalid value");
271
0
            return -4;
272
0
        }
273
3.54k
        data = SCCalloc(1, sizeof(*data));
274
3.54k
        if (unlikely(data == NULL))
275
0
            return -1;
276
3.54k
        data->alproto = alproto;
277
3.54k
        data->event_id = (uint8_t)event_id;
278
3.54k
    }
279
4.17k
    SCLogDebug("data->event_id %u", data->event_id);
280
281
4.17k
    SigMatch *sm = SigMatchAlloc();
282
4.17k
    if (sm == NULL)
283
0
        goto error;
284
285
4.17k
    sm->type = DETECT_AL_APP_LAYER_EVENT;
286
4.17k
    sm->ctx = (SigMatchCtx *)data;
287
288
4.17k
    if (event_type == APP_LAYER_EVENT_TYPE_PACKET) {
289
630
        SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
290
3.54k
    } else {
291
3.54k
        if (DetectSignatureSetAppProto(s, data->alproto) != 0)
292
16
            goto error;
293
294
3.52k
        SigMatchAppendSMToList(s, sm, g_applayer_events_list_id);
295
3.52k
        s->flags |= SIG_FLAG_APPLAYER;
296
3.52k
    }
297
298
4.15k
    return 0;
299
300
16
error:
301
16
    if (data) {
302
16
        DetectAppLayerEventFree(de_ctx, data);
303
16
    }
304
16
    if (sm) {
305
16
        sm->ctx = NULL;
306
16
        SigMatchFree(de_ctx, sm);
307
16
    }
308
16
    return -1;
309
4.17k
}
310
311
static void DetectAppLayerEventFree(DetectEngineCtx *de_ctx, void *ptr)
312
80.8k
{
313
80.8k
    SCFree(ptr);
314
80.8k
}