File CVE-2022-32084.patch of Package mariadb.29762
From 49e14000eeb245ea27e9207d2f63cb0a28be1ca9 Mon Sep 17 00:00:00 2001
From: Oleg Smirnov <olernov@gmail.com>
Date: Sat, 18 Jun 2022 20:54:39 +0700
Subject: [PATCH] MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT
1. For INSERT..SELECT statements: don't include table/view the data
is inserted into in the list of leaf tables
2. Remove duplicated and dead code related to table_count
---
mysql-test/main/insert_select.result | 70 +++++++++++
mysql-test/main/insert_select.test | 54 ++++++++
mysql-test/main/view.result | 10 ++
mysql-test/main/view.test | 2 +
sql/sql_base.cc | 178 +++++++++++++++++++--------
sql/sql_insert.cc | 4 +-
sql/sql_select.cc | 4 -
sql/sql_select.h | 1 -
8 files changed, 264 insertions(+), 59 deletions(-)
Index: mariadb-10.2.44/sql/sql_base.cc
===================================================================
--- mariadb-10.2.44.orig/sql/sql_base.cc
+++ mariadb-10.2.44/sql/sql_base.cc
@@ -7309,46 +7309,118 @@ bool setup_fields(THD *thd, Ref_ptr_arra
DBUG_RETURN(MY_TEST(thd->is_error()));
}
+/*
+ make list of leaves for a single TABLE_LIST
+
+ SYNOPSIS
+ make_leaves_for_single_table()
+ thd Thread handler
+ leaves List of leaf tables to be filled
+ table TABLE_LIST object to process
+ full_table_list Whether to include tables from mergeable derived table/view
+*/
+void make_leaves_for_single_table(THD *thd, List<TABLE_LIST> &leaves,
+ TABLE_LIST *table, bool& full_table_list,
+ TABLE_LIST *boundary)
+{
+ if (table == boundary)
+ full_table_list= !full_table_list;
+ if (full_table_list && table->is_merged_derived())
+ {
+ SELECT_LEX *select_lex= table->get_single_select();
+ /*
+ It's safe to use select_lex->leaf_tables because all derived
+ tables/views were already prepared and has their leaf_tables
+ set properly.
+ */
+ make_leaves_list(thd, leaves, select_lex->get_table_list(),
+ full_table_list, boundary);
+ }
+ else
+ {
+ leaves.push_back(table, thd->mem_root);
+ }
+}
+
/*
make list of leaves of join table tree
SYNOPSIS
make_leaves_list()
- list pointer to pointer on list first element
- tables table list
- full_table_list whether to include tables from mergeable derived table/view.
- we need them for checks for INSERT/UPDATE statements only.
-
- RETURN pointer on pointer to next_leaf of last element
+ leaves List of leaf tables to be filled
+ tables Table list
+ full_table_list Whether to include tables from mergeable derived table/view.
+ We need them for checks for INSERT/UPDATE statements only.
*/
-void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
+void make_leaves_list(THD *thd, List<TABLE_LIST> &leaves, TABLE_LIST *tables,
bool full_table_list, TABLE_LIST *boundary)
{
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- if (table == boundary)
- full_table_list= !full_table_list;
- if (full_table_list && table->is_merged_derived())
- {
- SELECT_LEX *select_lex= table->get_single_select();
- /*
- It's safe to use select_lex->leaf_tables because all derived
- tables/views were already prepared and has their leaf_tables
- set properly.
- */
- make_leaves_list(thd, list, select_lex->get_table_list(),
- full_table_list, boundary);
- }
- else
- {
- list.push_back(table, thd->mem_root);
- }
+ make_leaves_for_single_table(thd, leaves, table, full_table_list,
+ boundary);
}
}
+
+/*
+ Setup the map and other attributes for a single TABLE_LIST object
+
+ SYNOPSIS
+ setup_table_attributes()
+ thd Thread handler
+ table_list TABLE_LIST object to process
+ first_select_table First table participating in SELECT for INSERT..SELECT
+ statements, NULL for other cases
+ tablenr Serial number of the table in the SQL statement
+
+ RETURN
+ false Success
+ true Failure
+*/
+bool setup_table_attributes(THD *thd, TABLE_LIST *table_list,
+ TABLE_LIST *first_select_table,
+ uint &tablenr)
+{
+ TABLE *table= table_list->table;
+ if (table)
+ table->pos_in_table_list= table_list;
+ if (first_select_table && table_list->top_table() == first_select_table)
+ {
+ /* new counting for SELECT of INSERT ... SELECT command */
+ first_select_table= 0;
+ thd->lex->select_lex.insert_tables= tablenr;
+ tablenr= 0;
+ }
+ if (table_list->jtbm_subselect)
+ {
+ table_list->jtbm_table_no= tablenr;
+ }
+ else if (table)
+ {
+ table->pos_in_table_list= table_list;
+ setup_table_map(table, table_list, tablenr);
+
+ if (table_list->process_index_hints(table))
+ return true;
+ }
+ tablenr++;
+ /*
+ We test the max tables here as we setup_table_map() should not be called
+ with tablenr >= 64
+ */
+ if (tablenr > MAX_TABLES)
+ {
+ my_error(ER_TOO_MANY_TABLES, MYF(0), static_cast<int>(MAX_TABLES));
+ return true;
+ }
+ return false;
+}
+
+
/*
prepare tables
@@ -7405,7 +7477,14 @@ bool setup_tables(THD *thd, Name_resolut
leaves.empty();
if (select_lex->prep_leaf_list_state != SELECT_LEX::SAVED)
{
- make_leaves_list(thd, leaves, tables, full_table_list, first_select_table);
+ /*
+ For INSERT ... SELECT statements we must not include the first table
+ (where the data is being inserted into) in the list of leaves
+ */
+ TABLE_LIST *tables_for_leaves=
+ select_insert ? first_select_table : tables;
+ make_leaves_list(thd, leaves, tables_for_leaves, full_table_list,
+ first_select_table);
select_lex->prep_leaf_list_state= SELECT_LEX::READY;
select_lex->leaf_tables_exec.empty();
}
@@ -7416,37 +7495,34 @@ bool setup_tables(THD *thd, Name_resolut
leaves.push_back(table_list, thd->mem_root);
}
+ List_iterator<TABLE_LIST> ti(leaves);
while ((table_list= ti++))
{
- TABLE *table= table_list->table;
- if (table)
- table->pos_in_table_list= table_list;
- if (first_select_table &&
- table_list->top_table() == first_select_table)
- {
- /* new counting for SELECT of INSERT ... SELECT command */
- first_select_table= 0;
- thd->lex->select_lex.insert_tables= tablenr;
- tablenr= 0;
- }
- if(table_list->jtbm_subselect)
- {
- table_list->jtbm_table_no= tablenr;
- }
- else if (table)
- {
- table->pos_in_table_list= table_list;
- setup_table_map(table, table_list, tablenr);
+ if (setup_table_attributes(thd, table_list, first_select_table, tablenr))
+ DBUG_RETURN(1);
+ }
+
+ if (select_insert)
+ {
+ /*
+ The table/view in which the data is inserted must not be included into
+ the leaf_tables list. But we need this table/view to setup attributes
+ for it. So build a temporary list of leaves and setup attributes for
+ the tables included
+ */
+ List<TABLE_LIST> leaves;
+ TABLE_LIST *table= tables;
- if (table_list->process_index_hints(table))
+ make_leaves_for_single_table(thd, leaves, table, full_table_list,
+ first_select_table);
+
+ List_iterator<TABLE_LIST> ti(leaves);
+ while ((table_list= ti++))
+ {
+ if (setup_table_attributes(thd, table_list, first_select_table,
+ tablenr))
DBUG_RETURN(1);
}
- tablenr++;
- }
- if (tablenr > MAX_TABLES)
- {
- my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES));
- DBUG_RETURN(1);
}
}
else
Index: mariadb-10.2.44/sql/sql_insert.cc
===================================================================
--- mariadb-10.2.44.orig/sql/sql_insert.cc
+++ mariadb-10.2.44/sql/sql_insert.cc
@@ -1419,8 +1419,7 @@ static bool mysql_prepare_insert_check_t
if (insert_into_view && !fields.elements)
{
thd->lex->empty_field_list_on_rset= 1;
- if (!thd->lex->select_lex.leaf_tables.head()->table ||
- table_list->is_multitable())
+ if (!table_list->table || table_list->is_multitable())
{
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
table_list->view_db.str, table_list->view_name.str);
@@ -3537,7 +3536,6 @@ bool mysql_insert_select_prepare(THD *th
&select_lex->where, TRUE))
DBUG_RETURN(TRUE);
- DBUG_ASSERT(select_lex->leaf_tables.elements != 0);
List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
TABLE_LIST *table;
uint insert_tables;
Index: mariadb-10.2.44/sql/sql_select.cc
===================================================================
--- mariadb-10.2.44.orig/sql/sql_select.cc
+++ mariadb-10.2.44/sql/sql_select.cc
@@ -1237,7 +1237,6 @@ JOIN::optimize_inner()
/* Merge all mergeable derived tables/views in this SELECT. */
if (select_lex->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE);
- table_count= select_lex->leaf_tables.elements;
}
// Update used tables after all handling derived table procedures
select_lex->update_used_tables();
@@ -1275,8 +1274,6 @@ JOIN::optimize_inner()
eval_select_list_used_tables();
- table_count= select_lex->leaf_tables.elements;
-
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
@@ -12381,7 +12378,6 @@ void JOIN::cleanup(bool full)
/* Free the original optimized join created for the group_by_handler */
join_tab= original_join_tab;
original_join_tab= 0;
- table_count= original_table_count;
}
if (join_tab)
Index: mariadb-10.2.44/sql/sql_select.h
===================================================================
--- mariadb-10.2.44.orig/sql/sql_select.h
+++ mariadb-10.2.44/sql/sql_select.h
@@ -1178,7 +1178,6 @@ public:
Pushdown_query *pushdown_query;
JOIN_TAB *original_join_tab;
- uint original_table_count;
/******* Join optimization state members start *******/
/*