From: Dmitry Shulga Date: March 14 2011 5:52am Subject: bzr commit into mysql-5.5 branch (Dmitry.Shulga:3362) Bug#11764168 List-Archive: http://lists.mysql.com/commits/132872 X-Bug: 11764168 Message-Id: <201103140553.p2E5rDvc020807@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7398099075202505160==" --===============7398099075202505160== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/shulga/projects/mysql/mysql-5.5/ based on revid:marc.alff@stripped 3362 Dmitry Shulga 2011-03-14 [merge] Manual merge from mysql-5.1 for Bug#11764168 (56976: Severe denial of service in prepared statements). added: mysql-test/suite/sys_vars/r/max_long_data_size_basic.result mysql-test/suite/sys_vars/t/max_long_data_size_basic.test modified: mysql-test/r/mysqld--help-notwin.result mysql-test/r/mysqld--help-win.result mysql-test/r/variables.result mysql-test/t/variables.test sql/item.cc sql/mysqld.cc sql/mysqld.h sql/sql_prepare.cc sql/sys_vars.cc tests/mysql_client_test.c === modified file 'mysql-test/r/mysqld--help-notwin.result' --- a/mysql-test/r/mysqld--help-notwin.result 2011-01-14 13:21:46 +0000 +++ b/mysql-test/r/mysqld--help-notwin.result 2011-03-14 05:51:23 +0000 @@ -309,6 +309,10 @@ The following options may be given as th max_join_size records return an error --max-length-for-sort-data=# Max number of bytes in sorted records + --max-long-data-size=# + The maximum BLOB length to send to server from + mysql_send_long_data API. Deprecated option; use + max_allowed_packet instead. --max-prepared-stmt-count=# Maximum number of prepared statements in the server --max-relay-log-size=# @@ -830,6 +834,7 @@ max-error-count 64 max-heap-table-size 16777216 max-join-size 18446744073709551615 max-length-for-sort-data 1024 +max-long-data-size 1048576 max-prepared-stmt-count 16382 max-relay-log-size 0 max-seeks-for-key 18446744073709551615 === modified file 'mysql-test/r/mysqld--help-win.result' --- a/mysql-test/r/mysqld--help-win.result 2011-01-14 13:21:46 +0000 +++ b/mysql-test/r/mysqld--help-win.result 2011-03-14 05:51:23 +0000 @@ -308,6 +308,10 @@ The following options may be given as th max_join_size records return an error --max-length-for-sort-data=# Max number of bytes in sorted records + --max-long-data-size=# + The maximum BLOB length to send to server from + mysql_send_long_data API. Deprecated option; use + max_allowed_packet instead. --max-prepared-stmt-count=# Maximum number of prepared statements in the server --max-relay-log-size=# @@ -833,6 +837,7 @@ max-error-count 64 max-heap-table-size 16777216 max-join-size 18446744073709551615 max-length-for-sort-data 1024 +max-long-data-size 1048576 max-prepared-stmt-count 16382 max-relay-log-size 0 max-seeks-for-key 18446744073709551615 === modified file 'mysql-test/r/variables.result' --- a/mysql-test/r/variables.result 2011-02-10 07:34:22 +0000 +++ b/mysql-test/r/variables.result 2011-03-14 05:51:23 +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; === added file 'mysql-test/suite/sys_vars/r/max_long_data_size_basic.result' --- a/mysql-test/suite/sys_vars/r/max_long_data_size_basic.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/sys_vars/r/max_long_data_size_basic.result 2011-03-14 05:51:23 +0000 @@ -0,0 +1,14 @@ +select @@global.max_long_data_size=20; +@@global.max_long_data_size=20 +0 +select @@session.max_long_data_size; +ERROR HY000: Variable 'max_long_data_size' is a GLOBAL variable +SELECT @@global.max_long_data_size = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='max_long_data_size'; +@@global.max_long_data_size = VARIABLE_VALUE +1 +set global max_long_data_size=1; +ERROR HY000: Variable 'max_long_data_size' is a read only variable +set session max_long_data_size=1; +ERROR HY000: Variable 'max_long_data_size' is a read only variable === added file 'mysql-test/suite/sys_vars/t/max_long_data_size_basic.test' --- a/mysql-test/suite/sys_vars/t/max_long_data_size_basic.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/sys_vars/t/max_long_data_size_basic.test 2011-03-14 05:51:23 +0000 @@ -0,0 +1,17 @@ +select @@global.max_long_data_size=20; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.max_long_data_size; + +# Show that value of the variable matches the value in the GLOBAL I_S table +SELECT @@global.max_long_data_size = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='max_long_data_size'; + +# +# show that it's read-only +# +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set global max_long_data_size=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +set session max_long_data_size=1; + === modified file 'mysql-test/t/variables.test' --- a/mysql-test/t/variables.test 2011-02-10 07:34:22 +0000 +++ b/mysql-test/t/variables.test 2011-03-14 05:51:23 +0000 @@ -1281,6 +1281,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 parameter +# +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 2011-03-04 15:43:28 +0000 +++ b/sql/item.cc 2011-03-14 05:51:23 +0000 @@ -2885,6 +2885,17 @@ 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/mysqld.cc' --- a/sql/mysqld.cc 2011-03-10 08:43:55 +0000 +++ b/sql/mysqld.cc 2011-03-14 05:51:23 +0000 @@ -324,6 +324,7 @@ static PSI_rwlock_key key_rwlock_openssl /* 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; /* See Bug#56666 and Bug#56760 */; volatile bool ready_to_exit; @@ -478,6 +479,11 @@ ulong specialflag=0; ulong binlog_cache_use= 0, binlog_cache_disk_use= 0; ulong binlog_stmt_cache_use= 0, binlog_stmt_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; /** Limit of the total number of prepared statements in the server. Is necessary to protect the server against out-of-memory attacks. @@ -7155,6 +7161,10 @@ mysqld_get_one_option(int optid, if (argument == NULL) /* no argument */ log_error_file_ptr= const_cast(""); break; + case OPT_MAX_LONG_DATA_SIZE: + max_long_data_size_used= true; + WARN_DEPRECATED(NULL, 5, 6, "--max_long_data_size", "'--max_allowed_packet'"); + break; } return 0; } @@ -7381,6 +7391,13 @@ static int get_options(int *argc_ptr, ch opt_readonly= read_only; + /* + 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/mysqld.h' --- a/sql/mysqld.h 2011-03-10 08:43:55 +0000 +++ b/sql/mysqld.h 2011-03-14 05:51:23 +0000 @@ -126,6 +126,7 @@ extern char *default_storage_engine; extern bool opt_endinfo, using_udf_functions; extern my_bool locked_in_memory; extern bool opt_using_transactions; +extern ulong max_long_data_size; extern ulong current_pid; extern ulong expire_logs_days; extern my_bool relay_log_recovery; @@ -397,7 +398,8 @@ enum options_mysqld OPT_UPDATE_LOG, OPT_WANT_CORE, OPT_ENGINE_CONDITION_PUSHDOWN, - OPT_LOG_ERROR + OPT_LOG_ERROR, + OPT_MAX_LONG_DATA_SIZE }; === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2011-03-01 14:42:37 +0000 +++ b/sql/sql_prepare.cc 2011-03-14 05:51:23 +0000 @@ -2784,6 +2784,34 @@ 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_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) + { + stmt->state= Query_arena::ERROR; + stmt->last_errno= sql_errno; + strncpy(stmt->last_error, msg, MYSQL_ERRMSG_SIZE); + + return TRUE; + } + +private: + Prepared_statement *stmt; +}; + + /** Handle long data in pieces from client. @@ -2840,16 +2868,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); @@ -3389,6 +3420,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; @@ -3656,12 +3694,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 'sql/sys_vars.cc' --- a/sql/sys_vars.cc 2011-02-17 11:53:09 +0000 +++ b/sql/sys_vars.cc 2011-03-14 05:51:23 +0000 @@ -1182,6 +1182,16 @@ static Sys_var_harows Sys_sql_max_join_s NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_max_join_size), DEPRECATED(70000, 0)); +static Sys_var_ulong Sys_max_long_data_size( + "max_long_data_size", + "The maximum BLOB length to send to server from " + "mysql_send_long_data API. Deprecated option; " + "use max_allowed_packet instead.", + READ_ONLY GLOBAL_VAR(max_long_data_size), + CMD_LINE(REQUIRED_ARG, OPT_MAX_LONG_DATA_SIZE), + VALID_RANGE(1024, UINT_MAX32), DEFAULT(1024*1024), + BLOCK_SIZE(1)); + static PolyLock_mutex PLock_prepared_stmt_count(&LOCK_prepared_stmt_count); static Sys_var_ulong Sys_max_prepared_stmt_count( "max_prepared_stmt_count", === modified file 'tests/mysql_client_test.c' --- a/tests/mysql_client_test.c 2011-02-18 14:19:55 +0000 +++ b/tests/mysql_client_test.c 2011-03-14 05:51:23 +0000 @@ -19503,6 +19503,56 @@ static void test_bug57058() /* + 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= (char*) my_malloc(packet_len, MYF(0)); + DIE_UNLESS(long_buffer); + + 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); + } + + my_free(long_buffer); + 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 */ @@ -19838,6 +19888,7 @@ static struct my_tests_st my_tests[]= { { "test_bug47485", test_bug47485 }, { "test_bug58036", test_bug58036 }, { "test_bug57058", test_bug57058 }, + { "test_bug56976", test_bug56976 }, { 0, 0 } }; --===============7398099075202505160== 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\ # 057o56q003eafe04 # target_branch: file:///Users/shulga/projects/mysql/mysql-5.5/ # testament_sha1: af9850c844df96797fbfc2726bed667ed5190881 # timestamp: 2011-03-14 11:53:07 +0600 # source_branch: file:///Users/shulga/projects/mysql/mysql-5.1-\ # bug58887/ # base_revision_id: marc.alff@stripped\ # tzul0sqjz3cxj3n2 # # Begin bundle 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 --===============7398099075202505160==--