From: Dmitry Shulga Date: March 11 2011 10:43am Subject: bzr commit into mysql-5.5 branch (Dmitry.Shulga:3362) Bug#11764168 List-Archive: http://lists.mysql.com/commits/132803 X-Bug: 11764168 Message-Id: <201103111044.p2AImuW7025878@acsinet15.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1279323501565378497==" --===============1279323501565378497== 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-11 [merge] Manual merge from mysql-5.1 for Bug#11764168 (56976: Severe denial of service in prepared statements). 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-11 10:41:13 +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-11 10:41:13 +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-11 10:41:13 +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 2011-02-10 07:34:22 +0000 +++ b/mysql-test/t/variables.test 2011-03-11 10:41:13 +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-11 10:41:13 +0000 @@ -2885,6 +2885,20 @@ 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. */ + printf("Item_param::set_longdata::: max_long_data_size=%lu, str_value.length() + length=%lu\n", + max_long_data_size, str_value.length() + length); + + if (str_value.length() + length > max_long_data_size) + { + printf("Item_param::set_longdata::: max_long_data_size EXCEEDED\n"); + 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-11 10:41:13 +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-11 10:41:13 +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-11 10:41:13 +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-11 10:41:13 +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-11 10:41:13 +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 } }; --===============1279323501565378497== 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\ # mfyjbxo3cy66zb27 # target_branch: file:///Users/shulga/projects/mysql/mysql-5.5/ # testament_sha1: 73e8a60945f3f431c7ce9624d5f788fc46abad52 # timestamp: 2011-03-11 16:43:27 +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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 +VMqbw7Bik8Vf/F3JFOFCQGzZJbA --===============1279323501565378497==--