From: DIALLO David Date: Thu, 30 Apr 2015 17:02:56 +0000 (+0200) Subject: app-layer-modbus: fix deadlock in parsers X-Git-Tag: suricata-2.1beta4~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F1441%2Fhead;p=thirdparty%2Fsuricata.git app-layer-modbus: fix deadlock in parsers --- diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 6442b821e9..31982eadfe 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1175,18 +1175,19 @@ static int ModbusParseRequest(Flow *f, ModbusHeader header; while (input_len > 0) { - uint16_t adu_len, offset = 0; + uint32_t adu_len; + uint16_t offset = 0; uint8_t *ptr = input; /* Modbus header is 7 bytes long */ - if (input_len < sizeof(ModbusHeader)) + if (input_len < (uint32_t) sizeof(ModbusHeader)) SCReturnInt(0); /* Extract MODBUS Header */ ModbusParseHeader(&header, ptr, &offset); /* Compute ADU length. */ - adu_len = sizeof(ModbusHeader) + header.length - 1; + adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; if (adu_len > input_len) SCReturnInt(0); @@ -1235,18 +1236,19 @@ static int ModbusParseResponse(Flow *f, ModbusTransaction *tx; while (input_len > 0) { - uint16_t adu_len, offset = 0; + uint32_t adu_len; + uint16_t offset = 0; uint8_t *ptr = input; /* Modbus header is 7 bytes long */ - if (input_len < sizeof(ModbusHeader)) + if (input_len < (uint32_t) sizeof(ModbusHeader)) SCReturnInt(0); /* Extract MODBUS Header */ ModbusParseHeader(&header, ptr, &offset); /* Compute ADU length */ - adu_len = sizeof(ModbusHeader) + header.length - 1; + adu_len = (uint32_t) sizeof(ModbusHeader) + (uint32_t) header.length - 1; if (adu_len > input_len) SCReturnInt(0); @@ -1553,6 +1555,16 @@ static uint8_t invalidLengthWriteMultipleRegistersReq[] = { /* Registers Value */ 0x00, 0x0A, 0x01, 0x02}; +static uint8_t exceededLengthWriteMultipleRegistersReq[] = { + /* Transaction ID */ 0x00, 0x0A, + /* Protocol ID */ 0x00, 0x00, + /* Length */ 0xff, 0xfa, + /* Unit ID */ 0x00, + /* Function code */ 0x10, + /* Starting Address */ 0x00, 0x01, + /* Quantity of Registers */ 0x7f, 0xf9, + /* Byte count */ 0xff}; + /** \test Send Modbus Read Coils request/response. */ static int ModbusParserTest01(void) { AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); @@ -2401,6 +2413,93 @@ end: FLOW_DESTROY(&f); return result; } + +/** \test Send Modbus exceed Length request. */ +static int ModbusParserTest11(void) { + AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); + DetectEngineThreadCtx *det_ctx = NULL; + Flow f; + Packet *p = NULL; + Signature *s = NULL; + TcpSession ssn; + ThreadVars tv; + + int result = 0; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&f, 0, sizeof(Flow)); + memset(&ssn, 0, sizeof(TcpSession)); + + p = UTHBuildPacket(NULL, 0, IPPROTO_TCP); + + FLOW_INITIALIZE(&f); + f.alproto = ALPROTO_MODBUS; + f.protoctx = (void *)&ssn; + f.proto = IPPROTO_TCP; + f.flags |= FLOW_IPV4; + + p->flow = &f; + p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST; + p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED; + + StreamTcpInitConfig(TRUE); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) + goto end; + + de_ctx->flags |= DE_QUIET; + s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any " + "(msg:\"Modbus invalid Length\"; " + "app-layer-event: " + "modbus.invalid_length; " + "sid:1;)"); + if (s == NULL) + goto end; + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f.m); + int r = AppLayerParserParse(alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, + exceededLengthWriteMultipleRegistersReq, + sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 /* header.length - 7 */ * sizeof(uint8_t)); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f.m); + goto end; + } + SCMutexUnlock(&f.m); + + ModbusState *modbus_state = f.alstate; + if (modbus_state == NULL) { + printf("no modbus state: "); + goto end; + } + + /* do detect */ + SigMatchSignatures(&tv, de_ctx, det_ctx, p); + + if (!PacketAlertCheck(p, 1)) { + printf("sid 1 didn't match. Should have matched: "); + goto end; + } + + result = 1; +end: + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + if (alp_tctx != NULL) + AppLayerParserThreadCtxFree(alp_tctx); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + UTHFreePackets(&p, 1); + return result; +} #endif /* UNITTESTS */ void ModbusParserRegisterTests(void) { @@ -2415,5 +2514,6 @@ void ModbusParserRegisterTests(void) { UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid", ModbusParserTest08, 1); UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets", ModbusParserTest09, 1); UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet", ModbusParserTest10, 1); + UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request", ModbusParserTest11, 1); #endif /* UNITTESTS */ }