mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 04:22:27 +01:00
Bug #27440 read_only allows create and drop database
When read_only option was enabled, a user without SUPER privilege could perform CREATE DATABASE and DROP DATABASE operations. This patch adds a check to make sure this isn't possible. It also attempts to simplify the logic used to determine if relevant tables are updated, making it more human readable. mysql-test/r/read_only.result: Updated result file mysql-test/t/read_only.test: A test case is added which shows that it is not possible to drop or create a database in read-only mode despite having the GRANT permissions to do so, SUPER user excepted. sql/sql_parse.cc: - Simplified complex predicate by grouping it in a read friendly way. - Added predicate to fail on database updates while running in read-only mode.
This commit is contained in:
parent
b8a19c228c
commit
5826a5c490
3 changed files with 134 additions and 8 deletions
|
@ -46,4 +46,35 @@ Warnings:
|
|||
Note 1051 Unknown table 'ttt'
|
||||
drop table t1,t2;
|
||||
drop user test@localhost;
|
||||
#
|
||||
# Bug #27440 read_only allows create and drop database
|
||||
#
|
||||
drop database if exists mysqltest_db1;
|
||||
drop database if exists mysqltest_db2;
|
||||
delete from mysql.user where User like 'mysqltest_%';
|
||||
delete from mysql.db where User like 'mysqltest_%';
|
||||
delete from mysql.tables_priv where User like 'mysqltest_%';
|
||||
delete from mysql.columns_priv where User like 'mysqltest_%';
|
||||
flush privileges;
|
||||
grant all on mysqltest_db2.* to `mysqltest_u1`@`%`;
|
||||
create database mysqltest_db1;
|
||||
grant all on mysqltest_db1.* to `mysqltest_u1`@`%`;
|
||||
flush privileges;
|
||||
show grants for current_user();
|
||||
Grants for mysqltest_u1@%
|
||||
GRANT USAGE ON *.* TO 'mysqltest_u1'@'%'
|
||||
GRANT ALL PRIVILEGES ON `mysqltest_db2`.* TO 'mysqltest_u1'@'%'
|
||||
GRANT ALL PRIVILEGES ON `mysqltest_db1`.* TO 'mysqltest_u1'@'%'
|
||||
create database mysqltest_db2;
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
show databases like '%mysqltest_db2%';
|
||||
Database (%mysqltest_db2%)
|
||||
drop database mysqltest_db1;
|
||||
ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
|
||||
delete from mysql.user where User like 'mysqltest_%';
|
||||
delete from mysql.db where User like 'mysqltest_%';
|
||||
delete from mysql.tables_priv where User like 'mysqltest_%';
|
||||
delete from mysql.columns_priv where User like 'mysqltest_%';
|
||||
flush privileges;
|
||||
drop database mysqltest_db1;
|
||||
set global read_only=0;
|
||||
|
|
|
@ -117,4 +117,38 @@ connection default;
|
|||
drop table t1,t2;
|
||||
drop user test@localhost;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #27440 read_only allows create and drop database
|
||||
--echo #
|
||||
--disable_warnings
|
||||
drop database if exists mysqltest_db1;
|
||||
drop database if exists mysqltest_db2;
|
||||
--enable_warnings
|
||||
|
||||
delete from mysql.user where User like 'mysqltest_%';
|
||||
delete from mysql.db where User like 'mysqltest_%';
|
||||
delete from mysql.tables_priv where User like 'mysqltest_%';
|
||||
delete from mysql.columns_priv where User like 'mysqltest_%';
|
||||
flush privileges;
|
||||
|
||||
grant all on mysqltest_db2.* to `mysqltest_u1`@`%`;
|
||||
create database mysqltest_db1;
|
||||
grant all on mysqltest_db1.* to `mysqltest_u1`@`%`;
|
||||
flush privileges;
|
||||
connect (con_bug27440,127.0.0.1,mysqltest_u1,,test,$MASTER_MYPORT,);
|
||||
connection con_bug27440;
|
||||
show grants for current_user();
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
create database mysqltest_db2;
|
||||
show databases like '%mysqltest_db2%';
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
drop database mysqltest_db1;
|
||||
disconnect con_bug27440;
|
||||
connection default;
|
||||
delete from mysql.user where User like 'mysqltest_%';
|
||||
delete from mysql.db where User like 'mysqltest_%';
|
||||
delete from mysql.tables_priv where User like 'mysqltest_%';
|
||||
delete from mysql.columns_priv where User like 'mysqltest_%';
|
||||
flush privileges;
|
||||
drop database mysqltest_db1;
|
||||
set global read_only=0;
|
||||
|
|
|
@ -1597,6 +1597,74 @@ static bool do_command(THD *thd)
|
|||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
||||
|
||||
/**
|
||||
@brief Determine if an attempt to update a non-temporary table while the
|
||||
read-only option was enabled has been made.
|
||||
|
||||
This is a helper function to mysql_execute_command.
|
||||
|
||||
@note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere.
|
||||
|
||||
@see mysql_execute_command
|
||||
@returns Status code
|
||||
@retval TRUE The statement should be denied.
|
||||
@retval FALSE The statement isn't updating any relevant tables.
|
||||
*/
|
||||
|
||||
static my_bool deny_updates_if_read_only_option(THD *thd,
|
||||
TABLE_LIST *all_tables)
|
||||
{
|
||||
DBUG_ENTER("deny_updates_if_read_only_option");
|
||||
|
||||
if (!opt_readonly)
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
LEX *lex= thd->lex;
|
||||
|
||||
const my_bool user_is_super=
|
||||
((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
|
||||
(ulong)SUPER_ACL);
|
||||
|
||||
if (user_is_super)
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
if (!uc_update_queries[lex->sql_command])
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
/* Multi update is an exception and is dealt with later. */
|
||||
if (lex->sql_command == SQLCOM_UPDATE_MULTI)
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
const my_bool create_temp_tables=
|
||||
(lex->sql_command == SQLCOM_CREATE_TABLE) &&
|
||||
(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);
|
||||
|
||||
const my_bool drop_temp_tables=
|
||||
(lex->sql_command == SQLCOM_DROP_TABLE) &&
|
||||
lex->drop_temporary;
|
||||
|
||||
const my_bool update_real_tables=
|
||||
some_non_temp_table_to_be_updated(thd, all_tables) &&
|
||||
!(create_temp_tables || drop_temp_tables);
|
||||
|
||||
|
||||
const my_bool create_or_drop_databases=
|
||||
(lex->sql_command == SQLCOM_CREATE_DB) ||
|
||||
(lex->sql_command == SQLCOM_DROP_DB);
|
||||
|
||||
if (update_real_tables || create_or_drop_databases)
|
||||
{
|
||||
/*
|
||||
An attempt was made to modify one or more non-temporary tables.
|
||||
*/
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* Assuming that only temporary tables are modified. */
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
Perform one connection-level (COM_XXXX) command.
|
||||
|
||||
|
@ -2590,14 +2658,7 @@ mysql_execute_command(THD *thd)
|
|||
When option readonly is set deny operations which change non-temporary
|
||||
tables. Except for the replication thread and the 'super' users.
|
||||
*/
|
||||
if (opt_readonly &&
|
||||
!(thd->security_ctx->master_access & SUPER_ACL) &&
|
||||
uc_update_queries[lex->sql_command] &&
|
||||
!((lex->sql_command == SQLCOM_CREATE_TABLE) &&
|
||||
(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
|
||||
!((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
|
||||
((lex->sql_command != SQLCOM_UPDATE_MULTI) &&
|
||||
some_non_temp_table_to_be_updated(thd, all_tables)))
|
||||
if (deny_updates_if_read_only_option(thd, all_tables))
|
||||
{
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
DBUG_RETURN(-1);
|
||||
|
|
Loading…
Reference in a new issue