From: Dmitry Shulga Date: December 30 2010 7:04am Subject: bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3512) Bug#56976 List-Archive: http://lists.mysql.com/commits/127694 X-Bug: 56976 Message-Id: <201012300705.oBU75qUX024117@rcsinet13.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7609208520564756375==" --===============7609208520564756375== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/shulga/projects/mysql/5.1-bugteam-bug56976/ based on revid:mats.kindahl@stripped 3512 Dmitry Shulga 2010-12-30 Fixed the bug#56976 - Severe Denial Of Service in prepared statements. The problem was that server didn't check resulting size of prepared statement argument which was set using mysql_send_long_data() API. By calling mysql_send_long_data() several times it was possible to create overly big string and thus force server to allocate memory for it. There was no way to limit this allocation. The solution is to add check for size of result string against value of max_allowed_packet constant. When intermediate string exceeds max_allowed_packet value ER_TOO_LONG_STRING error is emitted. Incompatible change: It is no longer possible to use mysql_send_long_data() API to provide values for BLOBs with length more than 1G. @ sql/item.cc Added call to my_error when accumulated string exceeds max_allowed_packet value. my_error() calls handler for error ER_TOO_LONG_STRING that was installed in mysql_stmt_get_longdata before call to Item_param::set_longdata. The error handler sets to corresponding value the next current statement fileds: state, last_error, last_errno. @ sql/item.h Added argument of type THD* to declaration of set_longdata(). @ sql/sql_prepare.cc Added error handler class Set_longdata_error_handler. This handler is installed inside mysql_stmt_get_longdata() before call to param->set_longdata and deinstalled after return from it. Sourcecode snippet that makes checking for statement's state during statement execution moved from Prepared_statement::execute() to Prepared_statement::execute_loop() in order not to call set_parameters() when statement has been failed during set_long_data() execution. If it didn't do then call to set_parameters would failed. @ tests/mysql_client_test.c It was added testcase for the bug #56976. modified: sql/item.cc sql/item.h sql/sql_prepare.cc tests/mysql_client_test.c === modified file 'sql/item.cc' --- a/sql/item.cc 2010-11-18 13:11:18 +0000 +++ b/sql/item.cc 2010-12-30 07:03:56 +0000 @@ -2738,7 +2738,7 @@ bool Item_param::set_str(const char *str } -bool Item_param::set_longdata(const char *str, ulong length) +bool Item_param::set_longdata(THD *thd, const char *str, ulong length) { DBUG_ENTER("Item_param::set_longdata"); @@ -2751,6 +2751,9 @@ bool Item_param::set_longdata(const char (here), and first have to concatenate all pieces together, write query to the binary log and only then perform conversion. */ + if (str_value.length() + length > thd->variables.max_allowed_packet) + DBUG_RETURN(my_error(ER_TOO_LONG_STRING, MYF(0))); + if (str_value.append(str, length, &my_charset_bin)) DBUG_RETURN(TRUE); state= LONG_DATA_VALUE; === modified file 'sql/item.h' --- a/sql/item.h 2010-07-30 13:35:06 +0000 +++ b/sql/item.h 2010-12-30 07:03:56 +0000 @@ -1687,7 +1687,7 @@ public: void set_double(double i); void set_decimal(const char *str, ulong length); bool set_str(const char *str, ulong length); - bool set_longdata(const char *str, ulong length); + bool set_longdata(THD *thd, const char *str, ulong length); void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg); bool set_from_user_var(THD *thd, const user_var_entry *entry); void reset(); === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2010-11-03 10:24:47 +0000 +++ b/sql/sql_prepare.cc 2010-12-30 07:03:56 +0000 @@ -95,6 +95,7 @@ When one supplies long data for a placeh #else #include #endif +#include /** A result class used to send cursor rows using the binary protocol. @@ -2743,6 +2744,32 @@ void mysql_sql_stmt_close(THD *thd) } } + +class Set_longdata_error_handler : public Internal_error_handler +{ +public: + Set_longdata_error_handler(Prepared_statement *statement) + :stmt(statement) + { } + +public: + bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) + { + stmt->state= Query_arena::ERROR; + stmt->last_errno= sql_errno; + strncpy(stmt->last_error, message, MYSQL_ERRMSG_SIZE); + + return TRUE; + } + +private: + Prepared_statement *stmt; +}; + + /** Handle long data in pieces from client. @@ -2799,16 +2826,14 @@ void mysql_stmt_get_longdata(THD *thd, c param= stmt->param_array[param_number]; + Set_longdata_error_handler err_handler(stmt); + thd->push_internal_handler(&err_handler); #ifndef EMBEDDED_LIBRARY - if (param->set_longdata(packet, (ulong) (packet_end - packet))) + param->set_longdata(thd, packet, (ulong) (packet_end - packet)); #else - if (param->set_longdata(thd->extra_data, thd->extra_length)) + param->set_longdata(thd, thd->extra_data, thd->extra_length); #endif - { - stmt->state= Query_arena::ERROR; - stmt->last_errno= ER_OUTOFMEMORY; - sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0); - } + thd->pop_internal_handler(); general_log_print(thd, thd->command, NullS); @@ -3269,6 +3294,13 @@ Prepared_statement::execute_loop(String bool error; int reprepare_attempt= 0; + /* Check if we got an error when sending long data */ + if (state == Query_arena::ERROR) + { + my_message(last_errno, last_error, MYF(0)); + return TRUE; + } + if (set_parameters(expanded_query, packet, packet_end)) return TRUE; @@ -3509,12 +3541,6 @@ bool Prepared_statement::execute(String status_var_increment(thd->status_var.com_stmt_execute); - /* Check if we got an error when sending long data */ - if (state == Query_arena::ERROR) - { - my_message(last_errno, last_error, MYF(0)); - return TRUE; - } if (flags & (uint) IS_IN_USE) { my_error(ER_PS_NO_RECURSION, MYF(0)); === modified file 'tests/mysql_client_test.c' --- a/tests/mysql_client_test.c 2010-11-26 12:51:48 +0000 +++ b/tests/mysql_client_test.c 2010-12-30 07:03:56 +0000 @@ -18399,6 +18399,54 @@ static void test_bug47485() /* + Bug #56976: Severe Denial Of Service in prepared statements +*/ + +static void test_bug56976() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + int rc; + const char* query = "SELECT LENGTH(?)"; + char *long_buffer; + unsigned long i, packet_len = 256 * 1024L; + unsigned long dos_len = 2 * 1024 * 1024L; + + DBUG_ENTER("test_bug56976"); + myheader("test_bug56976"); + + stmt= mysql_stmt_init(mysql); + check_stmt(stmt); + + rc= mysql_stmt_prepare(stmt, query, strlen(query)); + check_execute(stmt, rc); + + memset(bind, 0, sizeof(bind)); + bind[0].buffer_type = MYSQL_TYPE_TINY_BLOB; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + long_buffer= malloc(packet_len); + memset(long_buffer, 'a', packet_len); + + for (i= 0; i < dos_len / packet_len; i++) + { + rc= mysql_stmt_send_long_data(stmt, 0, long_buffer, packet_len); + check_execute(stmt, rc); + } + + rc= mysql_stmt_execute(stmt); + + DIE_UNLESS(rc && mysql_stmt_errno(stmt) == ER_TOO_LONG_STRING); + + mysql_stmt_close(stmt); + + DBUG_VOID_RETURN; +} + + +/* Read and parse arguments and MySQL options from my.cnf */ @@ -18724,6 +18772,7 @@ static struct my_tests_st my_tests[]= { { "test_bug42373", test_bug42373 }, { "test_bug54041", test_bug54041 }, { "test_bug47485", test_bug47485 }, + { "test_bug56976", test_bug56976 }, { 0, 0 } }; --===============7609208520564756375== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.shulga@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.shulga@stripped\ # v2y9i4x0btmkynck # target_branch: file:///Users/shulga/projects/mysql/5.1-bugteam-\ # bug56976/ # testament_sha1: 34f2343e623c15be13c2a4ad0302d1165e291877 # timestamp: 2010-12-30 13:04:04 +0600 # base_revision_id: mats.kindahl@stripped\ # 7udci9op4lc6jvtb # # Begin bundle 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 --===============7609208520564756375==--