From c7cd81bce83684124e5a4ae4eda873dd30ddb52b Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 8 Jun 2021 09:22:06 -0400 Subject: [PATCH] LibSQL: Limit the number of nested subqueries SQLite hasn't documented a limit on https://www.sqlite.org/limits.html for the maximum number of nested subqueries. However, its parser is generated with Yacc and has an internal limit of 100 for general nested statements. Fixes https://crbug.com/oss-fuzz/35022. --- Tests/LibSQL/TestSqlStatementParser.cpp | 7 +++++++ Userland/Libraries/LibSQL/Parser.cpp | 6 ++++++ Userland/Libraries/LibSQL/Parser.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/Tests/LibSQL/TestSqlStatementParser.cpp b/Tests/LibSQL/TestSqlStatementParser.cpp index bf262d4907e..259a9e091e0 100644 --- a/Tests/LibSQL/TestSqlStatementParser.cpp +++ b/Tests/LibSQL/TestSqlStatementParser.cpp @@ -738,3 +738,10 @@ TEST_CASE(common_table_expression) validate("WITH table (column1, column2) AS (SELECT * FROM table) DELETE FROM table;", { false, { { "table", { "column1", "column2" } } } }); validate("WITH RECURSIVE table AS (SELECT * FROM table) DELETE FROM table;", { true, { { "table", {} } } }); } + +TEST_CASE(nested_subquery_limit) +{ + auto subquery = String::formatted("{:(^{}}table{:)^{}}", "", SQL::Limits::maximum_subquery_depth - 1, "", SQL::Limits::maximum_subquery_depth - 1); + EXPECT(!parse(String::formatted("SELECT * FROM {};", subquery)).is_error()); + EXPECT(parse(String::formatted("SELECT * FROM ({});", subquery)).is_error()); +} diff --git a/Userland/Libraries/LibSQL/Parser.cpp b/Userland/Libraries/LibSQL/Parser.cpp index d3de8150942..5ee5d2538d3 100644 --- a/Userland/Libraries/LibSQL/Parser.cpp +++ b/Userland/Libraries/LibSQL/Parser.cpp @@ -5,6 +5,7 @@ */ #include "Parser.h" +#include #include namespace SQL { @@ -946,6 +947,11 @@ NonnullRefPtr Parser::parse_result_column() NonnullRefPtr Parser::parse_table_or_subquery() { + if (++m_parser_state.m_current_subquery_depth > Limits::maximum_subquery_depth) + syntax_error(String::formatted("Exceeded maximum subquery depth of {}", Limits::maximum_subquery_depth)); + + ScopeGuard guard([&]() { --m_parser_state.m_current_subquery_depth; }); + // https://sqlite.org/syntax/table-or-subquery.html if (match(TokenType::Identifier)) { String schema_name; diff --git a/Userland/Libraries/LibSQL/Parser.h b/Userland/Libraries/LibSQL/Parser.h index e9f202514dc..94fb0e6a048 100644 --- a/Userland/Libraries/LibSQL/Parser.h +++ b/Userland/Libraries/LibSQL/Parser.h @@ -17,6 +17,7 @@ namespace SQL { namespace Limits { // https://www.sqlite.org/limits.html constexpr size_t maximum_expression_tree_depth = 1000; +constexpr size_t maximum_subquery_depth = 100; } class Parser { @@ -54,6 +55,7 @@ private: Token m_token; Vector m_errors; size_t m_current_expression_depth { 0 }; + size_t m_current_subquery_depth { 0 }; }; NonnullRefPtr parse_statement();