From f8f36effc9d3fdcf8b780ea2c80bf2fbf9241b8a Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 5 Jun 2021 09:55:16 -0400 Subject: [PATCH] LibSQL: Limit the allowed depth of an expression tree According to the definition at https://sqlite.org/lang_expr.html, SQL expressions could be infinitely deep. For practicality, SQLite enforces a maxiumum expression tree depth of 1000. Apply the same limit in LibSQL to avoid stack overflow in the expression parser. Fixes https://crbug.com/oss-fuzz/34859. --- Tests/LibSQL/TestSqlExpressionParser.cpp | 7 +++++++ Userland/Libraries/LibSQL/Parser.cpp | 6 ++++++ Userland/Libraries/LibSQL/Parser.h | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/Tests/LibSQL/TestSqlExpressionParser.cpp b/Tests/LibSQL/TestSqlExpressionParser.cpp index c2a6b3bfd7..4cf58324f2 100644 --- a/Tests/LibSQL/TestSqlExpressionParser.cpp +++ b/Tests/LibSQL/TestSqlExpressionParser.cpp @@ -602,3 +602,10 @@ TEST_CASE(in_selection_expression) validate("15 IN (SELECT * FROM table)", false); validate("15 NOT IN (SELECT * FROM table)", true); } + +TEST_CASE(stack_limit) +{ + auto too_deep_expression = String::formatted("{:+^{}}1", "", SQL::Limits::maximum_expression_tree_depth); + EXPECT(!parse(too_deep_expression.substring_view(1)).is_error()); + EXPECT(parse(too_deep_expression).is_error()); +} diff --git a/Userland/Libraries/LibSQL/Parser.cpp b/Userland/Libraries/LibSQL/Parser.cpp index 26d3fac53f..d3de815094 100644 --- a/Userland/Libraries/LibSQL/Parser.cpp +++ b/Userland/Libraries/LibSQL/Parser.cpp @@ -352,6 +352,11 @@ RefPtr Parser::parse_common_table_expression_list() NonnullRefPtr Parser::parse_expression() { + if (++m_parser_state.m_current_expression_depth > Limits::maximum_expression_tree_depth) { + syntax_error(String::formatted("Exceeded maximum expression tree depth of {}", Limits::maximum_expression_tree_depth)); + return create_ast_node(); + } + // https://sqlite.org/lang_expr.html auto expression = parse_primary_expression(); @@ -362,6 +367,7 @@ NonnullRefPtr Parser::parse_expression() // FIXME: Parse 'function-name'. // FIXME: Parse 'raise-function'. + --m_parser_state.m_current_expression_depth; return expression; } diff --git a/Userland/Libraries/LibSQL/Parser.h b/Userland/Libraries/LibSQL/Parser.h index 74595a3b7e..e9f202514d 100644 --- a/Userland/Libraries/LibSQL/Parser.h +++ b/Userland/Libraries/LibSQL/Parser.h @@ -14,6 +14,11 @@ namespace SQL { +namespace Limits { +// https://www.sqlite.org/limits.html +constexpr size_t maximum_expression_tree_depth = 1000; +} + class Parser { struct Position { size_t line { 0 }; @@ -48,6 +53,7 @@ private: Lexer m_lexer; Token m_token; Vector m_errors; + size_t m_current_expression_depth { 0 }; }; NonnullRefPtr parse_statement();