@@ -306,6 +306,13 @@ class WP_SQLite_Driver {
306306 */
307307 private $ last_sql_calc_found_rows = null ;
308308
309+ /**
310+ * Whether the current MySQL query is read-only.
311+ *
312+ * @var bool
313+ */
314+ private $ is_readonly ;
315+
309316 /**
310317 * Transaction nesting level of the executed SQLite queries.
311318 *
@@ -703,6 +710,7 @@ private function execute_mysql_query( WP_Parser_Node $node ): void {
703710 $ node = $ children [0 ]->get_first_child_node ();
704711 switch ( $ node ->rule_name ) {
705712 case 'selectStatement ' :
713+ $ this ->is_readonly = true ;
706714 $ this ->execute_select_statement ( $ node );
707715 break ;
708716 case 'insertStatement ' :
@@ -778,12 +786,14 @@ private function execute_mysql_query( WP_Parser_Node $node ): void {
778786 $ this ->last_result = 0 ;
779787 break ;
780788 case 'showStatement ' :
789+ $ this ->is_readonly = true ;
781790 $ this ->execute_show_statement ( $ node );
782791 break ;
783792 case 'utilityStatement ' :
784793 $ subtree = $ node ->get_first_child_node ();
785794 switch ( $ subtree ->rule_name ) {
786795 case 'describeStatement ' :
796+ $ this ->is_readonly = true ;
787797 $ this ->execute_describe_statement ( $ subtree );
788798 break ;
789799 case 'useCommand ' :
@@ -2084,6 +2094,24 @@ private function translate_qualified_identifier(
20842094 }
20852095 }
20862096
2097+ /*
2098+ * Make the 'information_schema' database read-only.
2099+ *
2100+ * This basic approach is rather restrictive, as it blocks the usage
2101+ * of information schema tables in all data-modifying statements.
2102+ *
2103+ * Some of these statements can be valid, when the schema is only read:
2104+ * DELETE t FROM t JOIN information_schema.columns c ON ...
2105+ *
2106+ * If needed, a more granular approach can be implemented in the future.
2107+ */
2108+ if ( true === $ is_information_schema && false === $ this ->is_readonly ) {
2109+ throw $ this ->new_driver_exception (
2110+ "Access denied for user 'sqlite'@'%' to database 'information_schema' " ,
2111+ '42000 '
2112+ );
2113+ }
2114+
20872115 // Database-level object name (table, view, procedure, trigger, etc.).
20882116 if ( null !== $ object_node ) {
20892117 if ( $ is_information_schema ) {
@@ -2937,6 +2965,7 @@ private function flush(): void {
29372965 $ this ->last_sqlite_queries = array ();
29382966 $ this ->last_result = null ;
29392967 $ this ->last_return_value = null ;
2968+ $ this ->is_readonly = false ;
29402969 }
29412970
29422971 /**
0 commit comments