From bb330900d4829711fd83c41392c9c091ce85050a Mon Sep 17 00:00:00 2001 From: onice Date: Fri, 17 Jul 2026 10:04:27 +0800 Subject: [PATCH] Optimize RFC5424 structured data parsing (#5437) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Which issue(s) this PR fixes**: Fixes #5367 **What this PR does / why we need it**: The RFC5424 structured-data pattern repeated an element that already contains a lazy wildcard. On Ruby 3.2 and older, invalid input with adjacent structured-data elements could trigger exponential backtracking. This removes the redundant outer repetition. The lazy match still spans adjacent structured-data elements, while a focused timeout regression protects the invalid-suffix case. Validation included an exhaustive comparison of 97,656 generated suffixes on Ruby 2.6 and Ruby 4.0; match results and all named captures were unchanged. **Docs Changes**: None. **Release Note**: parser_syslog: avoid excessive backtracking when parsing malformed RFC5424 structured data. **Testing**: - `bundle exec ruby -Itest test/plugin/test_parser_syslog.rb` — 77 tests, 332 assertions, 0 failures, 0 errors - `bundle exec rake test` — 4,336 tests, 15,819 assertions, 0 failures, 0 errors, 3 existing pendings, 36 existing omissions - `rubocop` — 459 files inspected, no offenses - `ruby -c` for both changed files and `git diff --check` Signed-off-by: Joey@macstudio <4296411@qq.com> Signed-off-by: github-actions[bot] --- lib/fluent/plugin/parser_syslog.rb | 2 +- test/plugin/test_parser_syslog.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/fluent/plugin/parser_syslog.rb b/lib/fluent/plugin/parser_syslog.rb index acf2cbfa71..2b6fcca479 100644 --- a/lib/fluent/plugin/parser_syslog.rb +++ b/lib/fluent/plugin/parser_syslog.rb @@ -44,7 +44,7 @@ class SyslogParser < Parser RFC3164_CAPTURES = RFC3164_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze RFC3164_PRI_REGEXP = /^<(?[0-9]{1,3})>/ - RFC5424_WITHOUT_TIME_AND_PRI_REGEXP = /(?[!-~]{1,255}) (?[!-~]{1,48}) (?[!-~]{1,128}) (?[!-~]{1,32}) (?(?:\-|(?:\[.*?(?.+))?\z/m + RFC5424_WITHOUT_TIME_AND_PRI_REGEXP = /(?[!-~]{1,255}) (?[!-~]{1,48}) (?[!-~]{1,128}) (?[!-~]{1,32}) (?(?:\-|(?:\[.*?(?.+))?\z/m RFC5424_CAPTURES = RFC5424_WITHOUT_TIME_AND_PRI_REGEXP.names.freeze RFC5424_PRI_REGEXP = /^<(?\d{1,3})>\d\d{0,2}\s/ diff --git a/test/plugin/test_parser_syslog.rb b/test/plugin/test_parser_syslog.rb index 64161f48f7..dcdbca8388 100644 --- a/test/plugin/test_parser_syslog.rb +++ b/test/plugin/test_parser_syslog.rb @@ -1,6 +1,7 @@ require_relative '../helper' require 'fluent/test/driver/parser' require 'fluent/plugin/parser' +require 'timeout' class SyslogParserTest < ::Test::Unit::TestCase def setup @@ -199,6 +200,16 @@ def test_parse_various_characters_for_tag_with_priority(param) end class TestRFC5424Regexp < self + def test_rejects_invalid_structured_data_without_excessive_backtracking + text = 'host ident pid msgid ' + ('[example]' * 30) + 'invalid' + + match = Timeout.timeout(1) do + Fluent::Plugin::SyslogParser::RFC5424_WITHOUT_TIME_AND_PRI_REGEXP.match(text) + end + + assert_nil(match) + end + data('regexp' => 'regexp', 'string' => 'string') def test_parse_with_rfc5424_message(param) @parser.configure(