diff options
author | Alexander Barkov <bar@mariadb.com> | 2020-05-30 13:50:37 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2020-05-30 14:00:56 +0400 |
commit | 0bf843cd13981b03920bfc49c646b28a130f5d47 (patch) | |
tree | b66a252f27ac6e4d1fbe3430ad09fc478ec20592 | |
parent | ccdfcedf10610a32ce7d173e2936c29cb10df75c (diff) | |
download | mariadb-git-0bf843cd13981b03920bfc49c646b28a130f5d47.tar.gz |
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 bf5a144e1692f6cc6a6d781b7e75ff4abf32bdf3
-rw-r--r-- | mysql-test/main/sp-security.result | 18 | ||||
-rw-r--r-- | mysql-test/main/sp-security.test | 27 | ||||
-rw-r--r-- | sql/sql_lex.cc | 33 | ||||
-rw-r--r-- | sql/sql_lex.h | 15 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 61 |
5 files changed, 118 insertions, 36 deletions
diff --git a/mysql-test/main/sp-security.result b/mysql-test/main/sp-security.result index 7d2098f62be..2c48883a509 100644 --- a/mysql-test/main/sp-security.result +++ b/mysql-test/main/sp-security.result @@ -802,3 +802,21 @@ connection default; DROP DATABASE u1; DROP USER u1@localhost; 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 +# diff --git a/mysql-test/main/sp-security.test b/mysql-test/main/sp-security.test index c375815b29a..e7790bf703a 100644 --- a/mysql-test/main/sp-security.test +++ b/mysql-test/main/sp-security.test @@ -1078,3 +1078,30 @@ DROP DATABASE u1; DROP USER u1@localhost; 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 # diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 477401c793f..671948f8e8d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -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, 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); +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0a802b9652c..49edce508ca 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3864,6 +3864,21 @@ public: const Column_definition &ref, Row_definition_list *fields, 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_finalize(THD *thd, int type); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6fe7d871f40..da752c0a3cb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1543,6 +1543,7 @@ End SQL_MODE_ORACLE_SPECIFIC */ admin_option_for_role user_maybe_role %type <user_auth> opt_auth_str auth_expression auth_token + text_or_password %type <charset> opt_collate @@ -16433,25 +16434,30 @@ option_value_no_option_type: unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) MYSQL_YYABORT; } - | PASSWORD_SYM opt_for_user text_or_password + | PASSWORD_SYM equal { if (sp_create_assignment_lex(thd, $1.pos())) MYSQL_YYABORT; - LEX *lex = Lex; - set_var_password *var= (new (thd->mem_root) - set_var_password(lex->definer)); - if (unlikely(var == NULL) || - unlikely(lex->var_list.push_back(var, thd->mem_root))) + } + text_or_password + { + if (unlikely(Lex->sp_create_set_password_instr(thd, $4, + yychar == YYEMPTY))) MYSQL_YYABORT; - lex->autocommit= TRUE; - if (lex->sphead) - lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; - if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY))) + } + | PASSWORD_SYM FOR_SYM + { + 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; } ; - transaction_characteristics: transaction_access_mode | isolation_level @@ -16508,42 +16514,25 @@ isolation_types: | 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_STRING { - Lex->definer->auth= new (thd->mem_root) USER_AUTH(); - Lex->definer->auth->auth_str= $1; + $$= new (thd->mem_root) USER_AUTH(); + $$->auth_str= $1; } | PASSWORD_SYM '(' TEXT_STRING ')' { - Lex->definer->auth= new (thd->mem_root) USER_AUTH(); - Lex->definer->auth->pwtext= $3; + $$= new (thd->mem_root) USER_AUTH(); + $$->pwtext= $3; } | OLD_PASSWORD_SYM '(' TEXT_STRING ')' { - Lex->definer->auth= new (thd->mem_root) USER_AUTH(); - Lex->definer->auth->pwtext= $3; - Lex->definer->auth->auth_str.str= Item_func_password::alloc(thd, + $$= new (thd->mem_root) USER_AUTH(); + $$->pwtext= $3; + $$->auth_str.str= Item_func_password::alloc(thd, $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; } ; |