mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
Manual merge from mysql-5.1 for Bug#11764168 (56976: Severe denial
of service in prepared statements).
This commit is contained in:
@ -309,6 +309,10 @@ The following options may be given as the first argument:
|
|||||||
max_join_size records return an error
|
max_join_size records return an error
|
||||||
--max-length-for-sort-data=#
|
--max-length-for-sort-data=#
|
||||||
Max number of bytes in sorted records
|
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=#
|
--max-prepared-stmt-count=#
|
||||||
Maximum number of prepared statements in the server
|
Maximum number of prepared statements in the server
|
||||||
--max-relay-log-size=#
|
--max-relay-log-size=#
|
||||||
@ -830,6 +834,7 @@ max-error-count 64
|
|||||||
max-heap-table-size 16777216
|
max-heap-table-size 16777216
|
||||||
max-join-size 18446744073709551615
|
max-join-size 18446744073709551615
|
||||||
max-length-for-sort-data 1024
|
max-length-for-sort-data 1024
|
||||||
|
max-long-data-size 1048576
|
||||||
max-prepared-stmt-count 16382
|
max-prepared-stmt-count 16382
|
||||||
max-relay-log-size 0
|
max-relay-log-size 0
|
||||||
max-seeks-for-key 18446744073709551615
|
max-seeks-for-key 18446744073709551615
|
||||||
|
@ -308,6 +308,10 @@ The following options may be given as the first argument:
|
|||||||
max_join_size records return an error
|
max_join_size records return an error
|
||||||
--max-length-for-sort-data=#
|
--max-length-for-sort-data=#
|
||||||
Max number of bytes in sorted records
|
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=#
|
--max-prepared-stmt-count=#
|
||||||
Maximum number of prepared statements in the server
|
Maximum number of prepared statements in the server
|
||||||
--max-relay-log-size=#
|
--max-relay-log-size=#
|
||||||
@ -833,6 +837,7 @@ max-error-count 64
|
|||||||
max-heap-table-size 16777216
|
max-heap-table-size 16777216
|
||||||
max-join-size 18446744073709551615
|
max-join-size 18446744073709551615
|
||||||
max-length-for-sort-data 1024
|
max-length-for-sort-data 1024
|
||||||
|
max-long-data-size 1048576
|
||||||
max-prepared-stmt-count 16382
|
max-prepared-stmt-count 16382
|
||||||
max-relay-log-size 0
|
max-relay-log-size 0
|
||||||
max-seeks-for-key 18446744073709551615
|
max-seeks-for-key 18446744073709551615
|
||||||
|
@ -1540,6 +1540,9 @@ ERROR HY000: Cannot drop default keycache
|
|||||||
SET @@global.key_cache_block_size=0;
|
SET @@global.key_cache_block_size=0;
|
||||||
Warnings:
|
Warnings:
|
||||||
Warning 1292 Truncated incorrect key_cache_block_size value: '0'
|
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_binlog_cache_size=DEFAULT;
|
||||||
SET @@global.max_join_size=DEFAULT;
|
SET @@global.max_join_size=DEFAULT;
|
||||||
SET @@global.key_buffer_size=@kbs;
|
SET @@global.key_buffer_size=@kbs;
|
||||||
|
14
mysql-test/suite/sys_vars/r/max_long_data_size_basic.result
Normal file
14
mysql-test/suite/sys_vars/r/max_long_data_size_basic.result
Normal file
@ -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
|
17
mysql-test/suite/sys_vars/t/max_long_data_size_basic.test
Normal file
17
mysql-test/suite/sys_vars/t/max_long_data_size_basic.test
Normal file
@ -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;
|
||||||
|
|
@ -1281,6 +1281,11 @@ SET @@global.max_join_size=0;
|
|||||||
SET @@global.key_buffer_size=0;
|
SET @@global.key_buffer_size=0;
|
||||||
SET @@global.key_cache_block_size=0;
|
SET @@global.key_cache_block_size=0;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#56976: added new start-up parameter
|
||||||
|
#
|
||||||
|
select @@max_long_data_size;
|
||||||
|
|
||||||
# cleanup
|
# cleanup
|
||||||
SET @@global.max_binlog_cache_size=DEFAULT;
|
SET @@global.max_binlog_cache_size=DEFAULT;
|
||||||
SET @@global.max_join_size=DEFAULT;
|
SET @@global.max_join_size=DEFAULT;
|
||||||
|
10
sql/item.cc
10
sql/item.cc
@ -2885,6 +2885,16 @@ bool Item_param::set_longdata(const char *str, ulong length)
|
|||||||
(here), and first have to concatenate all pieces together,
|
(here), and first have to concatenate all pieces together,
|
||||||
write query to the binary log and only then perform conversion.
|
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))
|
if (str_value.append(str, length, &my_charset_bin))
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
state= LONG_DATA_VALUE;
|
state= LONG_DATA_VALUE;
|
||||||
|
@ -324,6 +324,7 @@ static PSI_rwlock_key key_rwlock_openssl;
|
|||||||
|
|
||||||
/* the default log output is log tables */
|
/* the default log output is log tables */
|
||||||
static bool lower_case_table_names_used= 0;
|
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 select_thread_in_use, signal_thread_in_use;
|
||||||
/* See Bug#56666 and Bug#56760 */;
|
/* See Bug#56666 and Bug#56760 */;
|
||||||
volatile bool ready_to_exit;
|
volatile bool ready_to_exit;
|
||||||
@ -478,6 +479,11 @@ ulong specialflag=0;
|
|||||||
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
|
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
|
||||||
ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0;
|
ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0;
|
||||||
ulong max_connections, max_connect_errors;
|
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.
|
Limit of the total number of prepared statements in the server.
|
||||||
Is necessary to protect the server against out-of-memory attacks.
|
Is necessary to protect the server against out-of-memory attacks.
|
||||||
@ -7160,6 +7166,10 @@ mysqld_get_one_option(int optid,
|
|||||||
if (argument == NULL) /* no argument */
|
if (argument == NULL) /* no argument */
|
||||||
log_error_file_ptr= const_cast<char*>("");
|
log_error_file_ptr= const_cast<char*>("");
|
||||||
break;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -7386,6 +7396,13 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
|
|||||||
|
|
||||||
opt_readonly= read_only;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@ extern char *default_storage_engine;
|
|||||||
extern bool opt_endinfo, using_udf_functions;
|
extern bool opt_endinfo, using_udf_functions;
|
||||||
extern my_bool locked_in_memory;
|
extern my_bool locked_in_memory;
|
||||||
extern bool opt_using_transactions;
|
extern bool opt_using_transactions;
|
||||||
|
extern ulong max_long_data_size;
|
||||||
extern ulong current_pid;
|
extern ulong current_pid;
|
||||||
extern ulong expire_logs_days;
|
extern ulong expire_logs_days;
|
||||||
extern my_bool relay_log_recovery;
|
extern my_bool relay_log_recovery;
|
||||||
@ -397,7 +398,8 @@ enum options_mysqld
|
|||||||
OPT_UPDATE_LOG,
|
OPT_UPDATE_LOG,
|
||||||
OPT_WANT_CORE,
|
OPT_WANT_CORE,
|
||||||
OPT_ENGINE_CONDITION_PUSHDOWN,
|
OPT_ENGINE_CONDITION_PUSHDOWN,
|
||||||
OPT_LOG_ERROR
|
OPT_LOG_ERROR,
|
||||||
|
OPT_MAX_LONG_DATA_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2784,6 +2784,7 @@ void mysql_sql_stmt_close(THD *thd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Handle long data in pieces from client.
|
Handle long data in pieces from client.
|
||||||
|
|
||||||
@ -2840,16 +2841,25 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
|
|||||||
|
|
||||||
param= stmt->param_array[param_number];
|
param= stmt->param_array[param_number];
|
||||||
|
|
||||||
|
Diagnostics_area new_stmt_da, *save_stmt_da= thd->stmt_da;
|
||||||
|
Warning_info new_warnning_info(thd->query_id), *save_warinig_info= thd->warning_info;
|
||||||
|
|
||||||
|
thd->stmt_da= &new_stmt_da;
|
||||||
|
thd->warning_info= &new_warnning_info;
|
||||||
|
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
if (param->set_longdata(packet, (ulong) (packet_end - packet)))
|
param->set_longdata(packet, (ulong) (packet_end - packet));
|
||||||
#else
|
#else
|
||||||
if (param->set_longdata(thd->extra_data, thd->extra_length))
|
param->set_longdata(thd->extra_data, thd->extra_length);
|
||||||
#endif
|
#endif
|
||||||
|
if (thd->stmt_da->is_error())
|
||||||
{
|
{
|
||||||
stmt->state= Query_arena::ERROR;
|
stmt->state= Query_arena::ERROR;
|
||||||
stmt->last_errno= ER_OUTOFMEMORY;
|
stmt->last_errno= thd->stmt_da->sql_errno();
|
||||||
sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
|
strncpy(stmt->last_error, thd->stmt_da->message(), MYSQL_ERRMSG_SIZE);
|
||||||
}
|
}
|
||||||
|
thd->stmt_da= save_stmt_da;
|
||||||
|
thd->warning_info= save_warinig_info;
|
||||||
|
|
||||||
general_log_print(thd, thd->command, NullS);
|
general_log_print(thd, thd->command, NullS);
|
||||||
|
|
||||||
@ -3389,6 +3399,13 @@ Prepared_statement::execute_loop(String *expanded_query,
|
|||||||
bool error;
|
bool error;
|
||||||
int reprepare_attempt= 0;
|
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))
|
if (set_parameters(expanded_query, packet, packet_end))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
@ -3656,12 +3673,6 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||||||
|
|
||||||
status_var_increment(thd->status_var.com_stmt_execute);
|
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)
|
if (flags & (uint) IS_IN_USE)
|
||||||
{
|
{
|
||||||
my_error(ER_PS_NO_RECURSION, MYF(0));
|
my_error(ER_PS_NO_RECURSION, MYF(0));
|
||||||
|
@ -1182,6 +1182,16 @@ static Sys_var_harows Sys_sql_max_join_size(
|
|||||||
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
|
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
|
||||||
ON_UPDATE(fix_max_join_size), DEPRECATED(70000, 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 PolyLock_mutex PLock_prepared_stmt_count(&LOCK_prepared_stmt_count);
|
||||||
static Sys_var_ulong Sys_max_prepared_stmt_count(
|
static Sys_var_ulong Sys_max_prepared_stmt_count(
|
||||||
"max_prepared_stmt_count",
|
"max_prepared_stmt_count",
|
||||||
|
@ -19464,6 +19464,56 @@ static void test_bug49972()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Bug#57058 SERVER_QUERY_WAS_SLOW not wired up.
|
Bug#57058 SERVER_QUERY_WAS_SLOW not wired up.
|
||||||
*/
|
*/
|
||||||
@ -19838,6 +19888,7 @@ static struct my_tests_st my_tests[]= {
|
|||||||
{ "test_bug47485", test_bug47485 },
|
{ "test_bug47485", test_bug47485 },
|
||||||
{ "test_bug58036", test_bug58036 },
|
{ "test_bug58036", test_bug58036 },
|
||||||
{ "test_bug57058", test_bug57058 },
|
{ "test_bug57058", test_bug57058 },
|
||||||
|
{ "test_bug56976", test_bug56976 },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user