From: Jeff Lucovsky Date: Sat, 13 Feb 2021 15:41:09 +0000 (-0500) Subject: detect/content: Consider distance in validation X-Git-Tag: suricata-7.0.0-rc1~379 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7eb5fb1826233d7a25720e85baf4ab1baab52c1d;p=thirdparty%2Fsuricata.git detect/content: Consider distance in validation Ticket: 2982 This commit validates that the content usage in a rule will not exceed the dsize value. Values of distance that cause the right edge to be exceeded are considered an error and the signature will be rejected. --- diff --git a/src/detect-content.c b/src/detect-content.c index f5229ab7bc..e3dbd85379 100644 --- a/src/detect-content.c +++ b/src/detect-content.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2019 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -392,9 +392,78 @@ void DetectContentFree(DetectEngineCtx *de_ctx, void *ptr) SCReturn; } +/* + * \brief Determine the size needed to accommodate the content + * elements of a signature + * \param s signature to get dsize value from + * \param max_size Maximum buffer/data size allowed. + * \param list signature match list. + * \param len Maximum length required + * \param offset Maximum offset encounted + * + * Note that negated content does not contribute to the maximum + * required size value. However, each negated content's values + * must not exceed the size value. + * + * Values from negated content blocks are used to determine if the + * negated content block requires a value that exceeds "max_size". The + * distance and within values from negated content blocks are added to + * the running total of required content size to see if the max_size + * would be exceeded. + * + * - Non-negated content contributes to the required size (content length, distance) + * - Negated content values are checked but not accumulated for the required size. + */ +void SigParseRequiredContentSize( + const Signature *s, const int max_size, int list, int *len, int *offset) +{ + if (list > (int)s->init_data->smlists_array_size) { + return; + } + + SigMatch *sm = s->init_data->smlists[list]; + int max_offset = 0, total_len = 0; + bool first = true; + for (; sm != NULL; sm = sm->next) { + if (sm->type != DETECT_CONTENT || sm->ctx == NULL) { + continue; + } + + DetectContentData *cd = (DetectContentData *)sm->ctx; + SCLogDebug("content_len %d; negated: %s; distance: %d, offset: %d, depth: %d", + cd->content_len, cd->flags & DETECT_CONTENT_NEGATED ? "yes" : "no", cd->distance, + cd->offset, cd->depth); + + if (!first) { + /* only count content with relative modifiers */ + if (!((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN))) + continue; + + if (cd->flags & DETECT_CONTENT_NEGATED) { + /* Check if distance/within cause max to be exceeded */ + int check = total_len + cd->distance + cd->within; + if (max_size < check) { + *len = check; + return; + } + + continue; + } + } + SCLogDebug("content_len %d; distance: %d, offset: %d, depth: %d", cd->content_len, + cd->distance, cd->offset, cd->depth); + total_len += cd->content_len + cd->distance; + max_offset = MAX(max_offset, cd->offset); + first = false; + } + + *len = total_len; + *offset = max_offset; +} + /** - * \retval 1 valid - * \retval 0 invalid + * \retval true valid + * \retval false invalid */ bool DetectContentPMATCHValidateCallback(const Signature *s) { @@ -409,25 +478,17 @@ bool DetectContentPMATCHValidateCallback(const Signature *s) uint32_t max_right_edge = (uint32_t)max_right_edge_i; - const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; - for ( ; sm != NULL; sm = sm->next) { - if (sm->type != DETECT_CONTENT) - continue; - const DetectContentData *cd = (const DetectContentData *)sm->ctx; - uint32_t right_edge = cd->content_len + cd->offset; - if (cd->content_len > max_right_edge) { - SCLogError(SC_ERR_INVALID_SIGNATURE, - "signature can't match as content length %u is bigger than dsize %u.", - cd->content_len, max_right_edge); - return false; - } - if (right_edge > max_right_edge) { + int min_dsize_required = SigParseMaxRequiredDsize(s); + if (min_dsize_required >= 0) { + SCLogDebug("min_dsize %d; max_right_edge %d", min_dsize_required, max_right_edge); + if ((uint32_t)min_dsize_required > max_right_edge) { SCLogError(SC_ERR_INVALID_SIGNATURE, - "signature can't match as content length %u with offset %u (=%u) is bigger than dsize %u.", - cd->content_len, cd->offset, right_edge, max_right_edge); + "signature can't match as required content length %d exceeds dsize value %d", + min_dsize_required, max_right_edge); return false; } } + return true; } @@ -2636,7 +2697,7 @@ static int SigTest42TestNegatedContent(void) /** * \test A negative test that checks that the content string doesn't contain * the negated content within the specified depth, and also after the - * specified offset. Since the content is there, the match fails. + * specified offset. Since the content is there, the match fails. * * Match is at offset:23, depth:34 */ diff --git a/src/detect-content.h b/src/detect-content.h index 5959d6473f..a99dc78462 100644 --- a/src/detect-content.h +++ b/src/detect-content.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -124,5 +124,7 @@ bool DetectContentPMATCHValidateCallback(const Signature *s); void DetectContentPropagateLimits(Signature *s); void DetectContentPatternPrettyPrint(const DetectContentData *cd, char *str, size_t str_len); +void SigParseRequiredContentSize( + const Signature *s, const int max, int list, int *len, int *offset); #endif /* __DETECT_CONTENT_H__ */ diff --git a/src/detect-dsize.c b/src/detect-dsize.c index b86140e5c4..c0603c67ee 100644 --- a/src/detect-dsize.c +++ b/src/detect-dsize.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -289,6 +289,48 @@ void SigParseSetDsizePair(Signature *s) } } +/** + * \brief Determine the required dsize for the signature + * \param s signature to get dsize value from + * + * Note that negated content does not contribute to the maximum + * required dsize value. However, each negated content's values + * must not exceed the dsize value. See SigParseRequiredContentSize. + * + * \retval -1 Signature doesn't have a dsize keyword + * \retval >= 0 Dsize value required to not exclude content matches + */ +int SigParseMaxRequiredDsize(const Signature *s) +{ + SCEnter(); + + if (!(s->flags & SIG_FLAG_DSIZE)) { + SCReturnInt(-1); + } + + const int dsize = SigParseGetMaxDsize(s); + if (dsize < 0) { + /* nothing to do */ + SCReturnInt(-1); + } + + int total_length, offset; + SigParseRequiredContentSize(s, dsize, DETECT_SM_LIST_PMATCH, &total_length, &offset); + SCLogDebug("dsize: %d len: %d; offset: %d [%s]", dsize, total_length, offset, s->sig_str); + + if (total_length > dsize) { + SCLogDebug("required_dsize: %d exceeds dsize: %d", total_length, dsize); + return total_length; + } + + if ((total_length + offset) > dsize) { + SCLogDebug("length + offset: %d exceeds dsize: %d", total_length + offset, dsize); + return total_length + offset; + } + + SCReturnInt(-1); +} + /** * \brief Apply dsize as depth to content matches in the rule * \param s signature to get dsize value from diff --git a/src/detect-dsize.h b/src/detect-dsize.h index 71b16484e2..c262a31186 100644 --- a/src/detect-dsize.h +++ b/src/detect-dsize.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -29,6 +29,7 @@ /* prototypes */ void DetectDsizeRegister (void); +int SigParseMaxRequiredDsize(const Signature *s); int SigParseGetMaxDsize(const Signature *s); void SigParseSetDsizePair(Signature *s); void SigParseApplyDsizeToContent(Signature *s);