summaryrefslogtreecommitdiff
path: root/Userland/Shell
diff options
context:
space:
mode:
authorBen Wiederhake <BenWiederhake.GitHub@gmx.de>2021-10-21 22:55:52 +0200
committerLinus Groh <mail@linusgroh.de>2021-10-23 19:29:59 +0100
commit48e4fb239a1466a8a89520abd7fb851963267c60 (patch)
tree7799b512e776366b29bbb808a3942630b36bf730 /Userland/Shell
parentfc519d43baaa926aae2213d5df526abd60b493e2 (diff)
downloadserenity-48e4fb239a1466a8a89520abd7fb851963267c60.zip
Shell: Prevent exponential explosion around '$(('
When parse_expression looks at '$((', there are two ways it can end up in parse_expression again, three consumed characters later. All these ways fail, so what happened was that the parser tried all possible combinations, hence taking potentially an exponential amount of time. 1. parse_evaluate swallows the '$(', a new invocation of parse_expression swallows the other '(', and through parse_list_expression we're at another parse_expression. 2. parse_evaluate swallows the '$(', but returns a SyntaxError. parse_expression used to not recognize the error, and treated it as a regular AST node, calling into read_concat, then a new invocation of parse_expression swallows the other '(', and through parse_list_expression we're at another parse_expression. Fixes #10561. Found by OSS Fuzz, long-standing issue https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28113
Diffstat (limited to 'Userland/Shell')
-rw-r--r--Userland/Shell/Parser.cpp4
-rw-r--r--Userland/Shell/Parser.h2
2 files changed, 4 insertions, 2 deletions
diff --git a/Userland/Shell/Parser.cpp b/Userland/Shell/Parser.cpp
index b56c599b64..bc98b3f25e 100644
--- a/Userland/Shell/Parser.cpp
+++ b/Userland/Shell/Parser.cpp
@@ -1166,8 +1166,10 @@ RefPtr<AST::Node> Parser::parse_expression()
if (auto immediate = parse_immediate_expression())
return read_concat(immediate.release_nonnull());
- if (auto inline_exec = parse_evaluate())
+ auto inline_exec = parse_evaluate();
+ if (inline_exec && !inline_exec->is_syntax_error())
return read_concat(inline_exec.release_nonnull());
+ return inline_exec;
}
if (starting_char == '#')
diff --git a/Userland/Shell/Parser.h b/Userland/Shell/Parser.h
index 37aac4097f..003267f968 100644
--- a/Userland/Shell/Parser.h
+++ b/Userland/Shell/Parser.h
@@ -251,7 +251,7 @@ expression :: evaluate expression?
| '(' list_expression ')' expression?
evaluate :: '$' '(' pipe_sequence ')'
- | '$' expression {eval / dynamic resolve}
+ | '$' [lookahead != '('] expression {eval / dynamic resolve}
string_composite :: string string_composite?
| variable string_composite?