From d1eeb4b83932660f8c8170a861734076bb6af546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 24 Feb 2021 12:02:54 +0200 Subject: MDEV-24964 : Heap-buffer-overflow on wsrep_schema.cc ::remove_fragments Problem was that we used heap allocated key using too small array. Fixed by using dynamic memory allocation using actual needed size. --- sql/wsrep_schema.cc | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'sql/wsrep_schema.cc') diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index b2346aba508..e811d4e8317 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -566,14 +566,24 @@ static int end_index_scan(TABLE* table) { return 0; } -static void make_key(TABLE* table, uchar* key, key_part_map* map, int parts) { +static void make_key(TABLE* table, uchar** key, key_part_map* map, int parts) { uint prefix_length= 0; KEY_PART_INFO* key_part= table->key_info->key_part; + for (int i=0; i < parts; i++) prefix_length += key_part[i].store_length; + *map= make_prev_keypart_map(parts); - key_copy(key, table->record[0], table->key_info, prefix_length); + + if (!(*key= (uchar *) my_malloc(prefix_length + 1, MYF(MY_WME)))) + { + WSREP_ERROR("Failed to allocate memory for key prefix_length %u", prefix_length); + assert(0); + } + + key_copy(*key, table->record[0], table->key_info, prefix_length); } + } /* namespace Wsrep_schema_impl */ @@ -958,7 +968,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, Wsrep_schema_impl::binlog_off binlog_off(thd); int error; - uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + uchar *key=NULL; key_part_map key_map= 0; TABLE* frag_table= 0; @@ -973,7 +983,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id()); Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get()); Wsrep_schema_impl::store(frag_table, 2, -1); - Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3); + Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3); if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, key_map))) @@ -987,9 +997,11 @@ int Wsrep_schema::update_fragment_meta(THD* thd, } Wsrep_schema_impl::finish_stmt(thd); thd->lex->restore_backup_query_tables_list(&query_tables_list_backup); + my_free(key); DBUG_RETURN(1); } + my_free(key); /* Copy the original record to frag_table->record[1] */ store_record(frag_table, record[1]); @@ -1024,7 +1036,7 @@ static int remove_fragment(THD* thd, seqno.get()); int ret= 0; int error; - uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + uchar *key= NULL; key_part_map key_map= 0; DBUG_ASSERT(server_id.is_undefined() == false); @@ -1038,7 +1050,7 @@ static int remove_fragment(THD* thd, Wsrep_schema_impl::store(frag_table, 0, server_id); Wsrep_schema_impl::store(frag_table, 1, transaction_id.get()); Wsrep_schema_impl::store(frag_table, 2, seqno.get()); - Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3); + Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3); if ((error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, @@ -1060,6 +1072,8 @@ static int remove_fragment(THD* thd, ret= 1; } + if (key) + my_free(key); Wsrep_schema_impl::end_index_scan(frag_table); return ret; } @@ -1147,7 +1161,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, int ret= 1; int error; TABLE* frag_table= 0; - uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + uchar *key=NULL; key_part_map key_map= 0; for (std::vector::const_iterator i= fragments.begin(); @@ -1164,7 +1178,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, Wsrep_schema_impl::store(frag_table, 0, ws_meta.server_id()); Wsrep_schema_impl::store(frag_table, 1, ws_meta.transaction_id().get()); Wsrep_schema_impl::store(frag_table, 2, i->get()); - Wsrep_schema_impl::make_key(frag_table, key, &key_map, 3); + Wsrep_schema_impl::make_key(frag_table, &key, &key_map, 3); int error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, @@ -1211,6 +1225,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, Wsrep_schema_impl::finish_stmt(&thd); DBUG_RETURN(1); } + error= Wsrep_schema_impl::init_for_index_scan(frag_table, key, key_map); @@ -1224,6 +1239,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, } error= Wsrep_schema_impl::delete_row(frag_table); + if (error) { WSREP_WARN("Could not delete row from streaming log table: %d", error); @@ -1233,8 +1249,12 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, } Wsrep_schema_impl::end_index_scan(frag_table); Wsrep_schema_impl::finish_stmt(&thd); + my_free(key); + key= NULL; } + if (key) + my_free(key); DBUG_RETURN(ret); } -- cgit v1.2.1