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 *******/
   /*
openSUSE Build Service is sponsored by