Bug #9269
Updated by Jeff Lucovsky 10 days ago
When a rule uses bsize, Suricata checks at load time whether the rule's contents can fit in the buffer, and The load-time check that rejects the rule if they can't. That check bsize rules which can't match gets some rules wrong in both directions. directions: it loads rules that can never match, and it rejects rules that can. It DetectBsizeValidateContentCallback (src/detect-bsize.c) reads only looks at the first bsize on keyword in a buffer, buffer and skips the check when stops. When that bsize first keyword is a lower bound (bsize:>N) or uses <=. It only counts bsize:<=N, it skips the check entirely. The required length comes from SigParseRequiredContentSize (src/detect-content.c), which adds up the first content and the contents after it that use with distance or within. And it within after it, skips any other content, and counts a negated contents, first content and a negated content's within window, window as bytes the buffer has to must hold. These rules Rules that load on main but can never match: <pre> dns.query; content:"0123456789"; bsize:<20; bsize:<8; dns.query; content:"0123456789"; bsize:>5; bsize:<8; dns.query; content:"abcdef"; bsize:<=5; dns.query; content:"abc"; bsize:15; bsize:27; dns.query; bsize:>20; bsize:<10; dns.query; content:"abc"; content:"defghij"; content:"k"; distance:0; bsize:5; </pre> These are rejected on main but can match, since The first is checked against its first bsize only. The second and third aren't checked at all, because their first bsize is a lower bound or uses <=. In the next two, no buffer too short to hold a negated content length satisfies both bsize keywords. In the negation: last one, "defghij" is not relative, so its 7 bytes are never compared against the bound of 5. Rules that main rejects although they can match: <pre> dns.query; content:!"abcdef"; bsize:5; -> required content length 6 exceeds bsize value: 5 http.uri; content:"/"; content:!"admin"; within:100; bsize:<32; -> required content length 101 exceeds bsize value: 32 </pre> Four A buffer too short to hold a negated content, or to reach its within window, satisfies the negation, and content inspection treats it that way. ET Open and ET Pro rules that load today on main and can never match: 2063355 (bsize:15 and bsize:27 on the same http.host), http.host buffer), and 2068295, 2068345 and 2866524 (a content longer than the bsize allows). buffer's bsize). These were found by loading the ruleset with the fix below. Proposed fix: check the content length against the smallest tightest upper bound among all of all the a buffer's bsize keywords on the buffer, <= included. Reject keywords, bsize:<=N included; reject a buffer whose bsize keywords that leave no buffer length can satisfy. Check each group that satisfies all of contents tied together by them; and compute the required length per content chain, where a content without distance or within starts a new chain and each chain must fit the bound on its own, so every content has to fit, and don't count negated contents. own. Negated contents need no bytes. The dsize is not affected. check keeps using SigParseRequiredContentSize unchanged. main-8.0.x has the same code. Found while working on #4226 (https://github.com/OISF/suricata/pull/16429). (PR https://github.com/OISF/suricata/pull/16429).