mariadb: fix CVE-2023-52969 and CVE-2023-52970

CVE-2023-52969:
MariaDB Server 10.4 through 10.5., 10.6 through 10.6., 10.7
through 10.11., and 11.0 through 11.0. can sometimes crash
with an empty backtrace log. This may be related to
make_aggr_tables_info and optimize_stage2.

CVE-2023-52970:
MariaDB Server 10.4 through 10.5., 10.6 through 10.6., 10.7
through 10.11., 11.0 through 11.0., and 11.1 through 11.4.*
crashes in Item_direct_view_ref::derived_field_transformer_for_where.

CVE-2023-52969-CVE-20230-52970-0001 and CVE-2023-52969-CVE-20230-52970-0002
are dependent commits while CVE-2023-52969-CVE-20230-52970-0003 and
CVE-2023-52969-CVE-20230-52970-0004 are actual CVE fixes.

References:
https://nvd.nist.gov/vuln/detail/CVE-2023-52969
https://nvd.nist.gov/vuln/detail/CVE-2023-52970

Upstream patches:
e640373389
https://github.com/MariaDB/server/commit/d98ac8511e39770ef3d8b42937c84e876d1459e
9b313d2de1
4fc9dc84b0

Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
This commit is contained in:
Yogita Urade
2025-06-25 13:03:12 +05:30
committed by Armin Kuster
parent c2140f3f2a
commit 5bc652be7a
5 changed files with 2929 additions and 0 deletions

View File

@@ -24,6 +24,10 @@ SRC_URI = "https://archive.mariadb.org/${BP}/source/${BP}.tar.gz \
file://0001-MDEV-29644-a-potential-bug-of-null-pointer-dereferen.patch \
file://CVE-2023-22084.patch \
file://CVE-2023-52968.patch \
file://CVE-2023-52969-CVE-20230-52970-0001.patch \
file://CVE-2023-52969-CVE-20230-52970-0002.patch \
file://CVE-2023-52969-CVE-20230-52970-0003.patch \
file://CVE-2023-52969-CVE-20230-52970-0004.patch \
"
SRC_URI:append:libc-musl = " file://ppc-remove-glibc-dep.patch"

View File

@@ -0,0 +1,502 @@
From e6403733897483bed249875f0f3e5e9937ca2b38 Mon Sep 17 00:00:00 2001
From: Oleg Smirnov <olernov@gmail.com>
Date: Fri, 25 Oct 2024 14:35:22 +0700
Subject: [PATCH] Revert "MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT"
This reverts commit 49e14000eeb245ea27e9207d2f63cb0a28be1ca9
as it introduces regression MDEV-29935 and has to be reconsidered
in general
CVE: CVE-2023-52969 and CVE-2023-52970
Upstream-Status: Backport [https://github.com/MariaDB/server/commit/e6403733897483bed249875f0f3e5e9937ca2b38]
Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
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, 59 insertions(+), 264 deletions(-)
diff --git a/mysql-test/main/insert_select.result b/mysql-test/main/insert_select.result
index 29618c6d..10c87271 100644
--- a/mysql-test/main/insert_select.result
+++ b/mysql-test/main/insert_select.result
@@ -883,76 +883,6 @@ INSERT INTO t1 SELECT a*2 FROM t1 ORDER BY a;
Warnings:
Warning 1264 Out of range value for column 'a' at row 4
DROP TABLE t1;
-CREATE TABLE t1 (a INT, b INT);
-INSERT INTO t1 (a) SELECT SUM(1);
-INSERT INTO t1 (a, b) SELECT AVG(2), MIN(3);
-INSERT INTO t1 (b) SELECT AVG('x') OVER ();
-ERROR 22007: Truncated incorrect DOUBLE value: 'x'
-INSERT INTO t1 SELECT MIN(7) OVER (), MAX(8) OVER();
-SELECT * FROM t1;
-a b
-1 NULL
-2 3
-7 8
-PREPARE stmt FROM 'INSERT INTO t1 (a) SELECT AVG(?)';
-EXECUTE stmt USING 9;
-EXECUTE stmt USING 10;
-PREPARE stmt FROM 'INSERT INTO t1 SELECT MIN(?), MAX(?)';
-EXECUTE stmt USING 11, 12;
-EXECUTE stmt USING 13, 14;
-DEALLOCATE PREPARE stmt;
-SELECT * FROM t1;
-a b
-1 NULL
-2 3
-7 8
-9 NULL
-10 NULL
-11 12
-13 14
-CREATE PROCEDURE p1(param_a INT, param_b INT)
-BEGIN
-INSERT INTO t1 SELECT MIN(param_a) OVER (), MAX(param_b);
-END//
-CALL p1(21, 22);
-CALL p1(23, 24);
-SELECT * FROM t1;
-a b
-1 NULL
-2 3
-7 8
-9 NULL
-10 NULL
-11 12
-13 14
-21 22
-23 24
-CREATE TABLE t2 (
-a DECIMAL UNIQUE CHECK (CASE 0 * 27302337.000000 WHEN 34 THEN
-+ 'x' LIKE 'x' OR a NOT IN (-1 / TRUE ^ 2) ELSE 7105743.000000 END));
-INSERT INTO t2 VALUES (90),( -1),(31152443.000000),(-32768),(NULL),(NULL);
-INSERT INTO t2 SELECT AVG('x') OVER (
-PARTITION BY ((NOT AVG(76698761.000000))) IS NOT NULL);
-ERROR 22007: Truncated incorrect DOUBLE value: 'x'
-INSERT IGNORE INTO t2 () VALUES (0),('x'),(3751286.000000),
-('x'),((a = 'x' AND 0 AND 0));
-Warnings:
-Warning 1366 Incorrect decimal value: 'x' for column `test`.`t2`.`a` at row 2
-Warning 1062 Duplicate entry '0' for key 'a'
-Warning 1366 Incorrect decimal value: 'x' for column `test`.`t2`.`a` at row 4
-Warning 1062 Duplicate entry '0' for key 'a'
-Warning 1062 Duplicate entry '0' for key 'a'
-INSERT INTO t2 VALUES (127);
-INSERT INTO t2 SELECT -2147483648 END FROM t2 AS TEXT JOIN t2 JOIN t2 TABLES;
-ERROR 23000: Duplicate entry '-2147483648' for key 'a'
-ALTER TABLE t2 ADD (
-b INT UNIQUE CHECK ((a = 'x' AND ((-(+(BINARY 49730460.000000)))) = 'x'
-BETWEEN 'x' AND 'x')));
-ERROR 22007: Truncated incorrect DECIMAL value: 'x'
-UPDATE t2 SET a = -128 WHERE a IS NULL ORDER BY 78 IN ('x','x'),a;
-ERROR 23000: Duplicate entry '-128' for key 'a'
-DROP TABLE t1, t2;
-DROP PROCEDURE p1;
# End of 10.2 test
#
# MDEV-28617: INSERT ... SELECT with redundant IN subquery in GROUP BY
diff --git a/mysql-test/main/insert_select.test b/mysql-test/main/insert_select.test
index a3604e38..7417bab9 100644
--- a/mysql-test/main/insert_select.test
+++ b/mysql-test/main/insert_select.test
@@ -459,60 +459,6 @@ INSERT INTO t1 SELECT a*2 FROM t1 ORDER BY a;
DROP TABLE t1;
-#
-# MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT
-#
-CREATE TABLE t1 (a INT, b INT);
-INSERT INTO t1 (a) SELECT SUM(1);
-INSERT INTO t1 (a, b) SELECT AVG(2), MIN(3);
-
---error ER_TRUNCATED_WRONG_VALUE
-INSERT INTO t1 (b) SELECT AVG('x') OVER ();
-INSERT INTO t1 SELECT MIN(7) OVER (), MAX(8) OVER();
-SELECT * FROM t1;
-
-PREPARE stmt FROM 'INSERT INTO t1 (a) SELECT AVG(?)';
-EXECUTE stmt USING 9;
-EXECUTE stmt USING 10;
-
-PREPARE stmt FROM 'INSERT INTO t1 SELECT MIN(?), MAX(?)';
-EXECUTE stmt USING 11, 12;
-EXECUTE stmt USING 13, 14;
-DEALLOCATE PREPARE stmt;
-SELECT * FROM t1;
-
-DELIMITER //;
-CREATE PROCEDURE p1(param_a INT, param_b INT)
-BEGIN
-INSERT INTO t1 SELECT MIN(param_a) OVER (), MAX(param_b);
-END//
-DELIMITER ;//
-CALL p1(21, 22);
-CALL p1(23, 24);
-SELECT * FROM t1;
-
-CREATE TABLE t2 (
- a DECIMAL UNIQUE CHECK (CASE 0 * 27302337.000000 WHEN 34 THEN
- + 'x' LIKE 'x' OR a NOT IN (-1 / TRUE ^ 2) ELSE 7105743.000000 END));
-INSERT INTO t2 VALUES (90),( -1),(31152443.000000),(-32768),(NULL),(NULL);
---error ER_TRUNCATED_WRONG_VALUE
-INSERT INTO t2 SELECT AVG('x') OVER (
- PARTITION BY ((NOT AVG(76698761.000000))) IS NOT NULL);
-INSERT IGNORE INTO t2 () VALUES (0),('x'),(3751286.000000),
- ('x'),((a = 'x' AND 0 AND 0));
-INSERT INTO t2 VALUES (127);
---error ER_DUP_ENTRY
-INSERT INTO t2 SELECT -2147483648 END FROM t2 AS TEXT JOIN t2 JOIN t2 TABLES;
---error ER_TRUNCATED_WRONG_VALUE
-ALTER TABLE t2 ADD (
- b INT UNIQUE CHECK ((a = 'x' AND ((-(+(BINARY 49730460.000000)))) = 'x'
- BETWEEN 'x' AND 'x')));
---error ER_DUP_ENTRY
-UPDATE t2 SET a = -128 WHERE a IS NULL ORDER BY 78 IN ('x','x'),a;
-
-DROP TABLE t1, t2;
-DROP PROCEDURE p1;
-
--echo # End of 10.2 test
--echo #
diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result
index aec4a5d0..69e850cd 100644
--- a/mysql-test/main/view.result
+++ b/mysql-test/main/view.result
@@ -1503,8 +1503,6 @@ execute stmt1 using @a;
set @a= 301;
execute stmt1 using @a;
deallocate prepare stmt1;
-insert into v3(a) select sum(302);
-insert into v3(a) select sum(303) over ();
select * from v3;
a b
100 0
@@ -1523,14 +1521,6 @@ a b
301 10
301 1000
301 2000
-302 0
-302 10
-302 1000
-302 2000
-303 0
-303 10
-303 1000
-303 2000
drop view v3;
drop tables t1,t2;
create table t1(f1 int);
diff --git a/mysql-test/main/view.test b/mysql-test/main/view.test
index c6cc9a69..f32b148b 100644
--- a/mysql-test/main/view.test
+++ b/mysql-test/main/view.test
@@ -1334,8 +1334,6 @@ execute stmt1 using @a;
set @a= 301;
execute stmt1 using @a;
deallocate prepare stmt1;
-insert into v3(a) select sum(302);
-insert into v3(a) select sum(303) over ();
--sorted_result
select * from v3;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 4142540f..59c13009 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7750,39 +7750,6 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
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);
- }
-}
-
/*
Perform checks like all given fields exists, if exists fill struct with
@@ -7809,79 +7776,40 @@ int setup_returning_fields(THD* thd, TABLE_LIST* table_list)
SYNOPSIS
make_leaves_list()
- 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.
+ 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
*/
-void make_leaves_list(THD *thd, List<TABLE_LIST> &leaves, TABLE_LIST *tables,
+void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
bool full_table_list, TABLE_LIST *boundary)
{
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
- 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->first_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;
+ 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);
+ }
}
- return false;
}
-
/*
prepare tables
@@ -7938,14 +7866,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
leaves.empty();
if (select_lex->prep_leaf_list_state != SELECT_LEX::SAVED)
{
- /*
- 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);
+ make_leaves_list(thd, leaves, tables, full_table_list, first_select_table);
select_lex->prep_leaf_list_state= SELECT_LEX::READY;
select_lex->leaf_tables_exec.empty();
}
@@ -7956,34 +7877,37 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
leaves.push_back(table_list, thd->mem_root);
}
- List_iterator<TABLE_LIST> ti(leaves);
while ((table_list= ti++))
{
- 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;
-
- make_leaves_for_single_table(thd, leaves, table, full_table_list,
- first_select_table);
-
- 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)
{
- if (setup_table_attributes(thd, table_list, first_select_table,
- tablenr))
+ /* new counting for SELECT of INSERT ... SELECT command */
+ first_select_table= 0;
+ thd->lex->first_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))
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
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index af2c4606..460c552f 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1570,7 +1570,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
if (insert_into_view && !fields.elements)
{
thd->lex->empty_field_list_on_rset= 1;
- if (!table_list->table || table_list->is_multitable())
+ if (!thd->lex->first_select_lex()->leaf_tables.head()->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);
@@ -3828,6 +3829,7 @@ int mysql_insert_select_prepare(THD *thd, select_result *sel_res)
if (sel_res)
sel_res->prepare(lex->returning()->item_list, NULL);
+ DBUG_ASSERT(select_lex->leaf_tables.elements != 0);
List_iterator<TABLE_LIST> ti(select_lex->leaf_tables);
TABLE_LIST *table;
uint insert_tables;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 21cc4806..8a7060c3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2037,6 +2037,7 @@ 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;
}
if (select_lex->first_cond_optimization &&
@@ -2084,6 +2085,8 @@ JOIN::optimize_inner()
eval_select_list_used_tables();
+ table_count= select_lex->leaf_tables.elements;
+
if (select_lex->options & OPTION_SCHEMA_TABLE &&
optimize_schema_tables_memory_usage(select_lex->leaf_tables))
DBUG_RETURN(1);
@@ -14549,6 +14552,7 @@ 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)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 6efdcafd..e1e06e73 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1291,6 +1291,7 @@ class JOIN :public Sql_alloc
Pushdown_query *pushdown_query;
JOIN_TAB *original_join_tab;
+ uint original_table_count;
/******* Join optimization state members start *******/
/*
--
2.40.0

View File

@@ -0,0 +1,168 @@
From d98ac8511e39770ef3d8b42937c84e876d1459e7 Mon Sep 17 00:00:00 2001
From: Oleg Smirnov <olernov@gmail.com>
Date: Sat, 26 Oct 2024 20:29:56 +0700
Subject: [PATCH] MDEV-26247 MariaDB Server SEGV on INSERT .. SELECT
This problem occured for statements like `INSERT INTO t1 SELECT 1`,
which do not have tables in the SELECT part. In such scenarios
SELECT_LEX::insert_tables was not properly set at `setup_tables()`,
and this led to either incorrect execution or a crash
Reviewer: Oleksandr Byelkin <sanja@mariadb.com>
CVE: CVE-2023-52969 and CVE-2023-52970
Upstream-Status: Backport [https://github.com/MariaDB/server/commit/d98ac8511e39770ef3d8b42937c84e876d1459e7]
Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
mysql-test/main/insert_select.result | 49 ++++++++++++++++++++++++++++
mysql-test/main/insert_select.test | 35 ++++++++++++++++++++
sql/sql_base.cc | 16 +++++++--
3 files changed, 97 insertions(+), 3 deletions(-)
diff --git a/mysql-test/main/insert_select.result b/mysql-test/main/insert_select.result
index 10c87271..79f8c519 100644
--- a/mysql-test/main/insert_select.result
+++ b/mysql-test/main/insert_select.result
@@ -986,3 +986,52 @@ drop table t1, t2;
#
# End of 10.3 test
#
+#
+# MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT
+#
+CREATE TABLE t1 (a int);
+INSERT INTO t1 SELECT AVG(1);
+SELECT * FROM t1;
+a
+1
+INSERT INTO t1 SELECT MIN(2) OVER ();
+SELECT * FROM t1;
+a
+1
+2
+CREATE VIEW v1 AS SELECT * FROM t1 ORDER BY a;
+INSERT INTO v1 SELECT SUM(3);
+SELECT * FROM v1;
+a
+1
+2
+3
+INSERT INTO v1 SELECT * FROM v1;
+SELECT * FROM t1;
+a
+1
+1
+2
+2
+3
+3
+INSERT INTO t1 SELECT * FROM v1;
+SELECT * FROM t1;
+a
+1
+1
+1
+1
+2
+2
+2
+2
+3
+3
+3
+3
+DROP VIEW v1;
+DROP TABLE t1;
+#
+# End of 10.5 test
+#
diff --git a/mysql-test/main/insert_select.test b/mysql-test/main/insert_select.test
index 7417bab9..0e9bd05a 100644
--- a/mysql-test/main/insert_select.test
+++ b/mysql-test/main/insert_select.test
@@ -559,3 +559,38 @@ drop table t1, t2;
--echo #
--echo # End of 10.3 test
--echo #
+
+--echo #
+--echo # MDEV-26427 MariaDB Server SEGV on INSERT .. SELECT
+--echo #
+
+CREATE TABLE t1 (a int);
+
+INSERT INTO t1 SELECT AVG(1);
+--sorted_result
+SELECT * FROM t1;
+
+INSERT INTO t1 SELECT MIN(2) OVER ();
+--sorted_result
+SELECT * FROM t1;
+
+CREATE VIEW v1 AS SELECT * FROM t1 ORDER BY a;
+
+INSERT INTO v1 SELECT SUM(3);
+--sorted_result
+SELECT * FROM v1;
+
+INSERT INTO v1 SELECT * FROM v1;
+--sorted_result
+SELECT * FROM t1;
+
+INSERT INTO t1 SELECT * FROM v1;
+--sorted_result
+SELECT * FROM t1;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo #
+--echo # End of 10.5 test
+--echo #
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 4f04f23d..d50f3407 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7876,18 +7876,19 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
while ((table_list= ti++))
leaves.push_back(table_list, thd->mem_root);
}
-
+
+ bool is_insert_tables_num_set= false;
while ((table_list= ti++))
{
TABLE *table= table_list->table;
if (table)
table->pos_in_table_list= table_list;
- if (first_select_table &&
+ if (select_insert && !is_insert_tables_num_set &&
table_list->top_table() == first_select_table)
{
/* new counting for SELECT of INSERT ... SELECT command */
- first_select_table= 0;
thd->lex->first_select_lex()->insert_tables= tablenr;
+ is_insert_tables_num_set= true;
tablenr= 0;
}
if(table_list->jtbm_subselect)
@@ -7909,6 +7910,15 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES));
DBUG_RETURN(1);
}
+ if (select_insert && !is_insert_tables_num_set)
+ {
+ /*
+ This happens for statements like `INSERT INTO t1 SELECT 1`,
+ when there are no tables in the SELECT part.
+ In this case all leaf tables belong to the INSERT part
+ */
+ thd->lex->first_select_lex()->insert_tables= tablenr;
+ }
}
else
{
--
2.40.0

View File

@@ -0,0 +1,470 @@
From 9b313d2de1df65626abb3b1d6c973f74addb12fb Mon Sep 17 00:00:00 2001
From: Oleksandr Byelkin <sanja@mariadb.com>
Date: Tue, 1 Apr 2025 20:57:29 +0200
Subject: [PATCH] MDEV-32086 Server crash when inserting from derived table
containing insert target table
Use original solution for INSERT ... SELECT - select result buferisation.
Also fix MDEV-36447 and MDEV-33139
CVE: CVE-2023-52969 and CVE-2023-52970
Upstream-Status: Backport [https://github.com/MariaDB/server/commit/9b313d2de1df65626abb3b1d6c973f74addb12fb]
Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
---
mysql-test/main/derived_cond_pushdown.result | 125 ++++++++----------
mysql-test/main/derived_view.result | 2 +
mysql-test/main/insert_select.result | 129 ++++++++++++++++++-
mysql-test/main/insert_select.test | 56 +++++++-
sql/sql_base.cc | 15 ++-
sql/sql_base.h | 1 +
sql/sql_insert.cc | 11 +-
7 files changed, 260 insertions(+), 79 deletions(-)
diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result
index f47920c0..9eac511e 100644
--- a/mysql-test/main/derived_cond_pushdown.result
+++ b/mysql-test/main/derived_cond_pushdown.result
@@ -10223,9 +10223,8 @@ SELECT * FROM ( SELECT t1.f FROM v1 JOIN t1 ) AS t WHERE f IS NOT NULL;
EXPLAIN INSERT INTO t1
SELECT * FROM ( SELECT t1.f FROM v1 JOIN t1 ) AS t WHERE f IS NOT NULL;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY <derived2> ALL NULL NULL NULL NULL 144 Using where
-2 DERIVED <derived4> ALL NULL NULL NULL NULL 12
-2 DERIVED t1 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
+1 PRIMARY <derived4> ALL NULL NULL NULL NULL 12 Using temporary
+1 PRIMARY t1 ALL NULL NULL NULL NULL 12 Using where; Using join buffer (flat, BNL join)
4 DERIVED t1 ALL NULL NULL NULL NULL 12
EXPLAIN FORMAT=JSON INSERT INTO t1
SELECT * FROM ( SELECT t1.f FROM v1 JOIN t1 ) AS t WHERE f IS NOT NULL;
@@ -10233,45 +10232,35 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
- "table": {
- "table_name": "<derived2>",
- "access_type": "ALL",
- "rows": 144,
- "filtered": 100,
- "attached_condition": "t.f is not null",
- "materialized": {
- "query_block": {
- "select_id": 2,
- "table": {
- "table_name": "<derived4>",
- "access_type": "ALL",
- "rows": 12,
- "filtered": 100,
- "materialized": {
- "query_block": {
- "select_id": 4,
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 12,
- "filtered": 100
- }
- }
- }
- },
- "block-nl-join": {
+ "temporary_table": {
+ "table": {
+ "table_name": "<derived4>",
+ "access_type": "ALL",
+ "rows": 12,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 4,
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 12,
- "filtered": 100,
- "attached_condition": "t1.f is not null"
- },
- "buffer_type": "flat",
- "buffer_size": "64",
- "join_type": "BNL"
+ "filtered": 100
+ }
}
}
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 12,
+ "filtered": 100,
+ "attached_condition": "t1.f is not null"
+ },
+ "buffer_type": "flat",
+ "buffer_size": "64",
+ "join_type": "BNL"
}
}
}
@@ -10302,43 +10291,33 @@ EXPLAIN
{
"query_block": {
"select_id": 1,
- "table": {
- "table_name": "<derived2>",
- "access_type": "ALL",
- "rows": 16,
- "filtered": 100,
- "attached_condition": "t.f is not null",
- "materialized": {
- "query_block": {
- "select_id": 2,
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 8,
- "filtered": 100,
- "attached_condition": "t1.f is not null"
- },
- "table": {
- "table_name": "<derived4>",
- "access_type": "ref",
- "possible_keys": ["key0"],
- "key": "key0",
- "key_length": "4",
- "used_key_parts": ["f"],
- "ref": ["test.t1.f"],
- "rows": 2,
- "filtered": 100,
- "materialized": {
- "query_block": {
- "select_id": 4,
- "table": {
- "table_name": "t1",
- "access_type": "ALL",
- "rows": 8,
- "filtered": 100,
- "attached_condition": "t1.f is not null"
- }
- }
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 8,
+ "filtered": 100,
+ "attached_condition": "t1.f is not null"
+ },
+ "table": {
+ "table_name": "<derived4>",
+ "access_type": "ref",
+ "possible_keys": ["key0"],
+ "key": "key0",
+ "key_length": "4",
+ "used_key_parts": ["f"],
+ "ref": ["test.t1.f"],
+ "rows": 2,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "select_id": 4,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 8,
+ "filtered": 100,
+ "attached_condition": "t1.f is not null"
}
}
}
diff --git a/mysql-test/main/derived_view.result b/mysql-test/main/derived_view.result
index 15a7784c..3df1acc6 100644
--- a/mysql-test/main/derived_view.result
+++ b/mysql-test/main/derived_view.result
@@ -2383,6 +2383,8 @@ SELECT * FROM t1;
a
1
1
+1
+1
drop table t1,t2;
set optimizer_switch=@save968720_optimizer_switch;
#
diff --git a/mysql-test/main/insert_select.result b/mysql-test/main/insert_select.result
index 79f8c519..ceb2fb8f 100644
--- a/mysql-test/main/insert_select.result
+++ b/mysql-test/main/insert_select.result
@@ -1032,6 +1032,133 @@ a
3
DROP VIEW v1;
DROP TABLE t1;
+create table t1 (pk int, id int);
+insert into t1 values (2,2), (3,3), (4,4);
+insert into t1
+select 1,10
+from
+(
+select dt2.id from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id=3;
+select * from t1;
+pk id
+2 2
+3 3
+4 4
+1 10
+explain insert into t1
+select 1,10
+from
+(
+select dt2.id from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where; Using temporary
+1 SIMPLE t ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join)
+explain format=json insert into t1
+select 1,10
+from
+(
+select dt2.id from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id=3;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t1.`id` = 3"
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100,
+ "attached_condition": "t.`id` = 3"
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ }
+}
+prepare stmt from "insert into t1
+select 1,10
+from
+(
+select dt2.id from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id=3";
+execute stmt;
+select * from t1;
+pk id
+2 2
+3 3
+4 4
+1 10
+1 10
+execute stmt;
+select * from t1;
+pk id
+2 2
+3 3
+4 4
+1 10
+1 10
+1 10
+deallocate prepare stmt;
+create procedure p() insert into t1
+select 1,10
+from
+(
+select dt2.id from (select id from t1) dt2, t1 t where t.id=dt2.id
+) dt
+where dt.id=3;
+call p();
+select * from t1;
+pk id
+2 2
+3 3
+4 4
+1 10
+1 10
+1 10
+1 10
+call p();
+select * from t1;
+pk id
+2 2
+3 3
+4 4
+1 10
+1 10
+1 10
+1 10
+1 10
+drop procedure p;
+drop table t1;
#
-# End of 10.5 test
+# MDEV-33139: Crash of INSERT SELECT when preparing structures for
+# split optimization
#
+CREATE TABLE v0 ( v1 INT UNIQUE ) ;
+INSERT INTO v0 ( v1 ) VALUES
+( ( SELECT
+FROM
+( SELECT v1
+FROM v0 GROUP BY v1 ) AS v6 NATURAL JOIN
+v0 AS v2 NATURAL JOIN
+v0 AS v4 NATURAL JOIN
+v0 AS v3 NATURAL JOIN
+( SELECT v1 FROM v0 ) AS v7 ) ) ;
+DROP TABLE v0;
+# End of 10.5 tests
diff --git a/mysql-test/main/insert_select.test b/mysql-test/main/insert_select.test
index 0e9bd05a..5c2691c9 100644
--- a/mysql-test/main/insert_select.test
+++ b/mysql-test/main/insert_select.test
@@ -591,6 +591,60 @@ SELECT * FROM t1;
DROP VIEW v1;
DROP TABLE t1;
+#
+# MDEV-32086: condition pushdown into two mergeable derived tables,
+# one containing the other, when they are forced to be
+# materialized in INSERT
+#
+create table t1 (pk int, id int);
+insert into t1 values (2,2), (3,3), (4,4);
+
+let $q=
+insert into t1
+ select 1,10
+ from
+ (
+ select dt2.id from (select id from t1) dt2, t1 t where t.id=dt2.id
+ ) dt
+ where dt.id=3;
+
+eval $q;
+select * from t1;
+
+eval explain $q;
+eval explain format=json $q;
+
+eval prepare stmt from "$q";
+execute stmt;
+select * from t1;
+execute stmt;
+select * from t1;
+deallocate prepare stmt;
+
+eval create procedure p() $q;
+call p();
+select * from t1;
+call p();
+select * from t1;
+drop procedure p;
+
+drop table t1;
+
--echo #
---echo # End of 10.5 test
+--echo # MDEV-33139: Crash of INSERT SELECT when preparing structures for
+--echo # split optimization
--echo #
+
+CREATE TABLE v0 ( v1 INT UNIQUE ) ;
+INSERT INTO v0 ( v1 ) VALUES
+ ( ( SELECT 1
+ FROM
+ ( SELECT v1
+ FROM v0 GROUP BY v1 ) AS v6 NATURAL JOIN
+ v0 AS v2 NATURAL JOIN
+ v0 AS v4 NATURAL JOIN
+ v0 AS v3 NATURAL JOIN
+ ( SELECT v1 FROM v0 ) AS v7 ) ) ;
+DROP TABLE v0;
+
+--echo # End of 10.5 tests
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d50f3407..15a9882b 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1176,11 +1176,20 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
DBUG_PRINT("info",
("found same copy of table or table which we should skip"));
}
- if (res && res->belong_to_derived)
+ /*
+ If we've found a duplicate in a derived table, try to work around that.
+
+ For INSERT...SELECT, do not do any workarounds, return the duplicate. The
+ caller will enable buffering to handle this.
+ */
+ if (res && res->belong_to_derived &&
+ !(check_flag & CHECK_DUP_FOR_INSERT_SELECT))
{
/*
- We come here for queries of type:
- INSERT INTO t1 (SELECT tmp.a FROM (select * FROM t1) as tmp);
+ We come here for queries like this:
+
+ INSERT INTO t1 VALUES ((SELECT tmp.a FROM (select * FROM t1)));
+ DELETE FROM t1 WHERE ( ... (SELECT ... FROM t1) ) ;
Try to fix by materializing the derived table
*/
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 5b449fdd..da9b1575 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -72,6 +72,7 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
#define CHECK_DUP_ALLOW_DIFFERENT_ALIAS 1
#define CHECK_DUP_FOR_CREATE 2
#define CHECK_DUP_SKIP_TEMP_TABLE 4
+#define CHECK_DUP_FOR_INSERT_SELECT 8
uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 50e3bcd3..d9813660 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1741,6 +1741,14 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(1);
}
+ /*
+ Check if we read from the same table we're inserting into.
+ Queries like INSERT INTO t1 VALUES ((SELECT ... FROM t1...)) are not
+ allowed.
+
+ INSERT...SELECT is an exception: it will detect this case and use
+ buffering to handle it correctly.
+ */
if (!select_insert)
{
Item *fake_conds= 0;
@@ -4021,7 +4029,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
Is table which we are changing used somewhere in other parts of
query
*/
- if (unique_table(thd, table_list, table_list->next_global, 0))
+ if (unique_table(thd, table_list, table_list->next_global,
+ CHECK_DUP_FOR_INSERT_SELECT))
{
/* Using same table for INSERT and SELECT */
lex->current_select->options|= OPTION_BUFFER_RESULT;
--
2.40.0

File diff suppressed because it is too large Load Diff