Commit 0bf843cd authored by Alexander Barkov's avatar Alexander Barkov

MDEV-20366 Server crashes in get_current_user upon SET PASSWORD via SP

The opt_for_user subrule was incorrectly scanned before sp_create_assignment_lex(),
so the user name and the host were created on a wrong memory root.

- Reoganizing the grammar to make sure that sp_create_assignment_lex()
  is called immediately after PASSWORD_SYM is scanned, so all attributes
  are then allocated on its memory root.

- Moving the semantic code as methods to LEX, so the grammar looks as simple as possible.

- Changing text_or_password to be of the data type USER_AUTH*.
  As a side effect, the LEX::definer member is now not used when processing
  the SET PASSWORD statement. Everything is done using Bison's stack.

The bug sas introduced by this commit:
commit bf5a144e
parent ccdfcedf
...@@ -802,3 +802,21 @@ connection default; ...@@ -802,3 +802,21 @@ connection default;
DROP DATABASE u1; DROP DATABASE u1;
DROP USER u1@localhost; DROP USER u1@localhost;
set @@global.character_set_server=@save_character_set_server; set @@global.character_set_server=@save_character_set_server;
#
# Start of 10.5 tests
#
#
# MDEV-20366 Server crashes in get_current_user upon SET PASSWORD via SP
#
CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x');
CALL p1();
ERROR 28000: Can't find any matching row in the user table
DROP PROCEDURE p1;
CREATE USER foo@localhost;
CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x');
CALL p1();
DROP PROCEDURE p1;
DROP USER foo@localhost;
#
# End of 10.5 tests
#
...@@ -1078,3 +1078,30 @@ DROP DATABASE u1; ...@@ -1078,3 +1078,30 @@ DROP DATABASE u1;
DROP USER u1@localhost; DROP USER u1@localhost;
set @@global.character_set_server=@save_character_set_server; set @@global.character_set_server=@save_character_set_server;
--echo #
--echo # Start of 10.5 tests
--echo #
--echo #
--echo # MDEV-20366 Server crashes in get_current_user upon SET PASSWORD via SP
--echo #
# Testing without the user
CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x');
--error ER_PASSWORD_NO_MATCH
CALL p1();
DROP PROCEDURE p1;
# Testing with the user
CREATE USER foo@localhost;
CREATE PROCEDURE p1() SET PASSWORD FOR foo@localhost=PASSWORD('x');
CALL p1();
DROP PROCEDURE p1;
DROP USER foo@localhost;
--echo #
--echo # End of 10.5 tests
--echo #
...@@ -11393,3 +11393,36 @@ bool LEX::stmt_revoke_proxy(THD *thd, LEX_USER *user) ...@@ -11393,3 +11393,36 @@ bool LEX::stmt_revoke_proxy(THD *thd, LEX_USER *user)
return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command, return !(m_sql_cmd= new (thd->mem_root) Sql_cmd_grant_proxy(sql_command,
NO_ACL)); NO_ACL));
} }
LEX_USER *LEX::current_user_for_set_password(THD *thd)
{
LEX_CSTRING pw= { STRING_WITH_LEN("password") };
if (unlikely(spcont && spcont->find_variable(&pw, false)))
{
my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
return NULL;
}
LEX_USER *res;
if (unlikely(!(res= (LEX_USER*) thd->calloc(sizeof(LEX_USER)))))
return NULL;
res->user= current_user;
return res;
}
bool LEX::sp_create_set_password_instr(THD *thd,
LEX_USER *user,
USER_AUTH *auth,
bool no_lookahead)
{
user->auth= auth;
set_var_password *var= new (thd->mem_root) set_var_password(user);
if (unlikely(var == NULL) ||
unlikely(var_list.push_back(var, thd->mem_root)))
return true;
autocommit= true;
if (sphead)
sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
return sp_create_assignment_instr(thd, no_lookahead);
}
...@@ -3864,6 +3864,21 @@ struct LEX: public Query_tables_list ...@@ -3864,6 +3864,21 @@ struct LEX: public Query_tables_list
const Column_definition &ref, const Column_definition &ref,
Row_definition_list *fields, Row_definition_list *fields,
Item *def); Item *def);
LEX_USER *current_user_for_set_password(THD *thd);
bool sp_create_set_password_instr(THD *thd,
LEX_USER *user,
USER_AUTH *auth,
bool no_lookahead);
bool sp_create_set_password_instr(THD *thd,
USER_AUTH *auth,
bool no_lookahead)
{
LEX_USER *user;
return !(user= current_user_for_set_password(thd)) ||
sp_create_set_password_instr(thd, user, auth, no_lookahead);
}
bool sp_handler_declaration_init(THD *thd, int type); bool sp_handler_declaration_init(THD *thd, int type);
bool sp_handler_declaration_finalize(THD *thd, int type); bool sp_handler_declaration_finalize(THD *thd, int type);
......
...@@ -1543,6 +1543,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ ...@@ -1543,6 +1543,7 @@ End SQL_MODE_ORACLE_SPECIFIC */
admin_option_for_role user_maybe_role admin_option_for_role user_maybe_role
%type <user_auth> opt_auth_str auth_expression auth_token %type <user_auth> opt_auth_str auth_expression auth_token
text_or_password
%type <charset> %type <charset>
opt_collate opt_collate
...@@ -16433,25 +16434,30 @@ option_value_no_option_type: ...@@ -16433,25 +16434,30 @@ option_value_no_option_type:
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| PASSWORD_SYM opt_for_user text_or_password | PASSWORD_SYM equal
{ {
if (sp_create_assignment_lex(thd, $1.pos())) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT; MYSQL_YYABORT;
LEX *lex = Lex; }
set_var_password *var= (new (thd->mem_root) text_or_password
set_var_password(lex->definer)); {
if (unlikely(var == NULL) || if (unlikely(Lex->sp_create_set_password_instr(thd, $4,
unlikely(lex->var_list.push_back(var, thd->mem_root))) yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->autocommit= TRUE; }
if (lex->sphead) | PASSWORD_SYM FOR_SYM
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; {
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
user equal text_or_password
{
if (unlikely(Lex->sp_create_set_password_instr(thd, $4, $6,
yychar == YYEMPTY)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
; ;
transaction_characteristics: transaction_characteristics:
transaction_access_mode transaction_access_mode
| isolation_level | isolation_level
...@@ -16508,42 +16514,25 @@ isolation_types: ...@@ -16508,42 +16514,25 @@ isolation_types:
| SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; } | SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; }
; ;
opt_for_user:
equal
{
LEX *lex= thd->lex;
sp_pcontext *spc= lex->spcont;
LEX_CSTRING pw= { STRING_WITH_LEN("password") };
if (unlikely(spc && spc->find_variable(&pw, false)))
my_yyabort_error((ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str));
if (unlikely(!(lex->definer= (LEX_USER*)
thd->calloc(sizeof(LEX_USER)))))
MYSQL_YYABORT;
lex->definer->user= current_user;
lex->definer->auth= new (thd->mem_root) USER_AUTH();
}
| FOR_SYM user equal { Lex->definer= $2; }
;
text_or_password: text_or_password:
TEXT_STRING TEXT_STRING
{ {
Lex->definer->auth= new (thd->mem_root) USER_AUTH(); $$= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->auth_str= $1; $$->auth_str= $1;
} }
| PASSWORD_SYM '(' TEXT_STRING ')' | PASSWORD_SYM '(' TEXT_STRING ')'
{ {
Lex->definer->auth= new (thd->mem_root) USER_AUTH(); $$= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->pwtext= $3; $$->pwtext= $3;
} }
| OLD_PASSWORD_SYM '(' TEXT_STRING ')' | OLD_PASSWORD_SYM '(' TEXT_STRING ')'
{ {
Lex->definer->auth= new (thd->mem_root) USER_AUTH(); $$= new (thd->mem_root) USER_AUTH();
Lex->definer->auth->pwtext= $3; $$->pwtext= $3;
Lex->definer->auth->auth_str.str= Item_func_password::alloc(thd, $$->auth_str.str= Item_func_password::alloc(thd,
$3.str, $3.length, Item_func_password::OLD); $3.str, $3.length, Item_func_password::OLD);
Lex->definer->auth->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; $$->auth_str.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
} }
; ;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment