← Back to team overview

maria-developers team mailing list archive

Re: ec1a860bd09: MDEV-21743 Split up SUPER privilege to smaller privileges

 

Hi, Alexander!

Thanks!
Looks very straightforward.

See few comments below.

The main one - I am not sure I like the idea of creating numerous
aliases for privileges. This approach looks rather confusing to me.

On Feb 26, Alexander Barkov wrote:
> revision-id: ec1a860bd09 (mariadb-10.5.0-231-gec1a860bd09)
> parent(s): b8b5a6a2f9d
> author: Alexander Barkov <bar@xxxxxxxxxxx>
> committer: Alexander Barkov <bar@xxxxxxxxxxx>
> timestamp: 2020-02-23 22:09:55 +0400
> message:
> 
> MDEV-21743 Split up SUPER privilege to smaller privileges

> diff --git a/mysql-test/main/alter_user.test b/mysql-test/main/alter_user.test
> index 9ea98615272..60a36499a55 100644
> --- a/mysql-test/main/alter_user.test
> +++ b/mysql-test/main/alter_user.test
> @@ -30,7 +30,7 @@ alter user foo;
>  
>  --echo # Grant super privilege to the user.
>  connection default;
> -grant super on *.* to foo;
> +grant READ_ONLY ADMIN on *.* to foo;

--echo comments are now wrong

>  --echo # We now have super privilege. We should be able to run alter user.
>  connect (b, localhost, foo);
> diff --git a/mysql-test/main/grant.result b/mysql-test/main/grant.result
> index e83083be4ed..1452ada11f5 100644
> --- a/mysql-test/main/grant.result
> +++ b/mysql-test/main/grant.result
> @@ -631,6 +634,10 @@ Super      Server Admin    To use KILL thread, SET GLOBAL, CHANGE MASTER, etc.
>  Trigger        Tables  To use triggers
>  Create tablespace      Server Admin    To create/alter/drop tablespaces
>  Update Tables  To update existing rows
> +Set user       Server  To create views and stored routines with a different definer
> +Federated admin        Server  To execute the CREATE SERVER, ALTER SERVER, DROP SERVER statements
> +Connection admin       Server  To skip connection related limits tests

^^^ allows KILL too

> +Read_only admin        Server  To perform write operations even if @@read_only=ON
>  Usage  Server Admin    No privileges - allow connect only
>  connect  root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK;
>  connection root;
> diff --git a/sql/lock.cc b/sql/lock.cc
> index 6f86c0a38f6..9a4024606f8 100644
> --- a/sql/lock.cc
> +++ b/sql/lock.cc
> @@ -114,7 +113,7 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
>    DBUG_ENTER("lock_tables_check");
>  
>    system_count= 0;
> -  is_superuser= (thd->security_ctx->master_access & SUPER_ACL) != NO_ACL;
> +  is_superuser= (thd->security_ctx->master_access & IGNORE_READ_ONLY_ACL) != NO_ACL;

may be then s/is_superuser/ignores_read_only/ ?

