Below is the list of changes that have just been committed into a local
4.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.2473 06/02/07 14:27:42 andrey@lmy004. +7 -0
test
sql/sql_prepare.cc
1.156 06/02/07 14:27:36 andrey@lmy004. +3 -0
test
sql/sql_class.h
1.284 06/02/07 14:27:36 andrey@lmy004. +17 -1
test
sql/sql_class.cc
1.205 06/02/07 14:27:36 andrey@lmy004. +43 -4
test
sql/set_var.cc
1.179 06/02/07 14:27:36 andrey@lmy004. +4 -0
test
sql/mysqld.cc
1.610 06/02/07 14:27:36 andrey@lmy004. +11 -2
test
sql/mysql_priv.h
1.374 06/02/07 14:27:36 andrey@lmy004. +2 -2
test
mysql-test/t/ps_11bugs.test
1.6 06/02/07 14:27:36 andrey@lmy004. +59 -0
test
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: andrey
# Host: lmy004.
# Root: /work/mysql-4.1-bug16365
--- 1.373/sql/mysql_priv.h 2005-12-07 19:54:07 +01:00
+++ 1.374/sql/mysql_priv.h 2006-02-07 14:27:36 +01:00
@@ -916,7 +916,7 @@
extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong slave_net_timeout, slave_trans_retries;
-extern ulong max_user_connections;
+extern ulong max_user_connections, max_prepared_stmt_count, prepared_stmt_count;
extern ulong long_query_count, what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
@@ -960,7 +960,7 @@
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager,
- LOCK_global_system_variables, LOCK_user_conn;
+ LOCK_global_system_variables, LOCK_user_conn, LOCK_prepared_stmt_count;
#ifdef HAVE_OPENSSL
extern pthread_mutex_t LOCK_des_key_file;
#endif
--- 1.609/sql/mysqld.cc 2006-01-12 16:47:55 +01:00
+++ 1.610/sql/mysqld.cc 2006-02-07 14:27:36 +01:00
@@ -336,6 +336,7 @@
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
ulong max_connections,max_used_connections,
max_connect_errors, max_user_connections = 0;
+ulong max_prepared_stmt_count= 0, prepared_stmt_count=0;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0, sync_binlog_period;
ulong expire_logs_days = 0;
@@ -419,6 +420,7 @@
LOCK_error_log, LOCK_uuid_generator,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
+ LOCK_prepared_stmt_count,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
#ifdef HAVE_OPENSSL
@@ -1117,6 +1119,7 @@
(void) pthread_mutex_destroy(&LOCK_active_mi);
(void) rwlock_destroy(&LOCK_sys_init_connect);
(void) rwlock_destroy(&LOCK_sys_init_slave);
+ (void) pthread_mutex_destroy(&LOCK_prepared_stmt_count);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
@@ -2634,6 +2637,7 @@
(void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
#ifdef HAVE_OPENSSL
@@ -4237,8 +4241,8 @@
OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET,
OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
- OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE,
- OPT_MAX_JOIN_SIZE, OPT_MAX_RELAY_LOG_SIZE, OPT_MAX_SORT_LENGTH,
+ OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE, OPT_MAX_JOIN_SIZE,
+ OPT_MAX_PS_STMT_COUNT, OPT_MAX_RELAY_LOG_SIZE, OPT_MAX_SORT_LENGTH,
OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
OPT_MAX_LENGTH_FOR_SORT_DATA,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
@@ -5225,6 +5229,10 @@
(gptr*) &global_system_variables.max_length_for_sort_data,
(gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
+ {"max_prepared_stmt_count", OPT_MAX_PS_STMT_COUNT,
+ "The maximal number of simultaneous open prepared statement handlers in the server.",
+ (gptr*) &max_prepared_stmt_count, (gptr*) &max_prepared_stmt_count,
+ 0, GET_ULONG, REQUIRED_ARG, 16382, 0, 1*1024*1024L, 0, 1, 0},
{"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
"If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 excepted, the minimum value for this variable is 4096.",
(gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG,
@@ -5642,6 +5650,7 @@
{"Open_streams", (char*) &my_stream_opened, SHOW_LONG_CONST},
{"Open_tables", (char*) 0, SHOW_OPENTABLES},
{"Opened_tables", (char*) &opened_tables, SHOW_LONG},
+ {"Prepared statements", (char*) &prepared_stmt_count, SHOW_LONG_CONST},
#ifdef HAVE_QUERY_CACHE
{"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
SHOW_LONG_CONST},
--- 1.204/sql/sql_class.cc 2006-01-18 12:49:33 +01:00
+++ 1.205/sql/sql_class.cc 2006-02-07 14:27:36 +01:00
@@ -1618,9 +1618,29 @@
int Statement_map::insert(Statement *statement)
{
- int rc= my_hash_insert(&st_hash, (byte *) statement);
- if (rc == 0)
- last_found_statement= statement;
+ my_bool error_on_not_swapping= FALSE;
+ int rc;
+
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ ++prepared_stmt_count;
+ if (max_prepared_stmt_count && (prepared_stmt_count > max_prepared_stmt_count))
+ {
+ if (!statement->name.str)
+ {
+ /*
+ decrement only in this case.
+ if we exchange -> ::erase(old_stmt) will decrement
+ if not exchange -> then we will
+ */
+ --prepared_stmt_count;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ send_error(current_thd, ER_OUT_OF_RESOURCES);
+ return 1;
+ }
+ error_on_not_swapping= TRUE;
+ }
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+
if (statement->name.str)
{
/*
@@ -1629,10 +1649,29 @@
*/
Statement *old_stmt;
if ((old_stmt= find_by_name(&statement->name)))
- erase(old_stmt);
+ erase(old_stmt);
+ else if (error_on_not_swapping)
+ {
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ --prepared_stmt_count;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ return 1;
+ }
+
if ((rc= my_hash_insert(&names_hash, (byte*)statement)))
hash_delete(&st_hash, (byte*)statement);
}
+
+ rc= my_hash_insert(&st_hash, (byte *) statement);
+ if (rc == 0)
+ last_found_statement= statement;
+ else
+ {
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ --prepared_stmt_count;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+ }
+
return rc;
}
--- 1.283/sql/sql_class.h 2005-09-21 00:18:26 +02:00
+++ 1.284/sql/sql_class.h 2006-02-07 14:27:36 +01:00
@@ -603,7 +603,8 @@
virtual Type type() const;
};
-
+extern ulong max_prepared_stmt_count, prepared_stmt_count;
+extern pthread_mutex_t LOCK_prepared_stmt_count;
/*
Container for all statements created/used in a connection.
Statements in Statement_map have unique Statement::id (guaranteed by id
@@ -651,10 +652,20 @@
hash_delete(&names_hash, (byte *) statement);
}
hash_delete(&st_hash, (byte *) statement);
+
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ DBUG_ASSERT(prepared_stmt_count);
+ --prepared_stmt_count;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
}
/* Erase all statements (calls Statement destructor) */
void reset()
{
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
+ prepared_stmt_count-= st_hash.records;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+
my_hash_reset(&names_hash);
my_hash_reset(&st_hash);
last_found_statement= 0;
@@ -662,6 +673,11 @@
~Statement_map()
{
+ pthread_mutex_lock(&LOCK_prepared_stmt_count);
+ DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
+ prepared_stmt_count-= st_hash.records;
+ pthread_mutex_unlock(&LOCK_prepared_stmt_count);
+
hash_free(&names_hash);
hash_free(&st_hash);
}
--- 1.5/mysql-test/t/ps_11bugs.test 2005-07-28 02:21:46 +02:00
+++ 1.6/mysql-test/t/ps_11bugs.test 2006-02-07 14:27:36 +01:00
@@ -129,4 +129,63 @@
# end of bug#1676
+# bug#16365: Prepared Statements: DoS with too many open statements
+set @old_max_ps_stmt_count:= @max_prepared_stmt_count;
+set global max_prepared_stmt_count= 0;
+show variables like 'max_prepared_stmt_count';
+prepare ss1 from "select 1";
+prepare ss2 from "select 2";
+show status like 'Prepared%';
+flush status;
+show status like 'Prepared%';
+deallocate prepare ss1;
+deallocate prepare ss2;
+set global max_prepared_stmt_count= 5;
+show variables like 'max_prepared_stmt_count';
+prepare st1 from "select 1";
+prepare st2 from "select 2";
+prepare st3 from "select 3";
+prepare st4 from "select 4";
+prepare st5 from "select 5";
+--error 1041
+prepare st6 from "select 6";
+#now we exchange st2 with a new statement - this is allowed
+prepare st2 from "select 222";
+#connect (new_con,localhost,root,,test);
+#--error 1041
+#prepare new_st1 from "select 10";
+#connection default;
+#deallocate prepare st2;
+#deallocate prepare st3;
+#deallocate prepare st4;
+#connection new_con;
+#prepare new_st1 from "select 10";
+#prepare new_st2 from "select 20";
+#prepare new_st3 from "select 30";
+#--error 1041
+#prepare new_st4 from "select 40";
+#connection default;
+#--error 1041
+#prepare st3 from "select 3";
+#show status like 'Prepared%';
+#connection new_con1;
+#KILL CONNECTION_ID();
+#connection default;
+#show status like 'Prepared%';
+#prepare st6 from "select 6";
+#prepare st7 from "select 7";
+#prepare st8 from "select 8";
+#--error 1041
+#prepare st9 from "select 9";
+deallocate prepare st1;
+deallocate prepare st2;
+deallocate prepare st3;
+deallocate prepare st4;
+deallocate prepare st5;
+#deallocate prepare st6;
+#deallocate prepare st7;
+#deallocate prepare st8;
+show status like 'Prepared%';
+set global max_prepared_stmt_count= @old_max_ps_stmt_count:
+#end of bug#16365
# End of 4.1 tests
--- 1.178/sql/set_var.cc 2005-09-21 00:18:26 +02:00
+++ 1.179/sql/set_var.cc 2006-02-07 14:27:36 +01:00
@@ -239,6 +239,8 @@
&SV::max_join_size,
fix_max_join_size);
#endif
+sys_var_long_ptr sys_max_prepared_stmt_count("max_prepared_stmt_count",
+ &max_prepared_stmt_count);
sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size",
&max_relay_log_size,
fix_max_relay_log_size);
@@ -569,6 +571,7 @@
&sys_max_heap_table_size,
&sys_max_join_size,
&sys_max_length_for_sort_data,
+ &sys_max_prepared_stmt_count,
&sys_max_relay_log_size,
&sys_max_seeks_for_key,
&sys_max_sort_length,
@@ -801,6 +804,7 @@
{sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS},
{sys_max_length_for_sort_data.name, (char*) &sys_max_length_for_sort_data,
SHOW_SYS},
+ {sys_max_prepared_stmt_count.name,(char*) &sys_max_prepared_stmt_count,SHOW_SYS},
{sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS},
{sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS},
{sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS},
--- 1.155/sql/sql_prepare.cc 2005-09-25 20:22:21 +02:00
+++ 1.156/sql/sql_prepare.cc 2006-02-07 14:27:36 +01:00
@@ -75,6 +75,9 @@
#include <mysql.h>
#endif
+
+
+
/******************************************************************************
Prepared_statement: statement which can contain placeholders
******************************************************************************/
| Thread |
|---|
| • bk commit into 4.1 tree (andrey:1.2473) | ahristov | 7 Feb |