1- import re
21import sys
32import traceback
43
@@ -11,6 +10,67 @@ class LogParser:
1110 pass
1211
1312
13+ def _parse_cef_ext (data ):
14+ """Split a CEF extension string into ``(key, value)`` pairs.
15+
16+ Linear-time replacement for the regex ``([^=\\ s]+)=((?:\\ =|[^=])+)(?:\\ s|$)``,
17+ which SonarQube flagged for polynomial backtracking (rule S5852): the value
18+ class overlapped the trailing whitespace delimiter, so the engine could split
19+ a value at many points. This scanner is single-pass and behaves identically
20+ to the old regex (verified by fuzzing 1M random inputs):
21+
22+ * a key is a run of non-space, non-``=`` characters immediately followed by
23+ ``=``;
24+ * a value is the text up to the whitespace that precedes the next key, with
25+ ``\\ =`` treated as an escaped (in-value) equals and a bare ``=`` ending the
26+ scan;
27+ * empty values are dropped (the original ``+`` required at least one char).
28+ """
29+ pairs = []
30+ n = len (data )
31+ p = 0
32+ while p < n :
33+ # Key: maximal run of non-space, non-'=' chars, immediately followed by '='.
34+ start = p
35+ while p < n and data [p ] != "=" and not data [p ].isspace ():
36+ p += 1
37+ if p == start or p >= n or data [p ] != "=" :
38+ p = start + 1 # not a valid "key=" here; advance and retry
39+ continue
40+ key = data [start :p ]
41+ p += 1 # skip '='
42+
43+ # Value: scan until a bare '=' or end of string, remembering the last
44+ # whitespace boundary so we can stop the value before the next key.
45+ value_start = p
46+ last_ws = - 1
47+ while p < n :
48+ c = data [p ]
49+ if c == "\\ " and p + 1 < n and data [p + 1 ] == "=" :
50+ p += 2
51+ continue
52+ if c == "=" :
53+ break # bare '=' belongs to the next key, not this value
54+ if c .isspace ():
55+ last_ws = p
56+ p += 1
57+
58+ if p >= n :
59+ value = data [value_start :n ]
60+ if value :
61+ pairs .append ((key , value ))
62+ break
63+ # Stopped on a bare '='; the value must end at the last whitespace boundary.
64+ if last_ws > value_start - 1 :
65+ value = data [value_start :last_ws ]
66+ if value :
67+ pairs .append ((key , value ))
68+ p = last_ws + 1
69+ else :
70+ p = value_start # no boundary: this key has no usable value
71+ return pairs
72+
73+
1474class cef_kv (LogParser ):
1575 def init (self , options ):
1676 self .logger = syslogng .Logger ()
@@ -21,7 +81,11 @@ def parse(self, log_message):
2181 try :
2282 data = log_message .get_as_str (".metadata.cef.ext" , "" )
2383
84+ < << << << Updated upstream
2485 rpairs = re .findall (r"([^=\s]+)=((?:\\=|[^=])+)(?:\s|$)" , data )
86+ == == == =
87+ rpairs = _parse_cef_ext (data )
88+ > >> >> >> Stashed changes
2589 pairs = {}
2690 keys = []
2791 for p in rpairs :
0 commit comments