Skip to content

Commit fc90c88

Browse files
authored
[6.8] Improve circular reference detection in grok processor (#74581) (#74772)
1 parent c3ea8df commit fc90c88

File tree

2 files changed

+42
-11
lines changed

2 files changed

+42
-11
lines changed

libs/grok/src/main/java/org/elasticsearch/grok/Grok.java

+26-7
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,21 @@ private Grok(Map<String, String> patternBank, String grokPattern, boolean namedC
114114
* check for a circular reference.
115115
*/
116116
private void forbidCircularReferences(String patternName, List<String> path, String pattern) {
117-
if (pattern.contains("%{" + patternName + "}") || pattern.contains("%{" + patternName + ":")) {
117+
// first ensure that the pattern bank contains no simple circular references (i.e., any pattern
118+
// containing an immediate reference to itself) as those can cause the remainder of this algorithm
119+
// to recurse infinitely
120+
for (Map.Entry<String, String> entry : patternBank.entrySet()) {
121+
if (patternReferencesItself(entry.getValue(), entry.getKey())) {
122+
throw new IllegalArgumentException("circular reference in pattern [" + entry.getKey() + "][" + entry.getValue() + "]");
123+
}
124+
}
125+
126+
// next recursively check any other pattern names referenced in the pattern
127+
innerForbidCircularReferences(patternName, path, pattern);
128+
}
129+
130+
private void innerForbidCircularReferences(String patternName, List<String> path, String pattern) {
131+
if (patternReferencesItself(pattern, patternName)) {
118132
String message;
119133
if (path.isEmpty()) {
120134
message = "circular reference in pattern [" + patternName + "][" + pattern + "]";
@@ -129,17 +143,18 @@ private void forbidCircularReferences(String patternName, List<String> path, Str
129143
throw new IllegalArgumentException(message);
130144
}
131145

146+
// next check any other pattern names found in the pattern
132147
for (int i = pattern.indexOf("%{"); i != -1; i = pattern.indexOf("%{", i + 1)) {
133148
int begin = i + 2;
134-
int brackedIndex = pattern.indexOf('}', begin);
149+
int bracketIndex = pattern.indexOf('}', begin);
135150
int columnIndex = pattern.indexOf(':', begin);
136151
int end;
137-
if (brackedIndex != -1 && columnIndex == -1) {
138-
end = brackedIndex;
139-
} else if (columnIndex != -1 && brackedIndex == -1) {
152+
if (bracketIndex != -1 && columnIndex == -1) {
153+
end = bracketIndex;
154+
} else if (columnIndex != -1 && bracketIndex == -1) {
140155
end = columnIndex;
141-
} else if (brackedIndex != -1 && columnIndex != -1) {
142-
end = Math.min(brackedIndex, columnIndex);
156+
} else if (bracketIndex != -1 && columnIndex != -1) {
157+
end = Math.min(bracketIndex, columnIndex);
143158
} else {
144159
throw new IllegalArgumentException("pattern [" + pattern + "] has circular references to other pattern definitions");
145160
}
@@ -149,6 +164,10 @@ private void forbidCircularReferences(String patternName, List<String> path, Str
149164
}
150165
}
151166

167+
private static boolean patternReferencesItself(String pattern, String patternName) {
168+
return pattern.contains("%{" + patternName + "}") || pattern.contains("%{" + patternName + ":");
169+
}
170+
152171
public String groupMatch(String name, Region region, String pattern) {
153172
try {
154173
int number = GROK_PATTERN_REGEX.nameToBackrefNumber(name.getBytes(StandardCharsets.UTF_8), 0,

libs/grok/src/test/java/org/elasticsearch/grok/GrokTests.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,7 @@ public void testCircularReference() {
244244
String pattern = "%{NAME1}";
245245
new Grok(bank, pattern, false);
246246
});
247-
assertEquals("circular reference in pattern [NAME3][!!!%{NAME1}!!!] back to pattern [NAME1] via patterns [NAME2]",
248-
e.getMessage());
247+
assertEquals("circular reference in pattern [NAME3][!!!%{NAME1}!!!] back to pattern [NAME1] via patterns [NAME2]", e.getMessage());
249248

250249
e = expectThrows(IllegalArgumentException.class, () -> {
251250
Map<String, String> bank = new TreeMap<>();
@@ -257,8 +256,21 @@ public void testCircularReference() {
257256
String pattern = "%{NAME1}";
258257
new Grok(bank, pattern, false);
259258
});
260-
assertEquals("circular reference in pattern [NAME5][!!!%{NAME1}!!!] back to pattern [NAME1] " +
261-
"via patterns [NAME2=>NAME3=>NAME4]", e.getMessage());
259+
assertEquals(
260+
"circular reference in pattern [NAME5][!!!%{NAME1}!!!] back to pattern [NAME1] via patterns [NAME2=>NAME3=>NAME4]",
261+
e.getMessage()
262+
);
263+
}
264+
265+
public void testCircularSelfReference() {
266+
Exception e = expectThrows(IllegalArgumentException.class, () -> {
267+
Map<String, String> bank = new HashMap<>();
268+
bank.put("ANOTHER", "%{INT}");
269+
bank.put("INT", "%{INT}");
270+
String pattern = "does_not_matter";
271+
new Grok(bank, pattern, false);
272+
});
273+
assertEquals("circular reference in pattern [INT][%{INT}]", e.getMessage());
262274
}
263275

264276
public void testBooleanCaptures() {

0 commit comments

Comments
 (0)