Bug#11765108 (Bug#58036) client utf32, utf16, ucs2 should be disallowed, they crash server
A separate fix for 5.1 (as 5.1 and 5.5 have seriously differged in the related pieces of the code). A patch for 5.5 was approved earlier. Problem: ucs2 was correctly disallowed in "SET NAMES" only, while mysql_real_connect() and mysql_change_user() still allowed to use ucs2, which made server crash. Fix: disallow ucs2 in mysql_real_connect() and mysql_change_user(). @ sql/sql_priv.h - changing return type for thd_init_client_charset() to bool, to return errors to the caller @ sql/sql_var.cc - using new function @ sql/sql_connect.cc - thd_client_charset_init: in case of unsupported client character set send error and return true; in case of success return false - check_connection: Return error if character set initialization failed @ sql/sql_parse.cc - check charset in the very beginnig of the CMD_CHANGE_USER handling code @ tests/mysql_client_test.c - adding tests
This commit is contained in:
parent
f912dcd82e
commit
8a96012922
@ -1019,7 +1019,11 @@ void reset_mqh(LEX_USER *lu, bool get_them);
|
||||
bool check_mqh(THD *thd, uint check_command);
|
||||
void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
|
||||
void decrease_user_connections(USER_CONN *uc);
|
||||
void thd_init_client_charset(THD *thd, uint cs_number);
|
||||
bool thd_init_client_charset(THD *thd, uint cs_number);
|
||||
inline bool is_supported_parser_charset(CHARSET_INFO *cs)
|
||||
{
|
||||
return test(cs->mbminlen == 1);
|
||||
}
|
||||
bool setup_connection_thread_globals(THD *thd);
|
||||
|
||||
int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
|
||||
|
@ -2187,7 +2187,7 @@ bool sys_var_character_set_client::check(THD *thd, set_var *var)
|
||||
if (sys_var_character_set_sv::check(thd, var))
|
||||
return 1;
|
||||
/* Currently, UCS-2 cannot be used as a client character set */
|
||||
if (var->save_result.charset->mbminlen > 1)
|
||||
if (!is_supported_parser_charset(var->save_result.charset))
|
||||
{
|
||||
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name,
|
||||
var->save_result.charset->csname);
|
||||
|
@ -582,8 +582,23 @@ void reset_mqh(LEX_USER *lu, bool get_them= 0)
|
||||
}
|
||||
|
||||
|
||||
void thd_init_client_charset(THD *thd, uint cs_number)
|
||||
/**
|
||||
Set thread character set variables from the given ID
|
||||
|
||||
@param thd thread handle
|
||||
@param cs_number character set and collation ID
|
||||
|
||||
@retval 0 OK; character_set_client, collation_connection and
|
||||
character_set_results are set to the new value,
|
||||
or to the default global values.
|
||||
|
||||
@retval 1 error, e.g. the given ID is not supported by parser.
|
||||
Corresponding SQL error is sent.
|
||||
*/
|
||||
|
||||
bool thd_init_client_charset(THD *thd, uint cs_number)
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
/*
|
||||
Use server character set and collation if
|
||||
- opt_character_set_client_handshake is not set
|
||||
@ -592,10 +607,10 @@ void thd_init_client_charset(THD *thd, uint cs_number)
|
||||
- client character set doesn't exists in server
|
||||
*/
|
||||
if (!opt_character_set_client_handshake ||
|
||||
!(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
|
||||
!(cs= get_charset(cs_number, MYF(0))) ||
|
||||
!my_strcasecmp(&my_charset_latin1,
|
||||
global_system_variables.character_set_client->name,
|
||||
thd->variables.character_set_client->name))
|
||||
cs->name))
|
||||
{
|
||||
thd->variables.character_set_client=
|
||||
global_system_variables.character_set_client;
|
||||
@ -606,10 +621,18 @@ void thd_init_client_charset(THD *thd, uint cs_number)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_supported_parser_charset(cs))
|
||||
{
|
||||
/* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
|
||||
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
|
||||
cs->csname);
|
||||
return true;
|
||||
}
|
||||
thd->variables.character_set_results=
|
||||
thd->variables.collation_connection=
|
||||
thd->variables.character_set_client;
|
||||
thd->variables.character_set_client= cs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -782,7 +805,8 @@ static int check_connection(THD *thd)
|
||||
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
|
||||
thd->max_client_packet_length= uint4korr(net->read_pos+4);
|
||||
DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
|
||||
thd_init_client_charset(thd, (uint) net->read_pos[8]);
|
||||
if (thd_init_client_charset(thd, (uint) net->read_pos[8]))
|
||||
return 1;
|
||||
thd->update_charset();
|
||||
end= (char*) net->read_pos+32;
|
||||
}
|
||||
|
@ -1153,13 +1153,22 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
|
||||
if (ptr < packet_end)
|
||||
{
|
||||
CHARSET_INFO *cs;
|
||||
if (ptr + 2 > packet_end)
|
||||
{
|
||||
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
|
||||
break;
|
||||
}
|
||||
|
||||
cs_number= uint2korr(ptr);
|
||||
if ((cs_number= uint2korr(ptr)) &&
|
||||
(cs= get_charset(cs_number, MYF(0))) &&
|
||||
!is_supported_parser_charset(cs))
|
||||
{
|
||||
/* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
|
||||
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
|
||||
cs->csname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert database name to utf8 */
|
||||
@ -1205,7 +1214,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
|
||||
if (cs_number)
|
||||
{
|
||||
thd_init_client_charset(thd, cs_number);
|
||||
/*
|
||||
We have checked charset earlier,
|
||||
so thd_init_client_charset cannot fail.
|
||||
*/
|
||||
DBUG_ASSERT(!thd_init_client_charset(thd, cs_number));
|
||||
thd->update_charset();
|
||||
}
|
||||
}
|
||||
|
@ -18398,6 +18398,72 @@ static void test_bug47485()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Bug#58036 client utf32, utf16, ucs2 should be disallowed, they crash server
|
||||
*/
|
||||
static void test_bug58036()
|
||||
{
|
||||
MYSQL *conn;
|
||||
DBUG_ENTER("test_bug47485");
|
||||
myheader("test_bug58036");
|
||||
|
||||
/* Part1: try to connect with ucs2 client character set */
|
||||
conn= mysql_client_init(NULL);
|
||||
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "ucs2");
|
||||
if (mysql_real_connect(conn, opt_host, opt_user,
|
||||
opt_password, opt_db ? opt_db : "test",
|
||||
opt_port, opt_unix_socket, 0))
|
||||
{
|
||||
if (!opt_silent)
|
||||
printf("mysql_real_connect() succeeded (failure expected)\n");
|
||||
mysql_close(conn);
|
||||
DIE();
|
||||
}
|
||||
|
||||
if (!opt_silent)
|
||||
printf("Got mysql_real_connect() error (expected): %s (%d)\n",
|
||||
mysql_error(conn), mysql_errno(conn));
|
||||
DIE_UNLESS(mysql_errno(conn) == ER_WRONG_VALUE_FOR_VAR);
|
||||
mysql_close(conn);
|
||||
|
||||
|
||||
/*
|
||||
Part2:
|
||||
- connect with latin1
|
||||
- then change client character set to ucs2
|
||||
- then try mysql_change_user()
|
||||
*/
|
||||
conn= mysql_client_init(NULL);
|
||||
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "latin1");
|
||||
if (!mysql_real_connect(conn, opt_host, opt_user,
|
||||
opt_password, opt_db ? opt_db : "test",
|
||||
opt_port, opt_unix_socket, 0))
|
||||
{
|
||||
if (!opt_silent)
|
||||
printf("mysql_real_connect() failed: %s (%d)\n",
|
||||
mysql_error(conn), mysql_errno(conn));
|
||||
mysql_close(conn);
|
||||
DIE();
|
||||
}
|
||||
|
||||
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "ucs2");
|
||||
if (!mysql_change_user(conn, opt_user, opt_password, NULL))
|
||||
{
|
||||
if (!opt_silent)
|
||||
printf("mysql_change_user() succedded, error expected!");
|
||||
mysql_close(conn);
|
||||
DIE();
|
||||
}
|
||||
|
||||
if (!opt_silent)
|
||||
printf("Got mysql_change_user() error (expected): %s (%d)\n",
|
||||
mysql_error(conn), mysql_errno(conn));
|
||||
mysql_close(conn);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
*/
|
||||
@ -18724,6 +18790,7 @@ static struct my_tests_st my_tests[]= {
|
||||
{ "test_bug42373", test_bug42373 },
|
||||
{ "test_bug54041", test_bug54041 },
|
||||
{ "test_bug47485", test_bug47485 },
|
||||
{ "test_bug58036", test_bug58036 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user