diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index 852afa7c85..b7d4042544 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -293,8 +293,11 @@ static void DNSTransactionFree(DNSTransaction *tx, DNSState *state) AppLayerDecoderEventsFreeEvents(&tx->decoder_events); - if (tx->de_state != NULL) + if (tx->de_state != NULL) { DetectEngineStateFree(tx->de_state); + BUG_ON(state->tx_with_detect_state_cnt == 0); + state->tx_with_detect_state_cnt--; + } if (state->iter == tx) state->iter = NULL; @@ -366,15 +369,23 @@ DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16 return NULL; } +int DNSStateHasTxDetectState(void *alstate) +{ + DNSState *state = (DNSState *)alstate; + return (state->tx_with_detect_state_cnt > 0); +} + DetectEngineState *DNSGetTxDetectState(void *vtx) { DNSTransaction *tx = (DNSTransaction *)vtx; return tx->de_state; } -int DNSSetTxDetectState(void *vtx, DetectEngineState *s) +int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s) { + DNSState *state = (DNSState *)alstate; DNSTransaction *tx = (DNSTransaction *)vtx; + state->tx_with_detect_state_cnt++; tx->de_state = s; return 0; } @@ -413,6 +424,8 @@ void DNSStateFree(void *s) SCFree(dns_state->buffer); } + BUG_ON(dns_state->tx_with_detect_state_cnt > 0); + DNSDecrMemcap(sizeof(DNSState), dns_state); BUG_ON(dns_state->memuse > 0); SCFree(s); diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 1564fec986..1a06f8d1dc 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -181,6 +181,8 @@ typedef struct DNSState_ { uint32_t unreplied_cnt; /**< number of unreplied requests in a row */ uint32_t memuse; /**< state memuse, for comparing with state-memcap settings */ + uint64_t tx_with_detect_state_cnt; + uint16_t events; uint16_t givenup; @@ -221,8 +223,9 @@ int DNSGetAlstateProgressCompletionStatus(uint8_t direction); void DNSStateTransactionFree(void *state, uint64_t tx_id); DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id); +int DNSStateHasTxDetectState(void *alstate); DetectEngineState *DNSGetTxDetectState(void *vtx); -int DNSSetTxDetectState(void *vtx, DetectEngineState *s); +int DNSSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s); void DNSSetEvent(DNSState *s, uint8_t e); void *DNSStateAlloc(void); diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index 36b8848aeb..0842c6686e 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -647,6 +647,7 @@ void RegisterDNSTCPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSHasEvents); AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS, + DNSStateHasTxDetectState, DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx); diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 1917914b1b..bb0c73bf55 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -403,6 +403,7 @@ void RegisterDNSUDPParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSHasEvents); AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS, + DNSStateHasTxDetectState, DNSGetTxDetectState, DNSSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS, diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 8ae86fe1b4..2ded474ed9 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -310,9 +310,9 @@ error: SCReturnPtr(NULL, "void"); } -static void HtpTxUserDataFree(HtpTxUserData *htud) +static void HtpTxUserDataFree(HtpState *state, HtpTxUserData *htud) { - if (htud) { + if (likely(htud)) { HtpBodyFree(&htud->request_body); HtpBodyFree(&htud->response_body); bstr_free(htud->request_uri_normalized); @@ -324,6 +324,11 @@ static void HtpTxUserDataFree(HtpTxUserData *htud) if (htud->boundary) HTPFree(htud->boundary, htud->boundary_len); if (htud->de_state != NULL) { + if (likely(state != NULL)) { // should be impossible that it's null + BUG_ON(state->tx_with_detect_state_cnt == 0); + state->tx_with_detect_state_cnt--; + } + DetectEngineStateFree(htud->de_state); } HTPFree(htud, sizeof(HtpTxUserData)); @@ -357,15 +362,14 @@ void HTPStateFree(void *state) htp_tx_t *tx = HTPStateGetTx(s, tx_id); if (tx != NULL) { HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - HtpTxUserDataFree(htud); - htp_tx_set_user_data(tx, NULL); - } + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); } } } htp_connp_destroy_all(s->connp); } + BUG_ON(s->tx_with_detect_state_cnt > 0); FileContainerFree(s->files_ts); FileContainerFree(s->files_tc); @@ -400,10 +404,8 @@ static void HTPStateTransactionFree(void *state, uint64_t id) if (tx != NULL) { /* This will remove obsolete body chunks */ HtpTxUserData *htud = (HtpTxUserData *) htp_tx_get_user_data(tx); - if (htud != NULL) { - HtpTxUserDataFree(htud); - htp_tx_set_user_data(tx, NULL); - } + HtpTxUserDataFree(s, htud); + htp_tx_set_user_data(tx, NULL); htp_tx_destroy(tx); } @@ -2109,10 +2111,9 @@ static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data) tx_ud->request_headers_raw_len, tx_ud->request_headers_raw_len + tx_data->len); if (ptmp == NULL) { - HTPFree(tx_ud->request_headers_raw, tx_ud->request_headers_raw_len); - tx_ud->request_headers_raw = NULL; - tx_ud->request_headers_raw_len = 0; - HtpTxUserDataFree(tx_ud); + /* error: we're freeing the entire user data */ + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HtpTxUserDataFree(hstate, tx_ud); htp_tx_set_user_data(tx_data->tx, NULL); return HTP_OK; } @@ -2147,10 +2148,9 @@ static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data) tx_ud->response_headers_raw_len, tx_ud->response_headers_raw_len + tx_data->len); if (ptmp == NULL) { - HTPFree(tx_ud->response_headers_raw, tx_ud->response_headers_raw_len); - tx_ud->response_headers_raw = NULL; - tx_ud->response_headers_raw_len = 0; - HtpTxUserDataFree(tx_ud); + /* error: we're freeing the entire user data */ + HtpState *hstate = htp_connp_get_user_data(tx_data->tx->connp); + HtpTxUserDataFree(hstate, tx_ud); htp_tx_set_user_data(tx_data->tx, NULL); return HTP_OK; } @@ -2635,6 +2635,12 @@ static void HTPStateTruncate(void *state, uint8_t direction) } } +static int HTPStateHasTxDetectState(void *alstate) +{ + HtpState *htp_state = (HtpState *)alstate; + return (htp_state->tx_with_detect_state_cnt > 0); +} + static DetectEngineState *HTPGetTxDetectState(void *vtx) { htp_tx_t *tx = (htp_tx_t *)vtx; @@ -2642,8 +2648,9 @@ static DetectEngineState *HTPGetTxDetectState(void *vtx) return tx_ud ? tx_ud->de_state : NULL; } -static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) +static int HTPSetTxDetectState(void *alstate, void *vtx, DetectEngineState *s) { + HtpState *htp_state = (HtpState *)alstate; htp_tx_t *tx = (htp_tx_t *)vtx; HtpTxUserData *tx_ud = htp_tx_get_user_data(tx); if (tx_ud == NULL) { @@ -2653,6 +2660,7 @@ static int HTPSetTxDetectState(void *vtx, DetectEngineState *s) memset(tx_ud, 0, sizeof(*tx_ud)); htp_tx_set_user_data(tx, tx_ud); } + htp_state->tx_with_detect_state_cnt++; tx_ud->de_state = s; return 0; } @@ -2741,6 +2749,7 @@ void RegisterHTPParsers(void) AppLayerParserRegisterTruncateFunc(IPPROTO_TCP, ALPROTO_HTTP, HTPStateTruncate); AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_HTTP, + HTPStateHasTxDetectState, HTPGetTxDetectState, HTPSetTxDetectState); AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_HTTP, STREAM_TOSERVER, diff --git a/src/app-layer-htp.h b/src/app-layer-htp.h index 869d2bfc22..50b95d66d1 100644 --- a/src/app-layer-htp.h +++ b/src/app-layer-htp.h @@ -248,6 +248,7 @@ typedef struct HtpState_ { uint16_t flags; uint16_t events; uint16_t htp_messages_offset; /**< offset into conn->messages list */ + uint64_t tx_with_detect_state_cnt; } HtpState; /** part of the engine needs the request body (e.g. http_client_body keyword) */ diff --git a/src/app-layer-modbus.c b/src/app-layer-modbus.c index 31982eadfe..93b834b4b3 100644 --- a/src/app-layer-modbus.c +++ b/src/app-layer-modbus.c @@ -1343,7 +1343,7 @@ DetectEngineState *ModbusGetTxDetectState(void *vtx) return tx->de_state; } -int ModbusSetTxDetectState(void *vtx, DetectEngineState *s) +int ModbusSetTxDetectState(void *state, void *vtx, DetectEngineState *s) { ModbusTransaction *tx = (ModbusTransaction *)vtx; tx->de_state = s; @@ -1410,7 +1410,7 @@ void RegisterModbusParsers(void) AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetEvents); AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_MODBUS, ModbusHasEvents); - AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_MODBUS, NULL, ModbusGetTxDetectState, ModbusSetTxDetectState); AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_MODBUS, ModbusGetTx); diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 42ad4e1edd..289a59d7cd 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -106,8 +106,9 @@ typedef struct AppLayerParserProtoCtx_ int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type); + int (*StateHasTxDetectState)(void *alstate); DetectEngineState *(*GetTxDetectState)(void *tx); - int (*SetTxDetectState)(void *tx, DetectEngineState *); + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *); /* Indicates the direction the parser is ready to see the data * the first time for a flow. Values accepted - @@ -472,11 +473,13 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, } void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + int (*StateHasTxDetectState)(void *alstate), DetectEngineState *(*GetTxDetectState)(void *tx), - int (*SetTxDetectState)(void *tx, DetectEngineState *)) + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)) { SCEnter(); + alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState = StateHasTxDetectState; alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState = GetTxDetectState; alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState = SetTxDetectState; @@ -804,6 +807,16 @@ int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto) return FALSE; } +int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate) +{ + int r; + SCEnter(); + if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState == NULL) + return -ENOSYS; + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].StateHasTxDetectState(alstate); + SCReturnInt(r); +} + DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx) { SCEnter(); @@ -812,13 +825,14 @@ DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alpr SCReturnPtr(s, "DetectEngineState"); } -int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s) +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, + void *alstate, void *tx, DetectEngineState *s) { int r; SCEnter(); if ((alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx) != NULL)) SCReturnInt(-EBUSY); - r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(tx, s); + r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].SetTxDetectState(alstate, tx, s); SCReturnInt(r); } diff --git a/src/app-layer-parser.h b/src/app-layer-parser.h index 44f27b76c8..b81459b766 100644 --- a/src/app-layer-parser.h +++ b/src/app-layer-parser.h @@ -143,8 +143,9 @@ void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int (*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type)); void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, + int (*StateHasTxDetectState)(void *alstate), DetectEngineState *(*GetTxDetectState)(void *tx), - int (*SetTxDetectState)(void *tx, DetectEngineState *)); + int (*SetTxDetectState)(void *alstate, void *tx, DetectEngineState *)); /***** Get and transaction functions *****/ @@ -180,8 +181,9 @@ uint64_t AppLayerParserGetTransactionActive(uint8_t ipproto, AppProto alproto, A uint8_t AppLayerParserGetFirstDataDir(uint8_t ipproto, AppProto alproto); int AppLayerParserSupportsTxDetectState(uint8_t ipproto, AppProto alproto); +int AppLayerParserHasTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate); DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx); -int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx, DetectEngineState *s); +int AppLayerParserSetTxDetectState(uint8_t ipproto, AppProto alproto, void *alstate, void *tx, DetectEngineState *s); /***** General *****/ diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index e03cad8947..c0772ec75a 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1381,7 +1381,7 @@ static DetectEngineState *SMTPGetTxDetectState(void *vtx) return tx->de_state; } -static int SMTPSetTxDetectState(void *vtx, DetectEngineState *s) +static int SMTPSetTxDetectState(void *state, void *vtx, DetectEngineState *s) { SMTPTransaction *tx = (SMTPTransaction *)vtx; tx->de_state = s; @@ -1415,7 +1415,7 @@ void RegisterSMTPParsers(void) AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo); AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetEvents); - AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, + AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, NULL, SMTPGetTxDetectState, SMTPSetTxDetectState); AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc, diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 150f492136..37a63f5c7f 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -335,6 +335,14 @@ static int HasStoredSigs(Flow *f, uint8_t flags) return 0; } + int state = AppLayerParserHasTxDetectState(f->proto, alproto, f->alstate); + if (state == -ENOSYS) { /* proto doesn't support this API call */ + /* fall through */ + } else if (state == 0) { + return 0; + } + /* if state == 1 we also fall through */ + uint64_t inspect_tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags); uint64_t total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate); @@ -423,7 +431,7 @@ static void StoreStateTxFileOnly(DetectEngineThreadCtx *det_ctx, destate = DetectEngineStateAlloc(); if (destate == NULL) return; - if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) { + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { DetectEngineStateFree(destate); BUG_ON(1); return; @@ -449,7 +457,7 @@ static void StoreStateTx(DetectEngineThreadCtx *det_ctx, destate = DetectEngineStateAlloc(); if (destate == NULL) return; - if (AppLayerParserSetTxDetectState(f->proto, f->alproto, tx, destate) < 0) { + if (AppLayerParserSetTxDetectState(f->proto, f->alproto, f->alstate, tx, destate) < 0) { DetectEngineStateFree(destate); BUG_ON(1); return;