Commit be901b60 authored by Nisha Gopalakrishnan's avatar Nisha Gopalakrishnan

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.
parent ebd96c31
/*
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<partition_element> 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<partition_element> part_it(m_part_info->partitions);
List_iterator<partition_element> 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<partition_element> part_it(m_part_info->partitions);
List_iterator <partition_element> 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 @@ int ha_partition::del_ren_cre_table(const char *from,
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 @@ int ha_partition::del_ren_cre_table(const char *from,
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();
......
/* 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<partition_element> 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<partition_element> part_it(part_info->partitions);
List_iterator<partition_element> 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)
......
#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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment