Skip to content

Commit 7603fde

Browse files
authored
Improve circular reference detection in grok processor (#74581)
1 parent aa76ebb commit 7603fde

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,21 @@ private Grok(Map<String, String> patternBank, String grokPattern, boolean namedC
105105
* check for a circular reference.
106106
*/
107107
private void forbidCircularReferences(String patternName, List<String> path, String pattern) {
108-
if (pattern.contains("%{" + patternName + "}") || pattern.contains("%{" + patternName + ":")) {
108+
// first ensure that the pattern bank contains no simple circular references (i.e., any pattern
109+
// containing an immediate reference to itself) as those can cause the remainder of this algorithm
110+
// to recurse infinitely
111+
for (Map.Entry<String, String> entry : patternBank.entrySet()) {
112+
if (patternReferencesItself(entry.getValue(), entry.getKey())) {
113+
throw new IllegalArgumentException("circular reference in pattern [" + entry.getKey() + "][" + entry.getValue() + "]");
114+
}
115+
}
116+
117+
// next recursively check any other pattern names referenced in the pattern
118+
innerForbidCircularReferences(patternName, path, pattern);
119+
}
120+
121+
private void innerForbidCircularReferences(String patternName, List<String> path, String pattern) {
122+
if (patternReferencesItself(pattern, patternName)) {
109123
String message;
110124
if (path.isEmpty()) {
111125
message = "circular reference in pattern [" + patternName + "][" + pattern + "]";
@@ -120,17 +134,18 @@ private void forbidCircularReferences(String patternName, List<String> path, Str
120134
throw new IllegalArgumentException(message);
121135
}
122136

137+
// next check any other pattern names found in the pattern
123138
for (int i = pattern.indexOf("%{"); i != -1; i = pattern.indexOf("%{", i + 1)) {
124139
int begin = i + 2;
125-
int brackedIndex = pattern.indexOf('}', begin);
140+
int bracketIndex = pattern.indexOf('}', begin);
126141
int columnIndex = pattern.indexOf(':', begin);
127142
int end;
128-
if (brackedIndex != -1 && columnIndex == -1) {
129-
end = brackedIndex;
130-
} else if (columnIndex != -1 && brackedIndex == -1) {
143+
if (bracketIndex != -1 && columnIndex == -1) {
144+
end = bracketIndex;
145+
} else if (columnIndex != -1 && bracketIndex == -1) {
131146
end = columnIndex;
132-
} else if (brackedIndex != -1 && columnIndex != -1) {
133-
end = Math.min(brackedIndex, columnIndex);
147+
} else if (bracketIndex != -1 && columnIndex != -1) {
148+
end = Math.min(bracketIndex, columnIndex);
134149
} else {
135150
throw new IllegalArgumentException("pattern [" + pattern + "] has circular references to other pattern definitions");
136151
}
@@ -140,6 +155,10 @@ private void forbidCircularReferences(String patternName, List<String> path, Str
140155
}
141156
}
142157

158+
private static boolean patternReferencesItself(String pattern, String patternName) {
159+
return pattern.contains("%{" + patternName + "}") || pattern.contains("%{" + patternName + ":");
160+
}
161+
143162
private String groupMatch(String name, Region region, String pattern) {
144163
int number = GROK_PATTERN_REGEX.nameToBackrefNumber(name.getBytes(StandardCharsets.UTF_8), 0,
145164
name.getBytes(StandardCharsets.UTF_8).length, region);

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

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,7 @@ public void testCircularReference() {
320320
String pattern = "%{NAME1}";
321321
new Grok(bank, pattern, false, logger::warn);
322322
});
323-
assertEquals("circular reference in pattern [NAME3][!!!%{NAME1}!!!] back to pattern [NAME1] via patterns [NAME2]",
324-
e.getMessage());
323+
assertEquals("circular reference in pattern [NAME3][!!!%{NAME1}!!!] back to pattern [NAME1] via patterns [NAME2]", e.getMessage());
325324

326325
e = expectThrows(IllegalArgumentException.class, () -> {
327326
Map<String, String> bank = new TreeMap<>();
@@ -331,10 +330,23 @@ public void testCircularReference() {
331330
bank.put("NAME4", "!!!%{NAME5}!!!");
332331
bank.put("NAME5", "!!!%{NAME1}!!!");
333332
String pattern = "%{NAME1}";
334-
new Grok(bank, pattern, false, logger::warn );
333+
new Grok(bank, pattern, false, logger::warn);
334+
});
335+
assertEquals(
336+
"circular reference in pattern [NAME5][!!!%{NAME1}!!!] back to pattern [NAME1] via patterns [NAME2=>NAME3=>NAME4]",
337+
e.getMessage()
338+
);
339+
}
340+
341+
public void testCircularSelfReference() {
342+
Exception e = expectThrows(IllegalArgumentException.class, () -> {
343+
Map<String, String> bank = new HashMap<>();
344+
bank.put("ANOTHER", "%{INT}");
345+
bank.put("INT", "%{INT}");
346+
String pattern = "does_not_matter";
347+
new Grok(bank, pattern, false, logger::warn);
335348
});
336-
assertEquals("circular reference in pattern [NAME5][!!!%{NAME1}!!!] back to pattern [NAME1] " +
337-
"via patterns [NAME2=>NAME3=>NAME4]", e.getMessage());
349+
assertEquals("circular reference in pattern [INT][%{INT}]", e.getMessage());
338350
}
339351

340352
public void testBooleanCaptures() {

0 commit comments

Comments
 (0)