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