/** * @file * @author Philippe Antoine * 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; }