From ba80708f66fca32c7c2fbc66879177e5590e53fb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 27 Feb 2015 20:13:51 +0100 Subject: [PATCH] MDEV-6960 Server crashes in check_alter_user on setting a default role via PS There were two issues: * set_var_default_role::user was overwritten with a new value, allocated in the thd->mem_root, which is reset between executions. That was causing the crash. Solved by introducing set_var_default_role::real_user * when privilege tables were opened on EXECUTE, the reprepare_observer would abort the statement (as privilege tables are opened using the local TABLE_LIST that doesn't preserve metadata from PREPARE, so reprepare_observer thought they're changed). This issue also applied to SET PASSWORD. Solved by disabling reprepare_observer. --- .../suite/roles/set_default_role_ps-6960.result | 8 ++++++++ .../suite/roles/set_default_role_ps-6960.test | 15 +++++++++++++++ sql/set_var.cc | 16 ++++++++++++---- sql/set_var.h | 2 +- 4 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/roles/set_default_role_ps-6960.result create mode 100644 mysql-test/suite/roles/set_default_role_ps-6960.test diff --git a/mysql-test/suite/roles/set_default_role_ps-6960.result b/mysql-test/suite/roles/set_default_role_ps-6960.result new file mode 100644 index 00000000000..60210d7f92c --- /dev/null +++ b/mysql-test/suite/roles/set_default_role_ps-6960.result @@ -0,0 +1,8 @@ +create role r1; +prepare stmt from "set password = '11111111111111111111111111111111111111111'"; +execute stmt; +prepare stmt from "set default role r1"; +execute stmt; +set password = ''; +set default role NONE; +drop role r1; diff --git a/mysql-test/suite/roles/set_default_role_ps-6960.test b/mysql-test/suite/roles/set_default_role_ps-6960.test new file mode 100644 index 00000000000..8ac520e1776 --- /dev/null +++ b/mysql-test/suite/roles/set_default_role_ps-6960.test @@ -0,0 +1,15 @@ +# +# MDEV-6960 Server crashes in check_alter_user on setting a default role via PS +# + +--source include/not_embedded.inc + +create role r1; +prepare stmt from "set password = '11111111111111111111111111111111111111111'"; +execute stmt; +prepare stmt from "set default role r1"; +execute stmt; + +set password = ''; +set default role NONE; +drop role r1; diff --git a/sql/set_var.cc b/sql/set_var.cc index e994745db68..278a05213a6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -860,7 +860,11 @@ int set_var_password::check(THD *thd) int set_var_password::update(THD *thd) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - return change_password(thd, user); + Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; + thd->m_reprepare_observer= 0; + int res= change_password(thd, user); + thd->m_reprepare_observer= save_reprepare_observer; + return res; #else return 0; #endif @@ -896,8 +900,8 @@ int set_var_role::update(THD *thd) int set_var_default_role::check(THD *thd) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - user= get_current_user(thd, user); - int status= acl_check_set_default_role(thd, user->host.str, user->user.str); + real_user= get_current_user(thd, user); + int status= acl_check_set_default_role(thd, real_user->host.str, real_user->user.str); return status; #else return 0; @@ -907,7 +911,11 @@ int set_var_default_role::check(THD *thd) int set_var_default_role::update(THD *thd) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - return acl_set_default_role(thd, user->host.str, user->user.str, role.str); + Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; + thd->m_reprepare_observer= 0; + int res= acl_set_default_role(thd, real_user->host.str, real_user->user.str, role.str); + thd->m_reprepare_observer= save_reprepare_observer; + return res; #else return 0; #endif diff --git a/sql/set_var.h b/sql/set_var.h index 66d1bc4e983..15c89f1e2b4 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -344,7 +344,7 @@ public: class set_var_default_role: public set_var_base { - LEX_USER *user; + LEX_USER *user, *real_user; LEX_STRING role; public: set_var_default_role(LEX_USER *user_arg, LEX_STRING role_arg) :