Backported #3112 into 19.x branch by bbakerman · Pull Request #3133 · graphql-java/graphql-java · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/graphql/parser/ParseCancelledTooDeepException.java
47 changes: 40 additions & 7 deletions src/main/java/graphql/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int
// this lexer wrapper allows us to stop lexing when too many tokens are in place. This prevents DOS attacks.
int maxTokens = parserOptions.getMaxTokens();
int maxWhitespaceTokens = parserOptions.getMaxWhitespaceTokens();
BiConsumer<Integer, Token> onTooManyTokens = (maxTokenCount, token) -> throwCancelParseIfTooManyTokens(token, maxTokenCount, multiSourceReader);
BiConsumer<Integer, Token> onTooManyTokens = (maxTokenCount, token) -> throwIfTokenProblems(
token,
maxTokenCount,
multiSourceReader,
ParseCancelledException.class);
SafeTokenSource safeTokenSource = new SafeTokenSource(lexer, maxTokens, maxWhitespaceTokens, onTooManyTokens);

CommonTokenStream tokens = new CommonTokenStream(safeTokenSource);
Expand Down Expand Up @@ -285,9 +289,30 @@ private void setupParserListener(MultiSourceReader multiSourceReader, GraphqlPar
ParserOptions parserOptions = toLanguage.getParserOptions();
ParsingListener parsingListener = parserOptions.getParsingListener();
int maxTokens = parserOptions.getMaxTokens();
int maxRuleDepth = parserOptions.getMaxRuleDepth();
// prevent a billion laugh attacks by restricting how many tokens we allow
ParseTreeListener listener = new GraphqlBaseListener() {
int count = 0;
int depth = 0;


@Override
public void enterEveryRule(ParserRuleContext ctx) {
depth++;
if (depth > maxRuleDepth) {
throwIfTokenProblems(
ctx.getStart(),
maxRuleDepth,
multiSourceReader,
ParseCancelledTooDeepException.class
);
}
}

@Override
public void exitEveryRule(ParserRuleContext ctx) {
depth--;
}

@Override
public void visitTerminal(TerminalNode node) {
Expand All @@ -312,15 +337,20 @@ public int getCharPositionInLine() {

count++;
if (count > maxTokens) {
throwCancelParseIfTooManyTokens(token, maxTokens, multiSourceReader);
throwIfTokenProblems(
token,
maxTokens,
multiSourceReader,
ParseCancelledException.class
);
}
}
};
parser.addParseListener(listener);
}

private void throwCancelParseIfTooManyTokens(Token token, int maxTokens, MultiSourceReader multiSourceReader) throws ParseCancelledException {
String tokenType = "grammar";
private void throwIfTokenProblems(Token token, int maxLimit, MultiSourceReader multiSourceReader, Class<? extends InvalidSyntaxException> targetException) throws ParseCancelledException {
String tokenType = "grammar";
SourceLocation sourceLocation = null;
String offendingToken = null;
if (token != null) {
Expand All @@ -330,9 +360,12 @@ private void throwCancelParseIfTooManyTokens(Token token, int maxTokens, MultiSo
offendingToken = token.getText();
sourceLocation = AntlrHelper.createSourceLocation(multiSourceReader, token.getLine(), token.getCharPositionInLine());
}
String msg = String.format("More than %d %s tokens have been presented. To prevent Denial Of Service attacks, parsing has been cancelled.", maxTokens, tokenType);
throw new ParseCancelledException(msg, sourceLocation, offendingToken);
}
if (targetException.equals(ParseCancelledTooDeepException.class)) {
String msg = String.format("More than %d deep %s rules have been entered. To prevent Denial Of Service attacks, parsing has been cancelled.", maxLimit, tokenType);
throw new ParseCancelledTooDeepException(msg, sourceLocation, offendingToken, maxLimit, tokenType);
}
String msg = String.format("More than %d %s tokens have been presented. To prevent Denial Of Service attacks, parsing has been cancelled.", maxLimit, tokenType);
throw new ParseCancelledException(msg, sourceLocation, offendingToken); }

/**
* Allows you to override the ANTLR to AST code.
Expand Down
41 changes: 37 additions & 4 deletions src/main/java/graphql/parser/ParserOptions.java
Loading