diff --git a/src/detect-content.c b/src/detect-content.c index e3d1cb478e..d22fbc8f89 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -501,194 +501,190 @@ bool DetectContentPMATCHValidateCallback(const Signature *s) * cannot set a depth, but we can set an offset of 'offset:1;'. This will * make the mpm a bit more precise. */ -void DetectContentPropagateLimits(Signature *s) +static void PropagateLimits(Signature *s, SigMatch *sm_head) { #define VALIDATE(e) \ if (!(e)) { \ return; \ } - BUG_ON(s == NULL || s->init_data == NULL); - - uint32_t list = 0; - for (list = 0; list < s->init_data->smlists_array_size; list++) { - uint16_t offset = 0; - uint16_t offset_plus_pat = 0; - uint16_t depth = 0; - bool has_active_depth_chain = false; - - bool has_depth = false; - bool has_ends_with = false; - uint16_t ends_with_depth = 0; - - SigMatch *sm = s->init_data->smlists[list]; - for ( ; sm != NULL; sm = sm->next) { - switch (sm->type) { - case DETECT_CONTENT: { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if ((cd->flags & (DETECT_CONTENT_DEPTH|DETECT_CONTENT_OFFSET|DETECT_CONTENT_WITHIN|DETECT_CONTENT_DISTANCE)) == 0) { - offset = depth = 0; - offset_plus_pat = cd->content_len; - SCLogDebug("reset"); - has_active_depth_chain = false; - continue; - } - if (cd->flags & DETECT_CONTENT_NEGATED) { - offset = depth = 0; - offset_plus_pat = 0; - SCLogDebug("reset because of negation"); - has_active_depth_chain = false; - continue; - } + uint16_t offset = 0; + uint16_t offset_plus_pat = 0; + uint16_t depth = 0; + bool has_active_depth_chain = false; + + bool has_depth = false; + bool has_ends_with = false; + uint16_t ends_with_depth = 0; + + for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_CONTENT: { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET | + DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) == 0) { + offset = depth = 0; + offset_plus_pat = cd->content_len; + SCLogDebug("reset"); + has_active_depth_chain = false; + continue; + } + if (cd->flags & DETECT_CONTENT_NEGATED) { + offset = depth = 0; + offset_plus_pat = 0; + SCLogDebug("reset because of negation"); + has_active_depth_chain = false; + continue; + } - if (cd->depth) { - has_depth = true; - has_active_depth_chain = true; - } + if (cd->depth) { + has_depth = true; + has_active_depth_chain = true; + } - SCLogDebug("sm %p depth %u offset %u distance %d within %d", sm, cd->depth, cd->offset, cd->distance, cd->within); - SCLogDebug("stored: offset %u depth %u offset_plus_pat %u", offset, depth, offset_plus_pat); + SCLogDebug("sm %p depth %u offset %u distance %d within %d", sm, cd->depth, + cd->offset, cd->distance, cd->within); + SCLogDebug("stored: offset %u depth %u offset_plus_pat %u", offset, depth, + offset_plus_pat); - if ((cd->flags & (DETECT_DEPTH | DETECT_CONTENT_WITHIN)) == 0) { - if (depth) - SCLogDebug("no within, reset depth"); - depth = 0; - has_active_depth_chain = false; - } - if ((cd->flags & DETECT_CONTENT_DISTANCE) == 0) { - if (offset_plus_pat) - SCLogDebug("no distance, reset offset_plus_pat & offset"); - offset_plus_pat = offset = 0; - } + if ((cd->flags & (DETECT_DEPTH | DETECT_CONTENT_WITHIN)) == 0) { + if (depth) + SCLogDebug("no within, reset depth"); + depth = 0; + has_active_depth_chain = false; + } + if ((cd->flags & DETECT_CONTENT_DISTANCE) == 0) { + if (offset_plus_pat) + SCLogDebug("no distance, reset offset_plus_pat & offset"); + offset_plus_pat = offset = 0; + } - SCLogDebug("stored: offset %u depth %u offset_plus_pat %u " - "has_active_depth_chain %s", - offset, depth, offset_plus_pat, - has_active_depth_chain ? "true" : "false"); - if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) { - VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX); - offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance); - SCLogDebug("updated content to have offset %u", cd->offset); - } - if (has_active_depth_chain) { - if (offset_plus_pat && cd->flags & DETECT_CONTENT_WITHIN && - cd->within >= 0) { - if (depth && depth > offset_plus_pat) { - int32_t dist = 0; - if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance > 0) { - dist = cd->distance; - SCLogDebug("distance to add: %u. depth + dist %u", dist, - depth + dist); + SCLogDebug("stored: offset %u depth %u offset_plus_pat %u " + "has_active_depth_chain %s", + offset, depth, offset_plus_pat, has_active_depth_chain ? "true" : "false"); + if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) { + VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX); + offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance); + SCLogDebug("updated content to have offset %u", cd->offset); + } + if (has_active_depth_chain) { + if (offset_plus_pat && cd->flags & DETECT_CONTENT_WITHIN && cd->within >= 0) { + if (depth && depth > offset_plus_pat) { + int32_t dist = 0; + if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance > 0) { + dist = cd->distance; + SCLogDebug( + "distance to add: %u. depth + dist %u", dist, depth + dist); + } + SCLogDebug("depth %u + cd->within %u", depth, cd->within); + VALIDATE(depth + cd->within + dist >= 0 && + depth + cd->within + dist <= UINT16_MAX); + depth = cd->depth = (uint16_t)(depth + cd->within + dist); + } else { + SCLogDebug("offset %u + cd->within %u", offset, cd->within); + VALIDATE(depth + cd->within >= 0 && depth + cd->within <= UINT16_MAX); + depth = cd->depth = (uint16_t)(offset + cd->within); + } + SCLogDebug("updated content to have depth %u", cd->depth); + } else { + if (cd->depth == 0 && depth != 0) { + if (cd->within > 0) { + SCLogDebug("within %d distance %d", cd->within, cd->distance); + if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) { + VALIDATE(offset_plus_pat + cd->distance >= 0 && + offset_plus_pat + cd->distance <= UINT16_MAX); + cd->offset = (uint16_t)(offset_plus_pat + cd->distance); + SCLogDebug("updated content to have offset %u", cd->offset); } - SCLogDebug("depth %u + cd->within %u", depth, cd->within); - VALIDATE(depth + cd->within + dist >= 0 && - depth + cd->within + dist <= UINT16_MAX); - depth = cd->depth = (uint16_t)(depth + cd->within + dist); - } else { - SCLogDebug("offset %u + cd->within %u", offset, cd->within); + VALIDATE(depth + cd->within >= 0 && depth + cd->within <= UINT16_MAX); - depth = cd->depth = (uint16_t)(offset + cd->within); - } - SCLogDebug("updated content to have depth %u", cd->depth); - } else { - if (cd->depth == 0 && depth != 0) { - if (cd->within > 0) { - SCLogDebug("within %d distance %d", cd->within, cd->distance); - if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) { - VALIDATE(offset_plus_pat + cd->distance >= 0 && - offset_plus_pat + cd->distance <= UINT16_MAX); - cd->offset = (uint16_t)(offset_plus_pat + cd->distance); - SCLogDebug("updated content to have offset %u", cd->offset); - } - - VALIDATE(depth + cd->within >= 0 && - depth + cd->within <= UINT16_MAX); - depth = cd->depth = (uint16_t)(cd->within + depth); - SCLogDebug("updated content to have depth %u", cd->depth); - - if (cd->flags & DETECT_CONTENT_ENDS_WITH) { - has_ends_with = true; - if (ends_with_depth == 0) - ends_with_depth = depth; - ends_with_depth = MIN(ends_with_depth, depth); - } + depth = cd->depth = (uint16_t)(cd->within + depth); + SCLogDebug("updated content to have depth %u", cd->depth); + + if (cd->flags & DETECT_CONTENT_ENDS_WITH) { + has_ends_with = true; + if (ends_with_depth == 0) + ends_with_depth = depth; + ends_with_depth = MIN(ends_with_depth, depth); } } } } - if (cd->offset == 0) {// && offset != 0) { - if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) { - cd->offset = offset_plus_pat; - SCLogDebug("update content to have offset %u", cd->offset); - } + } + if (cd->offset == 0) { // && offset != 0) { + if (cd->flags & DETECT_CONTENT_DISTANCE && cd->distance >= 0) { + cd->offset = offset_plus_pat; + SCLogDebug("update content to have offset %u", cd->offset); } + } - if ((cd->flags & (DETECT_CONTENT_DEPTH|DETECT_CONTENT_OFFSET|DETECT_CONTENT_WITHIN|DETECT_CONTENT_DISTANCE)) == (DETECT_CONTENT_DISTANCE|DETECT_CONTENT_WITHIN) || - (cd->flags & (DETECT_CONTENT_DEPTH|DETECT_CONTENT_OFFSET|DETECT_CONTENT_WITHIN|DETECT_CONTENT_DISTANCE)) == (DETECT_CONTENT_DISTANCE)) { - if (cd->distance >= 0) { - // only distance - VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX); - offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance); - offset_plus_pat = offset + cd->content_len; - SCLogDebug("offset %u offset_plus_pat %u", offset, offset_plus_pat); - } - } - if (cd->flags & DETECT_CONTENT_OFFSET) { - offset = cd->offset; - offset_plus_pat = offset + cd->content_len; - SCLogDebug("stored offset %u offset_plus_pat %u", offset, offset_plus_pat); - } - if (cd->depth) { - depth = cd->depth; - SCLogDebug("stored depth now %u", depth); + if ((cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET | + DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) == + (DETECT_CONTENT_DISTANCE | DETECT_CONTENT_WITHIN) || + (cd->flags & (DETECT_CONTENT_DEPTH | DETECT_CONTENT_OFFSET | + DETECT_CONTENT_WITHIN | DETECT_CONTENT_DISTANCE)) == + (DETECT_CONTENT_DISTANCE)) { + if (cd->distance >= 0) { + // only distance + VALIDATE((uint32_t)offset_plus_pat + cd->distance <= UINT16_MAX); + offset = cd->offset = (uint16_t)(offset_plus_pat + cd->distance); offset_plus_pat = offset + cd->content_len; - if (cd->flags & DETECT_CONTENT_ENDS_WITH) { - has_ends_with = true; - if (ends_with_depth == 0) - ends_with_depth = depth; - ends_with_depth = MIN(ends_with_depth, depth); - } + SCLogDebug("offset %u offset_plus_pat %u", offset, offset_plus_pat); } - if ((cd->flags & (DETECT_CONTENT_WITHIN|DETECT_CONTENT_DEPTH)) == 0) { - has_active_depth_chain = false; - depth = 0; - } - break; } - case DETECT_PCRE: { - // relative could leave offset_plus_pat set. - const DetectPcreData *pd = (const DetectPcreData *)sm->ctx; - if (pd->flags & DETECT_PCRE_RELATIVE) { - depth = 0; - } else { - SCLogDebug("non-anchored PCRE not supported, reset offset_plus_pat & offset"); - offset_plus_pat = offset = depth = 0; + if (cd->flags & DETECT_CONTENT_OFFSET) { + offset = cd->offset; + offset_plus_pat = offset + cd->content_len; + SCLogDebug("stored offset %u offset_plus_pat %u", offset, offset_plus_pat); + } + if (cd->depth) { + depth = cd->depth; + SCLogDebug("stored depth now %u", depth); + offset_plus_pat = offset + cd->content_len; + if (cd->flags & DETECT_CONTENT_ENDS_WITH) { + has_ends_with = true; + if (ends_with_depth == 0) + ends_with_depth = depth; + ends_with_depth = MIN(ends_with_depth, depth); } + } + if ((cd->flags & (DETECT_CONTENT_WITHIN | DETECT_CONTENT_DEPTH)) == 0) { has_active_depth_chain = false; - break; + depth = 0; } - default: { - SCLogDebug("keyword not supported, reset offset_plus_pat & offset"); + break; + } + case DETECT_PCRE: { + // relative could leave offset_plus_pat set. + const DetectPcreData *pd = (const DetectPcreData *)sm->ctx; + if (pd->flags & DETECT_PCRE_RELATIVE) { + depth = 0; + } else { + SCLogDebug("non-anchored PCRE not supported, reset offset_plus_pat & offset"); offset_plus_pat = offset = depth = 0; - has_active_depth_chain = false; - break; } + has_active_depth_chain = false; + break; } + default: + SCLogDebug("keyword not supported, reset offset_plus_pat & offset"); + offset_plus_pat = offset = depth = 0; + has_active_depth_chain = false; + break; } - /* apply anchored 'ends with' as depth to all patterns */ - if (has_depth && has_ends_with) { - sm = s->init_data->smlists[list]; - for ( ; sm != NULL; sm = sm->next) { - switch (sm->type) { - case DETECT_CONTENT: { - DetectContentData *cd = (DetectContentData *)sm->ctx; - if (cd->depth == 0) - cd->depth = ends_with_depth; - cd->depth = MIN(ends_with_depth, cd->depth); - if (cd->depth) - cd->flags |= DETECT_CONTENT_DEPTH; - break; - } + } + /* apply anchored 'ends with' as depth to all patterns */ + if (has_depth && has_ends_with) { + for (SigMatch *sm = sm_head; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_CONTENT: { + DetectContentData *cd = (DetectContentData *)sm->ctx; + if (cd->depth == 0) + cd->depth = ends_with_depth; + cd->depth = MIN(ends_with_depth, cd->depth); + if (cd->depth) + cd->flags |= DETECT_CONTENT_DEPTH; + break; } } } @@ -696,6 +692,14 @@ void DetectContentPropagateLimits(Signature *s) #undef VALIDATE } +void DetectContentPropagateLimits(Signature *s) +{ + for (uint32_t list = 0; list < s->init_data->smlists_array_size; list++) { + SigMatch *sm = s->init_data->smlists[list]; + PropagateLimits(s, sm); + } +} + static inline bool NeedsAsHex(uint8_t c) { if (!isprint(c))