From: Dmitry Shulga Date: February 14 2011 12:33pm Subject: bzr commit into mysql-5.1-bugteam branch (Dmitry.Shulga:3537) Bug#56976 List-Archive: http://lists.mysql.com/commits/131181 X-Bug: 56976 Message-Id: <201102141234.p1ECYTJp013330@rcsinet15.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============4521918744276931346==" --===============4521918744276931346== 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:dao-gang.qu@stripped 3537 Dmitry Shulga 2011-02-14 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_long_data_size start-up parameter. When intermediate string exceeds max_long_data_size value an appropriate error message is emitted. For this purpose can be used max_allowed_packet parameter but since its value limited by 1GB we use new parameter max_long_data_size. max_long_data_size parameter is marked as deprecated and has default value that equials to value of max_allowed_packet start-up parameter. In the future start-up parameter max_long_data_size will be replaced by max_allowed_packet. @ mysql-test/t/variables.test Added checking for new start-up parameter max_long_data_size. @ sql/item.cc Added call to my_message() when accumulated string exceeds max_long_data_size value. my_message() calls error handler 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/mysql_priv.h Added max_long_data_size variable declaration. @ sql/mysqld.cc Added support for start-up parameter 'max_long_data_size'. This parameter limits size of data which can be sent from client to server using mysql_send_long_data() API. @ sql/set_var.cc Added variable 'max_long_data_size' into list of variables displayed by command 'show variables'. @ sql/sql_prepare.cc Added error handler class Set_longdata_error_handler. This handler is used to catch any errors that can be generated during execution of Item_param::set_longdata(). 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 failed during set_long_data() execution. If it didn't do then call to set_parameters would failed. @ tests/mysql_client_test.c A testcase for the bug #56976 was added. modified: mysql-test/r/variables.result mysql-test/t/variables.test sql/item.cc sql/mysql_priv.h sql/mysqld.cc sql/set_var.cc sql/sql_prepare.cc tests/mysql_client_test.c === modified file 'mysql-test/r/variables.result' --- a/mysql-test/r/variables.result 2010-11-25 03:11:05 +0000 +++ b/mysql-test/r/variables.result 2011-02-14 12:33:37 +0000 @@ -1540,6 +1540,9 @@ ERROR HY000: Cannot drop default keycach SET @@global.key_cache_block_size=0; Warnings: Warning 1292 Truncated incorrect key_cache_block_size value: '0' +select @@max_long_data_size; +@@max_long_data_size +1048576 SET @@global.max_binlog_cache_size=DEFAULT; SET @@global.max_join_size=DEFAULT; SET @@global.key_buffer_size=@kbs; === modified file 'mysql-test/t/variables.test' --- a/mysql-test/t/variables.test 2010-11-25 03:11:05 +0000 +++ b/mysql-test/t/variables.test 2011-02-14 12:33:37 +0000 @@ -1293,6 +1293,11 @@ SET @@global.max_join_size=0; SET @@global.key_buffer_size=0; SET @@global.key_cache_block_size=0; +# +# Bug#56976: added new start-up paramaeter +# +select @@max_long_data_size; + # cleanup SET @@global.max_binlog_cache_size=DEFAULT; SET @@global.max_join_size=DEFAULT; === modified file 'sql/item.cc' --- a/sql/item.cc 2010-12-21 11:34:11 +0000 +++ b/sql/item.cc 2011-02-14 12:33:37 +0000 @@ -2742,6 +2742,16 @@ 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 > max_long_data_size) + { + my_message(ER_UNKNOWN_ERROR, + "Parameter of prepared statement which is set through " + "mysql_send_long_data() is longer than " + "'max_long_data_size' bytes", + MYF(0)); + DBUG_RETURN(true); + } + if (str_value.append(str, length, &my_charset_bin)) DBUG_RETURN(TRUE); state= LONG_DATA_VALUE; === modified file 'sql/mysql_priv.h' --- a/sql/mysql_priv.h 2010-12-16 19:11:08 +0000 +++ b/sql/mysql_priv.h 2011-02-14 12:33:37 +0000 @@ -1969,6 +1969,7 @@ extern MYSQL_PLUGIN_IMPORT uint lower_ca extern bool opt_endinfo, using_udf_functions; extern my_bool locked_in_memory; extern bool opt_using_transactions; +extern ulong max_long_data_size; #endif /* MYSQL_SERVER */ #if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS extern MYSQL_PLUGIN_IMPORT bool mysqld_embedded; === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2010-12-28 23:47:05 +0000 +++ b/sql/mysqld.cc 2011-02-14 12:33:37 +0000 @@ -409,6 +409,7 @@ TYPELIB log_output_typelib= {array_eleme /* the default log output is log tables */ static bool lower_case_table_names_used= 0; +static bool max_long_data_size_used= false; static bool volatile select_thread_in_use, signal_thread_in_use; static bool volatile ready_to_exit; static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0; @@ -574,6 +575,9 @@ ulong delayed_insert_errors,flush_time; ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong max_connections, max_connect_errors; +// Maximum length of parameter value which can be set through +// mysql_send_long_data() call. +ulong max_long_data_size; uint max_user_connections= 0; /** Limit of the total number of prepared statements in the server. @@ -5782,7 +5786,8 @@ enum options_mysqld OPT_SLOW_QUERY_LOG_FILE, OPT_IGNORE_BUILTIN_INNODB, OPT_BINLOG_DIRECT_NON_TRANS_UPDATE, - OPT_DEFAULT_CHARACTER_SET_OLD + OPT_DEFAULT_CHARACTER_SET_OLD, + OPT_MAX_LONG_DATA_SIZE }; @@ -6862,6 +6867,13 @@ thread is in the relay logs.", &global_system_variables.max_length_for_sort_data, &max_system_variables.max_length_for_sort_data, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0}, + {"max_long_data_size", OPT_MAX_LONG_DATA_SIZE, + "The maximum size of prepared statement parameter which can be provided " + "through mysql_send_long_data() API call. " + "Deprecated option; use max_allowed_packet instead.", + &max_long_data_size, + &max_long_data_size, 0, GET_ULONG, + REQUIRED_ARG, 1024*1024L, 1024, UINT_MAX32, MALLOC_OVERHEAD, 1, 0}, {"max_prepared_stmt_count", OPT_MAX_PREPARED_STMT_COUNT, "Maximum number of prepared statements in the server.", &max_prepared_stmt_count, &max_prepared_stmt_count, @@ -8670,6 +8682,10 @@ mysqld_get_one_option(int optid, } break; #endif /* defined(ENABLED_DEBUG_SYNC) */ + case OPT_MAX_LONG_DATA_SIZE: + max_long_data_size_used= true; + WARN_DEPRECATED(NULL, VER_CELOSIA, "--max_long_data_size", "--max_allowed_packet"); + break; } return 0; } @@ -8831,6 +8847,14 @@ static int get_options(int *argc,char ** else pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */ #endif + + /* + If max_long_data_size is not specified explicitly use + value of max_allowed_packet. + */ + if (!max_long_data_size_used) + max_long_data_size= global_system_variables.max_allowed_packet; + return 0; } === modified file 'sql/set_var.cc' --- a/sql/set_var.cc 2010-12-28 23:47:05 +0000 +++ b/sql/set_var.cc 2011-02-14 12:33:37 +0000 @@ -394,6 +394,12 @@ static sys_var_thd_ulong sys_max_seeks_f &SV::max_seeks_for_key); static sys_var_thd_ulong sys_max_length_for_sort_data(&vars, "max_length_for_sort_data", &SV::max_length_for_sort_data); +static sys_var_const sys_max_long_data_size(&vars, + "max_long_data_size", + OPT_GLOBAL, SHOW_LONG, + (uchar*) + &max_long_data_size); + #ifndef TO_BE_DELETED /* Alias for max_join_size */ static sys_var_thd_ha_rows sys_sql_max_join_size(&vars, "sql_max_join_size", &SV::max_join_size, === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2010-12-28 23:47:05 +0000 +++ b/sql/sql_prepare.cc 2011-02-14 12:33:37 +0000 @@ -2730,6 +2730,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. @@ -2786,16 +2812,19 @@ void mysql_stmt_get_longdata(THD *thd, c param= stmt->param_array[param_number]; + Set_longdata_error_handler err_handler(stmt); + /* + Install handler that will catch any errors that can be generated + during execution of Item_param::set_longdata() and propagate + them to Statement::last_error. + */ + thd->push_internal_handler(&err_handler); #ifndef EMBEDDED_LIBRARY - if (param->set_longdata(packet, (ulong) (packet_end - packet))) + param->set_longdata(packet, (ulong) (packet_end - packet)); #else - if (param->set_longdata(thd->extra_data, thd->extra_length)) + param->set_longdata(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); @@ -3257,6 +3286,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; @@ -3497,12 +3533,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-12-28 23:47:05 +0000 +++ b/tests/mysql_client_test.c 2011-02-14 12:33:37 +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_UNKNOWN_ERROR); + + 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 } }; --===============4521918744276931346== 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\ # z2cq142i2jn15kzb # target_branch: file:///Users/shulga/projects/mysql/5.1-bugteam-\ # bug56976/ # testament_sha1: 50e76c3d50aac3d837d03474b9fd2f70f1062918 # timestamp: 2011-02-14 18:33:47 +0600 # base_revision_id: dao-gang.qu@stripped\ # 32f4p072xij1zkmj # # Begin bundle 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 --===============4521918744276931346==--