>    log_table_write_query= (is_log_table_write_query(thd->lex->sql_command)
>                           || ((flags & MYSQL_LOCK_LOG_TABLE) != 0));
>  
> diff --git a/sql/privilege.h b/sql/privilege.h
> index 5dbc0b6dbdf..f80e726d8d0 100644
> --- a/sql/privilege.h
> +++ b/sql/privilege.h
> @@ -59,24 +59,60 @@ enum privilege_t: unsigned long long
>    TRIGGER_ACL           = (1UL << 27),
>    CREATE_TABLESPACE_ACL = (1UL << 28),
>    DELETE_HISTORY_ACL    = (1UL << 29),  // Added in 10.3.4
> +  SET_USER_ACL          = (1UL << 30),  // Added in 10.5.2
> +  FEDERATED_ADMIN_ACL   = (1UL << 31),  // Added in 10.5.2
> +  CONNECTION_ADMIN_ACL  = (1ULL << 32), // Added in 10.5.2
> +  READ_ONLY_ADMIN_ACL   = (1ULL << 33), // Added in 10.5.2
> +  REPL_SLAVE_ADMIN_ACL  = (1ULL << 34), // Added in 10.5.2
> +  REPL_MASTER_ADMIN_ACL = (1ULL << 35), // Added in 10.5.2
> +  BINLOG_ADMIN_ACL      = (1ULL << 36)  // Added in 10.5.2
>    /*
> -    don't forget to update
> -    1. static struct show_privileges_st sys_privileges[]
> -    2. static const char *command_array[] and static uint command_lengths[]
> -    3. mysql_system_tables.sql and mysql_system_tables_fix.sql
> -    4. acl_init() or whatever - to define behaviour for old privilege tables
> -    5. sql_yacc.yy - for GRANT/REVOKE to work
> -    6. Add a new ALL_KNOWN_ACL_VERSION
> -    7. Change ALL_KNOWN_ACL to ALL_KNOWN_ACL_VERSION
> -    8. Update User_table_json::get_access()
> +    don't forget to update:
> +    In this file:
> +    - Add a new LAST_version_ACL
> +    - Fix PRIVILEGE_T_MAX_BIT
> +    - Add a new ALL_KNOWN_ACL_version
> +    - Change ALL_KNOWN_ACL to ALL_KNOWN_ACL_version
> +    - Change GLOBAL_ACLS if needed
> +    - Change SUPER_ADDED_SINCE_USER_TABLE_ACL if needed
> +
> +    In other files:
> +    - static struct show_privileges_st sys_privileges[]
> +    - static const char *command_array[] and static uint command_lengths[]
> +    - mysql_system_tables.sql and mysql_system_tables_fix.sql
> +    - acl_init() or whatever - to define behaviour for old privilege tables
> +    - Update User_table_json::get_access()
> +    - sql_yacc.yy - for GRANT/REVOKE to work
> +
> +    Important: the enum should contain only single-bit values.
> +    In this case, debuggers print bit combinations in the readable form:
> +     (gdb) p (privilege_t) (15)
> +     $8 = (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL)
> +
> +    Bit-OR combinations of the above values should be declared outside!
>    */
> -
> -  // A combination of all bits defined in 10.3.4 (and earlier)
> -  ALL_KNOWN_ACL_100304 = (1UL << 30) - 1
>  };
>  
>  
> -constexpr privilege_t ALL_KNOWN_ACL= ALL_KNOWN_ACL_100304;
> +// Version markers
> +constexpr privilege_t LAST_100304_ACL= DELETE_HISTORY_ACL;
> +constexpr privilege_t LAST_100502_ACL= BINLOG_ADMIN_ACL;
> +constexpr privilege_t LAST_CURRENT_ACL= LAST_100502_ACL;
> +constexpr uint PRIVILEGE_T_MAX_BIT= 36;
> +
> +static_assert((privilege_t)(1ULL << PRIVILEGE_T_MAX_BIT) == LAST_CURRENT_ACL,
> +              "LAST_CURRENT_ACL and PRIVILEGE_T_MAX_BIT do not match");

why wouldn't you define PRIVILEGE_T_MAX_BIT via LAST_CURRENT_ACL instead?

