Commit 428ff7f8 authored by Georgi Kodinov's avatar Georgi Kodinov

Bug #13708485: malformed resultset packet crashes client

Several fixes :

* sql-common/client.c
Added a validity check of the fields metadata packet sent 
by the server.
Now libmysql will check if the length of the data sent by
the server matches what's expected by the protocol before
using the data.

* client/mysqltest.cc
Fixed the error handling code in mysqltest to avoid sending
new commands when the reading the result set failed (and 
there are unread data in the pipe).

* sql_common.h + libmysql/libmysql.c + sql-common/client.c
unpack_fields() now generates a proper error when it fails.
Added a new argument to this function to support the error 
generation.

* sql/protocol.cc
Added a debug trigger to cause the server to send a NULL
insted of the packet expected by the client for testing 
purposes.
parent 43586697
/* /*
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -6848,6 +6848,8 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, ...@@ -6848,6 +6848,8 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
*/ */
if ((counter==0) && mysql_read_query_result(mysql)) if ((counter==0) && mysql_read_query_result(mysql))
{ {
/* we've failed to collect the result set */
cn->pending= TRUE;
handle_error(command, mysql_errno(mysql), mysql_error(mysql), handle_error(command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), ds); mysql_sqlstate(mysql), ds);
goto end; goto end;
......
/* Copyright (C) 2003-2004, 2006 MySQL AB /*
Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -23,8 +24,9 @@ extern "C" { ...@@ -23,8 +24,9 @@ extern "C" {
#endif #endif
extern CHARSET_INFO *default_client_charset_info; extern CHARSET_INFO *default_client_charset_info;
MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, MYSQL_FIELD *unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,
my_bool default_value, uint server_capabilities); uint fields, my_bool default_value,
uint server_capabilities);
void free_rows(MYSQL_DATA *cur); void free_rows(MYSQL_DATA *cur);
void free_old_query(MYSQL *mysql); void free_old_query(MYSQL *mysql);
void end_server(MYSQL *mysql); void end_server(MYSQL *mysql);
......
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -1254,7 +1254,7 @@ MYSQL_FIELD *cli_list_fields(MYSQL *mysql) ...@@ -1254,7 +1254,7 @@ MYSQL_FIELD *cli_list_fields(MYSQL *mysql)
return NULL; return NULL;
mysql->field_count= (uint) query->rows; mysql->field_count= (uint) query->rows;
return unpack_fields(query,&mysql->field_alloc, return unpack_fields(mysql, query,&mysql->field_alloc,
mysql->field_count, 1, mysql->server_capabilities); mysql->field_count, 1, mysql->server_capabilities);
} }
...@@ -1314,7 +1314,7 @@ mysql_list_processes(MYSQL *mysql) ...@@ -1314,7 +1314,7 @@ mysql_list_processes(MYSQL *mysql)
if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0, if (!(fields = (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*) 0,
protocol_41(mysql) ? 7 : 5))) protocol_41(mysql) ? 7 : 5)))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc,field_count,0, if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,field_count,0,
mysql->server_capabilities))) mysql->server_capabilities)))
DBUG_RETURN(0); DBUG_RETURN(0);
mysql->status=MYSQL_STATUS_GET_RESULT; mysql->status=MYSQL_STATUS_GET_RESULT;
...@@ -1891,7 +1891,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt) ...@@ -1891,7 +1891,7 @@ my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7))) if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7)))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root, if (!(stmt->fields= unpack_fields(mysql, fields_data,&stmt->mem_root,
field_count,0, field_count,0,
mysql->server_capabilities))) mysql->server_capabilities)))
DBUG_RETURN(1); DBUG_RETURN(1);
......
/* /*
Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -1268,7 +1268,7 @@ static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, ...@@ -1268,7 +1268,7 @@ static void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
***************************************************************************/ ***************************************************************************/
MYSQL_FIELD * MYSQL_FIELD *
unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
my_bool default_value, uint server_capabilities) my_bool default_value, uint server_capabilities)
{ {
MYSQL_ROWS *row; MYSQL_ROWS *row;
...@@ -1281,6 +1281,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, ...@@ -1281,6 +1281,7 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
if (!result) if (!result)
{ {
free_rows(data); /* Free old data */ free_rows(data); /* Free old data */
set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields); bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields);
...@@ -1308,6 +1309,14 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, ...@@ -1308,6 +1309,14 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
field->org_name_length= lengths[5]; field->org_name_length= lengths[5];
/* Unpack fixed length parts */ /* Unpack fixed length parts */
if (lengths[6] != 12)
{
/* malformed packet. signal an error. */
free_rows(data); /* Free old data */
set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
DBUG_RETURN(0);
}
pos= (uchar*) row->data[6]; pos= (uchar*) row->data[6];
field->charsetnr= uint2korr(pos); field->charsetnr= uint2korr(pos);
field->length= (uint) uint4korr(pos+2); field->length= (uint) uint4korr(pos+2);
...@@ -2868,7 +2877,7 @@ static my_bool cli_read_query_result(MYSQL *mysql) ...@@ -2868,7 +2877,7 @@ static my_bool cli_read_query_result(MYSQL *mysql)
if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5))) if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5)))
DBUG_RETURN(1); DBUG_RETURN(1);
if (!(mysql->fields=unpack_fields(fields,&mysql->field_alloc, if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,
(uint) field_count,0, (uint) field_count,0,
mysql->server_capabilities))) mysql->server_capabilities)))
DBUG_RETURN(1); DBUG_RETURN(1);
......
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -620,6 +620,8 @@ bool Protocol::send_fields(List<Item> *list, uint flags) ...@@ -620,6 +620,8 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
/* Store fixed length fields */ /* Store fixed length fields */
pos= (char*) local_packet->ptr()+local_packet->length(); pos= (char*) local_packet->ptr()+local_packet->length();
*pos++= 12; // Length of packed fields *pos++= 12; // Length of packed fields
/* inject a NULL to test the client */
DBUG_EXECUTE_IF("poison_rs_fields", pos[-1]= 0xfb;);
if (item->collation.collation == &my_charset_bin || thd_charset == NULL) if (item->collation.collation == &my_charset_bin || thd_charset == NULL)
{ {
/* No conversion */ /* No conversion */
......
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