From e06c0298497c8dcc2e803435e13c59b7c3d65ab1 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 15 May 2018 14:10:19 +0400 Subject: [PATCH] MDEV-15465 Server crash or ASAN heap-use-after-free in Item_func_match::cleanup upon using FT search with partitioning. Partition engine FT keys are implemented in such a way that the FT function's cleanup() methods use table's internals. So calling them after close_thread_tables is unsafe. --- mysql-test/main/partition_sync.result | 25 +++++++++++++++++++ mysql-test/main/partition_sync.test | 36 +++++++++++++++++++++++++++ sql/sql_base.cc | 13 ++++++++++ sql/sql_base.h | 1 + sql/sql_union.cc | 1 + 5 files changed, 76 insertions(+) diff --git a/mysql-test/main/partition_sync.result b/mysql-test/main/partition_sync.result index 18cc506e849..badcb10e5da 100644 --- a/mysql-test/main/partition_sync.result +++ b/mysql-test/main/partition_sync.result @@ -61,3 +61,28 @@ connection default; disconnect con2; disconnect con3; DROP TABLE tbl_with_partitions; +# +# MDEV-15465 Server crash or ASAN heap-use-after-free in Item_func_match::cleanup +# upon using FT search with partitioning. +# +connect con1,localhost,root,,test; +CREATE OR REPLACE TABLE t1 (c CHAR(8)) ENGINE=MyISAM PARTITION BY KEY(c); +connection default; +set debug_sync= 'execute_command_after_close_tables SIGNAL opened WAIT_FOR go'; +DELETE FROM t1 WHERE MATCH(c) AGAINST ('foo' IN BOOLEAN MODE); +connection con1; +set debug_sync= 'now WAIT_FOR opened'; +FLUSH TABLES; +set debug_sync= 'now SIGNAL go'; +connection default; +set debug_sync= 'execute_command_after_close_tables SIGNAL opened WAIT_FOR go'; +SELECT * FROM t1 WHERE MATCH(c) AGAINST ('foo' IN BOOLEAN MODE); +connection con1; +set debug_sync= 'now WAIT_FOR opened'; +FLUSH TABLES; +set debug_sync= 'now SIGNAL go'; +disconnect con1; +connection default; +c +DROP TABLE t1; +set debug_sync= 'RESET'; diff --git a/mysql-test/main/partition_sync.test b/mysql-test/main/partition_sync.test index fd704f35534..22ca7df7e62 100644 --- a/mysql-test/main/partition_sync.test +++ b/mysql-test/main/partition_sync.test @@ -77,6 +77,42 @@ disconnect con2; disconnect con3; DROP TABLE tbl_with_partitions; +--echo # +--echo # MDEV-15465 Server crash or ASAN heap-use-after-free in Item_func_match::cleanup +--echo # upon using FT search with partitioning. +--echo # + +--connect (con1,localhost,root,,test) +CREATE OR REPLACE TABLE t1 (c CHAR(8)) ENGINE=MyISAM PARTITION BY KEY(c); + +--connection default +set debug_sync= 'execute_command_after_close_tables SIGNAL opened WAIT_FOR go'; +--send +DELETE FROM t1 WHERE MATCH(c) AGAINST ('foo' IN BOOLEAN MODE); + +--connection con1 +set debug_sync= 'now WAIT_FOR opened'; +FLUSH TABLES; +set debug_sync= 'now SIGNAL go'; + +--connection default +--reap +set debug_sync= 'execute_command_after_close_tables SIGNAL opened WAIT_FOR go'; +--send +SELECT * FROM t1 WHERE MATCH(c) AGAINST ('foo' IN BOOLEAN MODE); + +--connection con1 +set debug_sync= 'now WAIT_FOR opened'; +FLUSH TABLES; +set debug_sync= 'now SIGNAL go'; + +# Cleanup +--disconnect con1 +--connection default +--reap +DROP TABLE t1; +set debug_sync= 'RESET'; + # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b6dab95774a..6c400bf6b25 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8639,6 +8639,19 @@ int setup_ftfuncs(SELECT_LEX *select_lex) } +void cleanup_ftfuncs(SELECT_LEX *select_lex) +{ + List_iterator li(*(select_lex->ftfunc_list)), + lj(*(select_lex->ftfunc_list)); + Item_func_match *ftf; + + while ((ftf=li++)) + { + ftf->cleanup(); + } +} + + int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) { if (select_lex->ftfunc_list->elements) diff --git a/sql/sql_base.h b/sql/sql_base.h index 8f6d406cb73..645a4a83fcb 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -216,6 +216,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, COND **conds); void wrap_ident(THD *thd, Item **conds); int setup_ftfuncs(SELECT_LEX* select); +void cleanup_ftfuncs(SELECT_LEX *select_lex); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); bool lock_table_names(THD *thd, const DDL_options_st &options, TABLE_LIST *table_list, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 971bb64cf2e..346b21c0a53 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1916,6 +1916,7 @@ bool st_select_lex::cleanup() cleanup_order(order_list.first); cleanup_order(group_list.first); + cleanup_ftfuncs(this); if (join) {