summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Nielsen <knielsen@odin>2010-04-28 07:48:03 +0200
committerKristian Nielsen <knielsen@odin>2010-04-28 07:48:03 +0200
commit1f683a7270e63abfadce20c6f51370621ff065e1 (patch)
tree5a0058c047e53644b525b705ead0fb6cda653c7a
parente432151e9cf6a7a5ccf84fc137975ccf38fd0798 (diff)
downloadmariadb-git-1f683a7270e63abfadce20c6f51370621ff065e1.tar.gz
Fix buffer overflow in COM_FIELD_LIST.
sql/sql_base.cc: Replace strmov() with strnmov() to remove the possibility for buffer overflow. sql/sql_parse.cc: Reject COM_FIELD_LIST with too-big table or wildcard argument. (libmysqlclient doesn't allow sending too long arguments anyway, but we need this to protect against buffer overflow exploits).
-rw-r--r--sql/sql_base.cc8
-rw-r--r--sql/sql_parse.cc30
2 files changed, 26 insertions, 12 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1da17c216f2..4416ebbc45c 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -233,8 +233,12 @@ static void check_unused(void)
uint create_table_def_key(THD *thd, char *key, TABLE_LIST *table_list,
bool tmp_table)
{
- uint key_length= (uint) (strmov(strmov(key, table_list->db)+1,
- table_list->table_name)-key)+1;
+ char *db_end= strnmov(key, table_list->db, MAX_DBKEY_LENGTH - 2);
+ *db_end++= '\0';
+ char *table_end= strnmov(db_end, table_list->table_name,
+ key + MAX_DBKEY_LENGTH - 1 - db_end);
+ *table_end++= '\0';
+ uint key_length= (uint) (table_end-key);
if (tmp_table)
{
int4store(key + key_length, thd->server_id);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9503e8a5d81..2eb6a190e63 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1304,10 +1304,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
#else
{
- char *fields, *packet_end= packet + packet_length, *arg_end;
+ char *fields, *packet_end= packet + packet_length, *wildcard;
/* Locked closure of all tables */
TABLE_LIST table_list;
- LEX_STRING conv_name;
+ char db_buff[NAME_LEN+1];
+ uint32 db_length;
+ uint dummy_errors;
/* used as fields initializator */
lex_start(thd);
@@ -1319,11 +1321,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/*
We have name + wildcard in packet, separated by endzero
*/
- arg_end= strend(packet);
- thd->convert_string(&conv_name, system_charset_info,
- packet, (uint) (arg_end - packet), thd->charset());
- table_list.alias= table_list.table_name= conv_name.str;
- packet= arg_end + 1;
+ wildcard= strend(packet);
+ db_length= wildcard - packet;
+ wildcard++;
+ uint query_length= (uint) (packet_end - wildcard); // Don't count end \0
+ if (db_length > NAME_LEN || query_length > NAME_LEN)
+ {
+ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
+ break;
+ }
+ db_length= copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info, packet, db_length,
+ thd->charset(), &dummy_errors);
+ db_buff[db_length]= '\0';
+ table_list.alias= table_list.table_name= db_buff;
+ if (!(fields= (char *) thd->memdup(wildcard, query_length + 1)))
+ break;
if (is_schema_db(table_list.db, table_list.db_length))
{
@@ -1332,9 +1345,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
table_list.schema_table= schema_table;
}
- uint query_length= (uint) (packet_end - packet); // Don't count end \0
- if (!(fields= (char *) thd->memdup(packet, query_length + 1)))
- break;
thd->set_query(fields, query_length);
general_log_print(thd, command, "%s %s", table_list.table_name, fields);
if (lower_case_table_names)