> +
> +// A combination of all bits defined in 10.3.4 (and earlier)
> +constexpr privilege_t ALL_KNOWN_ACL_100304 =
> +  (privilege_t) ((LAST_100304_ACL << 1) - 1);
> +
> +// A combination of all bits defined in 10.5.2
> +constexpr privilege_t ALL_KNOWN_ACL_100502=
> +  (privilege_t) ((LAST_100502_ACL << 1) - 1);
> +
> +// A combination of all bits defined as of the current version
> +constexpr privilege_t ALL_KNOWN_ACL= ALL_KNOWN_ACL_100502;
>  
>  
>  // Unary operators
> @@ -229,6 +280,104 @@ constexpr privilege_t SHOW_CREATE_TABLE_ACLS=
>  constexpr privilege_t TMP_TABLE_ACLS=
>    COL_DML_ACLS | ALL_TABLE_DDL_ACLS;
>  
> +
> +
> +/*
> +  If a VIEW has a `definer=invoker@host` clause and
> +  the specified definer does not exists, then
> +  - The invoker with REVEAL_MISSING_DEFINER_ACL gets:
> +    ERROR: The user specified as a definer ('definer1'@'localhost') doesn't exist
> +  - The invoker without MISSING_DEFINER_ACL gets a generic access error,
> +    without revealing details that the definer does not exists.
> +
> +  TODO: we should eventually test the same privilege when processing
> +  other objects that have the DEFINER clause (e.g. routines, triggers).
> +  Currently the missing definer is revealed for non-privileged invokers
> +  in case of routines, triggers, etc.
> +*/
> +constexpr privilege_t REVEAL_MISSING_DEFINER_ACL= SUPER_ACL;

1.
why did you create these aliases? I don't think they make the
code simpler, on the contrary, now one can never know whether
say, IGNORE_READ_ONLY_ACL is a real privilege like in

   GRANT IGNORE READ_ONLY ON *.* TO user@host

or it's just an alias.

2. REVEAL_MISSING_DEFINER_ACL should be SET_USER_ACL, I think

> +constexpr privilege_t DES_DECRYPT_ONE_ARG_ACL= SUPER_ACL;
> +constexpr privilege_t LOG_BIN_TRUSTED_SP_CREATOR_ACL= SUPER_ACL;

this could be SET_USER_ACL too

