From be901b60ae59c93848c829d1b0b2cb523ab8692e Mon Sep 17 00:00:00 2001 From: Nisha Gopalakrishnan Date: Wed, 16 Aug 2017 13:58:25 +0530 Subject: Bug#26390632: CREATE TABLE CAN CAUSE MYSQL TO EXIT. Analysis ======== CREATE TABLE of InnoDB table with a partition name which exceeds the path limit can cause the server to exit. During the preparation of the partition name, there was no check to identify whether the complete path name for partition exceeds the max supported path length, causing the server to exit during subsequent processing. Fix === During the preparation of partition name, check and report an error if the partition path name exceeds the maximum path name limit. This is a 5.5 patch. --- sql/ha_partition.cc | 150 ++++++++++++++++++++++++++----------------- sql/sql_partition.cc | 177 ++++++++++++++++++++++++++++++++------------------- sql/sql_partition.h | 6 +- 3 files changed, 204 insertions(+), 129 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index aadac36e2ee..414f9d52536 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -624,7 +624,7 @@ int ha_partition::create(const char *name, TABLE *table_arg, int ha_partition::drop_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); - char part_name_buff[FN_REFLEN]; + char part_name_buff[FN_REFLEN + 1]; uint num_parts= m_part_info->partitions.elements; uint num_subparts= m_part_info->num_subparts; uint i= 0; @@ -657,9 +657,12 @@ int ha_partition::drop_partitions(const char *path) { partition_element *sub_elem= sub_it++; part= i * num_subparts + j; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, name_variant); + if ((ret_error= create_subpartition_name(part_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, + name_variant))) + error= ret_error; + file= m_file[part]; DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); if ((ret_error= file->ha_delete_table(part_name_buff))) @@ -670,9 +673,11 @@ int ha_partition::drop_partitions(const char *path) } else { - create_partition_name(part_name_buff, path, - part_elem->partition_name, name_variant, - TRUE); + if ((ret_error= create_partition_name(part_name_buff, path, + part_elem->partition_name, + name_variant, TRUE))) + error= ret_error; + file= m_file[i]; DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); if ((ret_error= file->ha_delete_table(part_name_buff))) @@ -714,8 +719,8 @@ int ha_partition::rename_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); List_iterator temp_it(m_part_info->temp_partitions); - char part_name_buff[FN_REFLEN]; - char norm_name_buff[FN_REFLEN]; + char part_name_buff[FN_REFLEN + 1]; + char norm_name_buff[FN_REFLEN + 1]; uint num_parts= m_part_info->partitions.elements; uint part_count= 0; uint num_subparts= m_part_info->num_subparts; @@ -757,10 +762,11 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; file= m_reorged_file[part_count++]; - create_subpartition_name(norm_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - NORMAL_PART_NAME); + if ((ret_error= create_subpartition_name(norm_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME))) + error= ret_error; DBUG_PRINT("info", ("Delete subpartition %s", norm_name_buff)); if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; @@ -773,9 +779,11 @@ int ha_partition::rename_partitions(const char *path) else { file= m_reorged_file[part_count++]; - create_partition_name(norm_name_buff, path, - part_elem->partition_name, NORMAL_PART_NAME, - TRUE); + if ((ret_error= create_partition_name(norm_name_buff, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE))) + error= ret_error; + DBUG_PRINT("info", ("Delete partition %s", norm_name_buff)); if ((ret_error= file->ha_delete_table(norm_name_buff))) error= ret_error; @@ -825,10 +833,12 @@ int ha_partition::rename_partitions(const char *path) { sub_elem= sub_it++; part= i * num_subparts + j; - create_subpartition_name(norm_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - NORMAL_PART_NAME); + if ((ret_error= create_subpartition_name(norm_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME))) + error= ret_error; + if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; @@ -840,10 +850,12 @@ int ha_partition::rename_partitions(const char *path) (void) sync_ddl_log(); } file= m_new_file[part]; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - TEMP_PART_NAME); + if ((ret_error= create_subpartition_name(part_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, + TEMP_PART_NAME))) + error= ret_error; + DBUG_PRINT("info", ("Rename subpartition from %s to %s", part_name_buff, norm_name_buff)); if ((ret_error= file->ha_rename_table(part_name_buff, @@ -857,9 +869,11 @@ int ha_partition::rename_partitions(const char *path) } else { - create_partition_name(norm_name_buff, path, - part_elem->partition_name, NORMAL_PART_NAME, - TRUE); + if ((ret_error= create_partition_name(norm_name_buff, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE))) + error= ret_error; + if (part_elem->part_state == PART_IS_CHANGED) { file= m_reorged_file[part_count++]; @@ -871,9 +885,11 @@ int ha_partition::rename_partitions(const char *path) (void) sync_ddl_log(); } file= m_new_file[i]; - create_partition_name(part_name_buff, path, - part_elem->partition_name, TEMP_PART_NAME, - TRUE); + if ((ret_error= create_partition_name(part_name_buff, path, + part_elem->partition_name, + TEMP_PART_NAME, TRUE))) + error= ret_error; + DBUG_PRINT("info", ("Rename partition from %s to %s", part_name_buff, norm_name_buff)); if ((ret_error= file->ha_rename_table(part_name_buff, @@ -1477,7 +1493,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, { List_iterator part_it(m_part_info->partitions); List_iterator t_it(m_part_info->temp_partitions); - char part_name_buff[FN_REFLEN]; + char part_name_buff[FN_REFLEN + 1]; uint num_parts= m_part_info->partitions.elements; uint num_subparts= m_part_info->num_subparts; uint i= 0; @@ -1687,10 +1703,15 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, do { partition_element *sub_elem= sub_it++; - create_subpartition_name(part_name_buff, path, - part_elem->partition_name, - sub_elem->partition_name, - name_variant); + if ((error= create_subpartition_name(part_name_buff, path, + part_elem->partition_name, + sub_elem->partition_name, + name_variant))) + { + cleanup_new_partition(part_count); + DBUG_RETURN(error); + } + part= i * num_subparts + j; DBUG_PRINT("info", ("Add subpartition %s", part_name_buff)); if ((error= prepare_new_partition(table, create_info, @@ -1708,9 +1729,14 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, } else { - create_partition_name(part_name_buff, path, - part_elem->partition_name, name_variant, - TRUE); + if ((error= create_partition_name(part_name_buff, path, + part_elem->partition_name, + name_variant, TRUE))) + { + cleanup_new_partition(part_count); + DBUG_RETURN(error); + } + DBUG_PRINT("info", ("Add partition %s", part_name_buff)); if ((error= prepare_new_partition(table, create_info, new_file_array[i], @@ -1967,8 +1993,8 @@ int ha_partition::del_ren_cre_table(const char *from, { int save_error= 0; int error= HA_ERR_INTERNAL_ERROR; - char from_buff[FN_REFLEN], to_buff[FN_REFLEN], from_lc_buff[FN_REFLEN], - to_lc_buff[FN_REFLEN], buff[FN_REFLEN]; + char from_buff[FN_REFLEN + 1], to_buff[FN_REFLEN + 1], from_lc_buff[FN_REFLEN + 1], + to_lc_buff[FN_REFLEN + 1], buff[FN_REFLEN + 1]; char *name_buffer_ptr; const char *from_path; const char *to_path= NULL; @@ -2015,13 +2041,16 @@ int ha_partition::del_ren_cre_table(const char *from, i= 0; do { - create_partition_name(from_buff, from_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); + if ((error= create_partition_name(from_buff, from_path, name_buffer_ptr, + NORMAL_PART_NAME, FALSE))) + DBUG_RETURN(error); if (to != NULL) { // Rename branch - create_partition_name(to_buff, to_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); + if ((error= create_partition_name(to_buff, to_path, name_buffer_ptr, + NORMAL_PART_NAME, FALSE))) + DBUG_RETURN(error); + error= (*file)->ha_rename_table(from_buff, to_buff); if (error) goto rename_error; @@ -2066,9 +2095,9 @@ create_error: name_buffer_ptr= m_name_buffer_ptr; for (abort_file= file, file= m_file; file < abort_file; file++) { - create_partition_name(from_buff, from_path, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); - (void) (*file)->ha_delete_table((const char*) from_buff); + if (!create_partition_name(from_buff, from_path, name_buffer_ptr, NORMAL_PART_NAME, + FALSE)) + (void) (*file)->ha_delete_table((const char*) from_buff); name_buffer_ptr= strend(name_buffer_ptr) + 1; } DBUG_RETURN(error); @@ -2077,12 +2106,12 @@ rename_error: for (abort_file= file, file= m_file; file < abort_file; file++) { /* Revert the rename, back from 'to' to the original 'from' */ - create_partition_name(from_buff, from_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); - create_partition_name(to_buff, to_path, name_buffer_ptr, - NORMAL_PART_NAME, FALSE); - /* Ignore error here */ - (void) (*file)->ha_rename_table(to_buff, from_buff); + if (!create_partition_name(from_buff, from_path, name_buffer_ptr, + NORMAL_PART_NAME, FALSE)) + if (!create_partition_name(to_buff, to_path, name_buffer_ptr, + NORMAL_PART_NAME, FALSE)) + /* Ignore error here */ + (void) (*file)->ha_rename_table(to_buff, from_buff); name_buffer_ptr= strend(name_buffer_ptr) + 1; } DBUG_RETURN(error); @@ -2707,7 +2736,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) char *name_buffer_ptr; int error= HA_ERR_INITIALIZATION; handler **file; - char name_buff[FN_REFLEN]; + char name_buff[FN_REFLEN + 1]; bool is_not_tmp_table= (table_share->tmp_table == NO_TMP_TABLE); ulonglong check_table_flags; DBUG_ENTER("ha_partition::open"); @@ -2777,8 +2806,10 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) file= m_is_clone_of->m_file; for (i= 0; i < m_tot_parts; i++) { - create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); + if ((error= create_partition_name(name_buff, name, name_buffer_ptr, + NORMAL_PART_NAME, FALSE))) + goto err_handler; + if (!(m_file[i]= file[i]->clone(name_buff, m_clone_mem_root))) { error= HA_ERR_INITIALIZATION; @@ -2793,8 +2824,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) file= m_file; do { - create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME, - FALSE); + if ((error= create_partition_name(name_buff, name, name_buffer_ptr, + NORMAL_PART_NAME, FALSE))) + goto err_handler; if ((error= (*file)->ha_open(table, name_buff, mode, test_if_locked))) goto err_handler; m_num_locks+= (*file)->lock_count(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 5358535e9f9..65d4da0f2f6 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -5958,8 +5958,8 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; DDL_LOG_MEMORY_ENTRY *log_entry; - char tmp_path[FN_REFLEN]; - char normal_path[FN_REFLEN]; + char tmp_path[FN_REFLEN + 1]; + char normal_path[FN_REFLEN + 1]; List_iterator part_it(part_info->partitions); uint temp_partitions= part_info->temp_partitions.elements; uint num_elements= part_info->partitions.elements; @@ -5983,14 +5983,18 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); - create_subpartition_name(tmp_path, path, - part_elem->partition_name, - sub_elem->partition_name, - TEMP_PART_NAME); - create_subpartition_name(normal_path, path, - part_elem->partition_name, - sub_elem->partition_name, - NORMAL_PART_NAME); + if (create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + TEMP_PART_NAME)) + DBUG_RETURN(TRUE); + + if (create_subpartition_name(normal_path, path, + part_elem->partition_name, + sub_elem->partition_name, + NORMAL_PART_NAME)) + DBUG_RETURN(TRUE); + ddl_log_entry.name= normal_path; ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) @@ -6011,12 +6015,13 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); - create_partition_name(tmp_path, path, - part_elem->partition_name, - TEMP_PART_NAME, TRUE); - create_partition_name(normal_path, path, - part_elem->partition_name, - NORMAL_PART_NAME, TRUE); + if ((create_partition_name(tmp_path, path, part_elem->partition_name, + TEMP_PART_NAME, TRUE)) || + (create_partition_name(normal_path, path, + part_elem->partition_name, + NORMAL_PART_NAME, TRUE))) + DBUG_RETURN(TRUE); + ddl_log_entry.name= normal_path; ddl_log_entry.from_name= tmp_path; if (part_elem->part_state == PART_IS_CHANGED) @@ -6055,7 +6060,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DDL_LOG_ENTRY ddl_log_entry; partition_info *part_info= lpt->part_info; DDL_LOG_MEMORY_ENTRY *log_entry; - char tmp_path[FN_LEN]; + char tmp_path[FN_REFLEN + 1]; List_iterator part_it(part_info->partitions); List_iterator temp_it(part_info->temp_partitions); uint num_temp_partitions= part_info->temp_partitions.elements; @@ -6094,10 +6099,12 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(sub_elem->engine_type); - create_subpartition_name(tmp_path, path, - part_elem->partition_name, - sub_elem->partition_name, - name_variant); + if (create_subpartition_name(tmp_path, path, + part_elem->partition_name, + sub_elem->partition_name, + name_variant)) + DBUG_RETURN(TRUE); + ddl_log_entry.name= tmp_path; if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { @@ -6113,9 +6120,10 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, ddl_log_entry.next_entry= *next_entry; ddl_log_entry.handler_name= ha_resolve_storage_engine_name(part_elem->engine_type); - create_partition_name(tmp_path, path, - part_elem->partition_name, - name_variant, TRUE); + if ((create_partition_name(tmp_path, path, part_elem->partition_name, + name_variant, TRUE))) + DBUG_RETURN(TRUE); + ddl_log_entry.name= tmp_path; if (write_ddl_log_entry(&ddl_log_entry, &log_entry)) { @@ -8194,29 +8202,28 @@ static uint32 get_next_subpartition_via_walking(PARTITION_ITERATOR *part_iter) } -/* - Create partition names - - SYNOPSIS - create_partition_name() - out:out Created partition name string - in1 First part - in2 Second part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - - DESCRIPTION - This method is used to calculate the partition name, service routine to - the del_ren_cre_table method. +/** + Create partition names. This method is used to calculate the + partition name, service routine to the del_ren_cre_table method. + The output buffer size should be FN_REFLEN + 1(terminating '\0'). + + @param [out] out Created partition name string + @param in1 First part + @param in2 Second part + @param in3 Third part + @param name_variant Normal, temporary or renamed partition name + @param translate Flag to determine whether to convert a table name + to it its corresponding filename. + + @retval true Error. + @retval false Success. */ -void create_partition_name(char *out, const char *in1, +bool create_partition_name(char *out, const char *in1, const char *in2, uint name_variant, bool translate) { - char transl_part_name[FN_REFLEN]; + char transl_part_name[FN_REFLEN + 1]; const char *transl_part; if (translate) @@ -8226,35 +8233,50 @@ void create_partition_name(char *out, const char *in1, } else transl_part= in2; + + // Check if the path name for partition exceeds maximum path length. if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part, NullS); + { + if ((strlen(in1) + strlen(transl_part) + 3) > FN_REFLEN) + { + my_error(ER_PATH_LENGTH, MYF(0), in2); + return true; + } + } + else + if ((strlen(in1) + strlen(transl_part) + 8) > FN_REFLEN) + { + my_error(ER_PATH_LENGTH, MYF(0), in2); + return true; + } + + if (name_variant == NORMAL_PART_NAME) + strxnmov(out, FN_REFLEN, in1, "#P#", transl_part, NullS); else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#TMP#", NullS); + strxnmov(out, FN_REFLEN, in1, "#P#", transl_part, "#TMP#", NullS); else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part, "#REN#", NullS); -} + strxnmov(out, FN_REFLEN, in1, "#P#", transl_part, "#REN#", NullS); + return false; +} -/* - Create subpartition name - - SYNOPSIS - create_subpartition_name() - out:out Created partition name string - in1 First part - in2 Second part - in3 Third part - name_variant Normal, temporary or renamed partition name - - RETURN VALUE - NONE - DESCRIPTION - This method is used to calculate the subpartition name, service routine to - the del_ren_cre_table method. +/** + Create subpartition name. This method is used to calculate the + subpartition name, service routine to the del_ren_cre_table method. + The output buffer size should be FN_REFLEN + 1(terminating '\0'). + + @param [out] out Created partition name string + @param in1 First part + @param in2 Second part + @param in3 Third part + @param name_variant Normal, temporary or renamed partition name + + @retval true Error. + @retval false Success. */ -void create_subpartition_name(char *out, const char *in1, +bool create_subpartition_name(char *out, const char *in1, const char *in2, const char *in3, uint name_variant) { @@ -8262,15 +8284,36 @@ void create_subpartition_name(char *out, const char *in1, tablename_to_filename(in2, transl_part_name, FN_REFLEN); tablename_to_filename(in3, transl_subpart_name, FN_REFLEN); + + // Check if the path name for subpartition exceeds maximum path length. + if (name_variant == NORMAL_PART_NAME) + { + if ((strlen(in1) + strlen(transl_part_name) + + strlen(transl_subpart_name) + 7) > FN_REFLEN) + { + my_error(ER_PATH_LENGTH, MYF(0), in3); + return true; + } + } + else + if ((strlen(in1) + strlen(transl_part_name) + + strlen(transl_subpart_name) + 12) > FN_REFLEN) + { + my_error(ER_PATH_LENGTH, MYF(0), in3); + return true; + } + if (name_variant == NORMAL_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, + strxnmov(out, FN_REFLEN, in1, "#P#", transl_part_name, "#SP#", transl_subpart_name, NullS); else if (name_variant == TEMP_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, + strxnmov(out, FN_REFLEN, in1, "#P#", transl_part_name, "#SP#", transl_subpart_name, "#TMP#", NullS); else if (name_variant == RENAMED_PART_NAME) - strxmov(out, in1, "#P#", transl_part_name, + strxnmov(out, FN_REFLEN, in1, "#P#", transl_part_name, "#SP#", transl_subpart_name, "#REN#", NullS); + + return false; } uint get_partition_field_store_length(Field *field) diff --git a/sql/sql_partition.h b/sql/sql_partition.h index f232eaa0629..cfaab903f04 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -1,7 +1,7 @@ #ifndef SQL_PARTITION_INCLUDED #define SQL_PARTITION_INCLUDED -/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -272,10 +272,10 @@ char *generate_partition_syntax(partition_info *part_info, const char *current_comment_start); #endif -void create_partition_name(char *out, const char *in1, +bool create_partition_name(char *out, const char *in1, const char *in2, uint name_variant, bool translate); -void create_subpartition_name(char *out, const char *in1, +bool create_subpartition_name(char *out, const char *in1, const char *in2, const char *in3, uint name_variant); -- cgit v1.2.1