1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
/**
* @file
* @author Philippe Antoine <contact@catenacyber.fr>
* fuzz target for AppLayerProtoDetectGetProto
*/
#include "suricata-common.h"
#include "suricata.h"
#include "app-layer-detect-proto.h"
#include "flow-util.h"
#include "app-layer-parser.h"
#include "util-unittest-helper.h"
#include "conf-yaml-loader.h"
#define HEADER_LEN 6
//rule of thumb constant, so as not to timeout target
#define PROTO_DETECT_MAX_LEN 1024
#include "confyaml.c"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
AppLayerProtoDetectThreadCtx *alpd_tctx = NULL;
SC_ATOMIC_EXTERN(unsigned int, engine_stage);
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
Flow *f;
TcpSession ssn;
bool reverse;
AppProto alproto;
AppProto alproto2;
if (alpd_tctx == NULL) {
//global init
InitGlobal();
run_mode = RUNMODE_UNITTEST;
if (ConfYamlLoadString(configNoChecksum, strlen(configNoChecksum)) != 0) {
abort();
}
MpmTableSetup();
SpmTableSetup();
EngineModeSetIDS();
AppLayerProtoDetectSetup();
AppLayerParserSetup();
AppLayerParserRegisterProtocolParsers();
alpd_tctx = AppLayerProtoDetectGetCtxThread();
SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME);
}
if (size < HEADER_LEN) {
return 0;
}
f = TestHelperBuildFlow(AF_INET, "1.2.3.4", "5.6.7.8", (uint16_t)((data[2] << 8) | data[3]),
(uint16_t)((data[4] << 8) | data[5]));
if (f == NULL) {
return 0;
}
f->proto = data[1];
memset(&ssn, 0, sizeof(TcpSession));
f->protoctx = &ssn;
f->protomap = FlowGetProtoMapping(f->proto);
uint8_t flags = STREAM_TOCLIENT;
if (data[0] & STREAM_TOSERVER) {
flags = STREAM_TOSERVER;
}
alproto = AppLayerProtoDetectGetProto(
alpd_tctx, f, data + HEADER_LEN, size - HEADER_LEN, f->proto, flags, &reverse);
if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED && f->proto == IPPROTO_TCP) {
/* If we find a valid protocol at the start of a stream :
* check that with smaller input
* we find the same protocol or ALPROTO_UNKNOWN.
* Otherwise, we have evasion with TCP splitting
*/
for (size_t i = 0; i < size-HEADER_LEN && i < PROTO_DETECT_MAX_LEN; i++) {
// reset detection at each try cf probing_parser_toserver_alproto_masks
AppLayerProtoDetectReset(f);
alproto2 = AppLayerProtoDetectGetProto(
alpd_tctx, f, data + HEADER_LEN, i, f->proto, flags, &reverse);
if (alproto2 != ALPROTO_UNKNOWN && alproto2 != alproto) {
printf("Failed with input length %" PRIuMAX " versus %" PRIuMAX
", found %s instead of %s\n",
(uintmax_t)i, (uintmax_t)size - HEADER_LEN, AppProtoToString(alproto2),
AppProtoToString(alproto));
printf("Assertion failure: %s-%s\n", AppProtoToString(alproto2),
AppProtoToString(alproto));
fflush(stdout);
abort();
}
}
}
FlowFree(f);
return 0;
}
|