> +constexpr privilege_t DEBUG_ACL= SUPER_ACL;
> +constexpr privilege_t SET_GLOBAL_SYSTEM_VARIABLE_ACL= SUPER_ACL;
> +constexpr privilege_t SET_RESTRICTED_SESSION_SYSTEM_VARIABLE_ACL= SUPER_ACL;
> +
> +/* Privileges related to --read-only */
> +constexpr privilege_t IGNORE_READ_ONLY_ACL= READ_ONLY_ADMIN_ACL;
> +
> +/* Privileges related to connection handling */
> +constexpr privilege_t IGNORE_INIT_CONNECT_ACL= CONNECTION_ADMIN_ACL;
> +constexpr privilege_t IGNORE_MAX_USER_CONNECTIONS_ACL= CONNECTION_ADMIN_ACL;
> +constexpr privilege_t IGNORE_MAX_CONNECTIONS_ACL= CONNECTION_ADMIN_ACL;
> +constexpr privilege_t IGNORE_MAX_PASSWORD_ERRORS_ACL= CONNECTION_ADMIN_ACL;
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t KILL_OTHER_USER_PROCESS_ACL= CONNECTION_ADMIN_ACL;
> +
> +
> +/*
> +  Binary log related privileges that are checked regardless
> +  of active replication running.
> +*/
> +
> +/*
> +  This command was renamed from "SHOW MASTER STATUS"
> +  to "SHOW BINLOG STATUS" in 10.5.2.
> +  Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2
> +*/
> +constexpr privilege_t STMT_SHOW_BINLOG_STATUS_ACL= REPL_CLIENT_ACL;
> +
> +// Was SUPER_ACL | REPL_CLIENT_ACL prior to 10.5.2
> +constexpr privilege_t STMT_SHOW_BINARY_LOGS_ACL= REPL_CLIENT_ACL;
> +
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_PURGE_BINLOG_ACL= BINLOG_ADMIN_ACL;
> +
> +// Was REPL_SLAVE_ACL prior to 10.5.2
> +constexpr privilege_t STMT_SHOW_BINLOG_EVENTS_ACL= PROCESS_ACL;
> +
> +
> +/*
> +  Privileges for replication related statements
> +  that are executed on the master.
> +*/
> +constexpr privilege_t COM_REGISTER_SLAVE_ACL= REPL_SLAVE_ACL;
> +constexpr privilege_t COM_BINLOG_DUMP_ACL= REPL_SLAVE_ACL;
> +// Was REPL_SLAVE_ACL prior to 10.5.2
> +constexpr privilege_t STMT_SHOW_SLAVE_HOSTS_ACL= REPL_MASTER_ADMIN_ACL;
> +
> +
> +/* Privileges for statements that are executed on the slave */
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_START_SLAVE_ACL= REPL_SLAVE_ADMIN_ACL;
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_STOP_SLAVE_ACL= REPL_SLAVE_ADMIN_ACL;
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_CHANGE_MASTER_ACL= REPL_SLAVE_ADMIN_ACL;
> +// Was (SUPER_ACL | REPL_CLIENT_ACL) prior to 10.5.2
> +constexpr privilege_t STMT_SHOW_SLAVE_STATUS_ACL= REPL_SLAVE_ADMIN_ACL;
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_BINLOG_ACL= REPL_SLAVE_ADMIN_ACL;
> +// Was REPL_SLAVE_ACL prior to 10.5.2
> +constexpr privilege_t STMT_SHOW_RELAYLOG_EVENTS_ACL= REPL_SLAVE_ADMIN_ACL;
> +
> +
> +/* Privileges for federated database related statements */
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_CREATE_SERVER_ACL= FEDERATED_ADMIN_ACL;
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_ALTER_SERVER_ACL= FEDERATED_ADMIN_ACL;
> +// Was SUPER_ACL prior to 10.5.2
> +constexpr privilege_t STMT_DROP_SERVER_ACL= FEDERATED_ADMIN_ACL;
> +
> +
> +/* Privileges related to processes */
> +constexpr privilege_t COM_PROCESS_INFO_ACL= PROCESS_ACL;
> +constexpr privilege_t STMT_SHOW_EXPLAIN_ACL= PROCESS_ACL;
> +constexpr privilege_t STMT_SHOW_ENGINE_STATUS_ACL= PROCESS_ACL;
> +constexpr privilege_t STMT_SHOW_ENGINE_MUTEX_ACL= PROCESS_ACL;
> +constexpr privilege_t STMT_SHOW_PROCESSLIST_ACL= PROCESS_ACL;
> +
> +
>  /*
>    Defines to change the above bits to how things are stored in tables
>    This is needed as the 'host' and 'db' table is missing a few privileges
> diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
> index e2a3c482ae4..b096bfa7a95 100644
> --- a/sql/sql_connect.cc
> +++ b/sql/sql_connect.cc
> @@ -1246,7 +1245,8 @@ void prepare_new_connection_state(THD* thd)
>    thd->set_command(COM_SLEEP);
>    thd->init_for_queries();
>  
> -  if (opt_init_connect.length && !(sctx->master_access & SUPER_ACL))
> +  if (opt_init_connect.length &&
> +      (sctx->master_access & IGNORE_INIT_CONNECT_ACL) == NO_ACL)

dunno, I kind of like !(access & SOME_ACL)
why not to keep privilege_t -> bool?

>    {
>      execute_init_command(thd, &opt_init_connect, &LOCK_sys_init_connect);
>      if (unlikely(thd->is_error()))
> diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
> index dac5b025821..7f3a436a4c2 100644
> --- a/sql/sql_parse.cc
> +++ b/sql/sql_parse.cc
> @@ -7138,8 +7138,7 @@ bool check_some_access(THD *thd, privilege_t want_access, TABLE_LIST *table)
>    @warning
>      One gets access right if one has ANY of the rights in want_access.
>      This is useful as one in most cases only need one global right,
> -    but in some case we want to check if the user has SUPER or
> -    REPL_CLIENT_ACL rights.
> +    but in some case we want to check multiple rights.

In what cases? Are there any left?

>  
>    @retval
>      0  ok

Regards,
Sergei
VP of MariaDB Server Engineering
and security@xxxxxxxxxxx