summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2020-05-30 13:50:37 +0400
committerAlexander Barkov <bar@mariadb.com>2020-05-30 14:00:56 +0400
commit0bf843cd13981b03920bfc49c646b28a130f5d47 (patch)
treeb66a252f27ac6e4d1fbe3430ad09fc478ec20592
parentccdfcedf10610a32ce7d173e2936c29cb10df75c (diff)
downloadmariadb-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.result18
-rw-r--r--mysql-test/main/sp-security.test27
-rw-r--r--sql/sql_lex.cc33
-rw-r--r--sql/sql_lex.h15
-rw-r--r--sql/sql_yacc.yy61
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;
}
;