Coverage Report

Created: 2026-08-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/tests/fuzz/fuzz_sigpcap_aware.c
Line
Count
Source
1
/**
2
 * @file
3
 * @author Philippe Antoine <contact@catenacyber.fr>
4
 * fuzz target for AppLayerProtoDetectGetProto
5
 */
6
7
#include "suricata-common.h"
8
#include "source-pcap-file.h"
9
#include "detect-engine.h"
10
#include "util-classification-config.h"
11
#include "util-reference-config.h"
12
#include "app-layer.h"
13
#include "tm-queuehandlers.h"
14
#include "util-cidr.h"
15
#include "util-profiling.h"
16
#include "util-proto-name.h"
17
#include "detect-engine-tag.h"
18
#include "detect-engine-threshold.h"
19
#include "host-bit.h"
20
#include "ippair-bit.h"
21
#include "app-layer-htp.h"
22
#include "detect-fast-pattern.h"
23
#include "util-unittest-helper.h"
24
#include "conf-yaml-loader.h"
25
#include "pkt-var.h"
26
#include "flow-util.h"
27
#include "flow-worker.h"
28
#include "tm-modules.h"
29
#include "tmqh-packetpool.h"
30
#include "util-conf.h"
31
#include "packet.h"
32
33
#include <fuzz_pcap.h>
34
35
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
36
37
static int initialized = 0;
38
ThreadVars tv;
39
DecodeThreadVars *dtv;
40
// FlowWorkerThreadData
41
void *fwd;
42
SCInstance surifuzz;
43
SC_ATOMIC_EXTERN(unsigned int, engine_stage);
44
45
extern const char *configNoChecksum;
46
47
static void SigGenerateAware(const uint8_t *data, size_t size, char *r, size_t *len)
48
66.1k
{
49
66.1k
    *len = snprintf(r, 511, "alert ip any any -> any any (");
50
5.34M
    for (size_t i = 0; i + 1 < size && *len < 511; i++) {
51
5.27M
        if (data[i] & 0x80) {
52
116k
            size_t off = (data[i] & 0x7F + ((data[i + 1] & 0xF) << 7)) %
53
116k
                         (sizeof(sigmatch_table) / sizeof(SigTableElmt));
54
116k
            if (sigmatch_table[off].flags & SIGMATCH_NOOPT ||
55
71.9k
                    ((data[i + 1] & 0x80) && sigmatch_table[off].flags & SIGMATCH_OPTIONAL_OPT)) {
56
71.9k
                *len += snprintf(r + *len, 511 - *len, "; %s;", sigmatch_table[off].name);
57
71.9k
            } else {
58
44.8k
                *len += snprintf(r + *len, 511 - *len, "; %s:", sigmatch_table[off].name);
59
44.8k
            }
60
116k
            i++;
61
5.16M
        } else {
62
5.16M
            r[*len] = data[i];
63
5.16M
            *len = *len + 1;
64
5.16M
        }
65
5.27M
    }
66
66.1k
    if (*len < 511) {
67
63.3k
        *len += snprintf(r + *len, 511 - *len, ")");
68
63.3k
    } else {
69
2.78k
        r[511] = 0;
70
2.78k
        *len = 511;
71
2.78k
    }
72
66.1k
}
73
74
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
75
32.9k
{
76
32.9k
    FPC_buffer_t pkts;
77
32.9k
    const u_char *pkt;
78
32.9k
    struct pcap_pkthdr header;
79
32.9k
    int r;
80
32.9k
    Packet *p;
81
32.9k
    size_t pos;
82
32.9k
    size_t pcap_cnt = 0;
83
84
32.9k
    if (initialized == 0) {
85
        // Redirects logs to /dev/null
86
1
        setenv("SC_LOG_OP_IFACE", "file", 0);
87
1
        setenv("SC_LOG_FILE", "/dev/null", 0);
88
89
1
        InitGlobal();
90
91
1
        GlobalsInitPreConfig();
92
1
        run_mode = RUNMODE_PCAP_FILE;
93
        // redirect logs to /tmp
94
1
        ConfigSetLogDirectory("/tmp/");
95
        // disables checksums validation for fuzzing
96
1
        if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) {
97
0
            abort();
98
0
        }
99
        // do not load rules before reproducible DetectEngineReload
100
1
        remove("/tmp/fuzz.rules");
101
1
        surifuzz.sig_file = strdup("/tmp/fuzz.rules");
102
1
        surifuzz.sig_file_exclusive = 1;
103
        // loads rules after init
104
1
        surifuzz.delayed_detect = 1;
105
106
1
        PostConfLoadedSetup(&surifuzz);
107
1
        PreRunPostPrivsDropInit(run_mode);
108
1
        PostConfLoadedDetectSetup(&surifuzz);
109
110
1
        memset(&tv, 0, sizeof(tv));
111
1
        tv.flow_queue = FlowQueueNew();
112
1
        if (tv.flow_queue == NULL)
113
0
            abort();
114
1
        dtv = DecodeThreadVarsAlloc(&tv);
115
1
        DecodeRegisterPerfCounters(dtv, &tv);
116
1
        tmm_modules[TMM_FLOWWORKER].ThreadInit(&tv, NULL, &fwd);
117
1
        StatsSetupPrivate(&tv);
118
119
1
        extern uint16_t max_pending_packets;
120
1
        max_pending_packets = 128;
121
1
        PacketPoolInit();
122
1
        SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME);
123
1
        initialized = 1;
124
1
    }
125
126
32.9k
    if (size < 1 + FPC0_HEADER_LEN) {
127
2
        return 0;
128
2
    }
129
3.77M
    for (pos = 0; pos < size - FPC0_HEADER_LEN; pos++) {
130
3.77M
        if (data[pos] == 0) {
131
32.9k
            break;
132
32.9k
        }
133
3.77M
    }
134
    // initialize FPC with the buffer
135
32.9k
    if (FPC_init(&pkts, data + pos + 1, size - pos - 1) < 0) {
136
22
        return 0;
137
22
    }
138
139
    // dump signatures to a file so as to reuse SigLoadSignatures
140
32.9k
    char sigaware[512];
141
32.9k
    size_t len;
142
32.9k
    SigGenerateAware(data, pos + 1, sigaware, &len);
143
32.9k
    if (TestHelperBufferToFile(surifuzz.sig_file, (uint8_t *)sigaware, len) < 0) {
144
0
        return 0;
145
0
    }
146
147
32.9k
    if (DetectEngineReload(&surifuzz) < 0) {
148
0
        return 0;
149
0
    }
150
32.9k
    DetectEngineThreadCtx *old_det_ctx = FlowWorkerGetDetectCtxPtr(fwd);
151
152
32.9k
    DetectEngineCtx *de_ctx = DetectEngineGetCurrent();
153
32.9k
    de_ctx->ref_cnt--;
154
32.9k
    DetectEngineThreadCtx *new_det_ctx = DetectEngineThreadCtxInitForReload(&tv, de_ctx, 1);
155
32.9k
    FlowWorkerReplaceDetectCtx(fwd, new_det_ctx);
156
157
32.9k
    DetectEngineThreadCtxDeinit(NULL, old_det_ctx);
158
159
    // loop over packets
160
32.9k
    r = FPC_next(&pkts, &header, &pkt);
161
32.9k
    p = PacketGetFromAlloc();
162
32.9k
    if (r <= 0 || header.ts.tv_sec >= INT_MAX - 3600) {
163
914
        goto bail;
164
914
    }
165
32.0k
    p->pkt_src = PKT_SRC_WIRE;
166
32.0k
    p->ts = SCTIME_FROM_TIMEVAL(&header.ts);
167
32.0k
    p->datalink = pkts.datalink;
168
10.8M
    while (r > 0) {
169
10.8M
        if (PacketCopyData(p, pkt, header.caplen) == 0) {
170
            // DecodePcapFile
171
10.8M
            TmEcode ecode = tmm_modules[TMM_DECODEPCAPFILE].Func(&tv, p, dtv);
172
10.8M
            if (ecode == TM_ECODE_FAILED) {
173
0
                break;
174
0
            }
175
10.8M
            Packet *extra_p = PacketDequeueNoLock(&tv.decode_pq);
176
10.8M
            while (extra_p != NULL) {
177
11.4k
                PacketFreeOrRelease(extra_p);
178
11.4k
                extra_p = PacketDequeueNoLock(&tv.decode_pq);
179
11.4k
            }
180
10.8M
            tmm_modules[TMM_FLOWWORKER].Func(&tv, p, fwd);
181
10.8M
            extra_p = PacketDequeueNoLock(&tv.decode_pq);
182
10.8M
            while (extra_p != NULL) {
183
0
                PacketFreeOrRelease(extra_p);
184
0
                extra_p = PacketDequeueNoLock(&tv.decode_pq);
185
0
            }
186
10.8M
        }
187
10.8M
        r = FPC_next(&pkts, &header, &pkt);
188
10.8M
        if (r <= 0 || header.ts.tv_sec >= INT_MAX - 3600) {
189
32.0k
            goto bail;
190
32.0k
        }
191
10.8M
        PacketRecycle(p);
192
10.8M
        p->pkt_src = PKT_SRC_WIRE;
193
10.8M
        p->ts = SCTIME_FROM_TIMEVAL(&header.ts);
194
10.8M
        p->datalink = pkts.datalink;
195
10.8M
        pcap_cnt++;
196
10.8M
        p->pcap_cnt = pcap_cnt;
197
10.8M
    }
198
32.9k
bail:
199
32.9k
    PacketFree(p);
200
32.9k
    FlowReset();
201
202
32.9k
    return 0;
203
32.0k
}