summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <cvicentiu@gmail.com>2022-09-05 13:15:16 +0300
committerVicențiu-Marian Ciorbaru <vicentiu@mariadb.org>2022-09-14 14:40:50 +0300
commit145932a57b3ffba4ebab25aa5b3910673ddcfbf0 (patch)
treed347dfb2e0afb12d6ba0e54e8c4830663b87256b
parentd7aefc0fab6231e3646c3c8735c8670db9c3623e (diff)
downloadmariadb-git-145932a57b3ffba4ebab25aa5b3910673ddcfbf0.tar.gz
MDEV-29465: Inherited columns privs for roles wrongly set mysql.tables_priv column
There was a bug in the ACL internal data structures GRANT_TABLE and GRANT_COLUMN. The semantics are: GRANT_TABLE::init_cols and GRANT_COLUMN::init_privs represent the bits that correspond to the privilege bits stored in the physical tables. The other struct members GRANT_TABLE::cols and GRANT_COLUMN::privs represent the actual access bits, as they may be modified through role grants. The error in logic was mixing the two fields and thus we ended up storing the logical access bits in the physical tables, instead of the physical (init_xxx) bits. This caused subsequent DBUG_ASSERT failures when dropping the involved roles.
-rw-r--r--mysql-test/suite/roles/roles_tables_priv-29465.result36
-rw-r--r--mysql-test/suite/roles/roles_tables_priv-29465.test40
-rw-r--r--sql/sql_acl.cc23
3 files changed, 90 insertions, 9 deletions
diff --git a/mysql-test/suite/roles/roles_tables_priv-29465.result b/mysql-test/suite/roles/roles_tables_priv-29465.result
new file mode 100644
index 00000000000..de5f79d98f5
--- /dev/null
+++ b/mysql-test/suite/roles/roles_tables_priv-29465.result
@@ -0,0 +1,36 @@
+create user foo;
+create database some_db;
+create table some_db.t1 (a int, b int, secret int);
+create role r_select_column;
+create role r_active_column;
+grant r_select_column to r_active_column;
+grant r_active_column to foo;
+grant select(a) on some_db.t1 to r_select_column;
+select * from mysql.tables_priv order by user;
+Host Db User Table_name Grantor Timestamp Table_priv Column_priv
+ some_db r_select_column t1 root@localhost 0000-00-00 00:00:00 Select
+grant insert(a) on some_db.t1 to r_active_column;
+select * from mysql.tables_priv order by user;
+Host Db User Table_name Grantor Timestamp Table_priv Column_priv
+ some_db r_active_column t1 root@localhost 0000-00-00 00:00:00 Insert
+ some_db r_select_column t1 root@localhost 0000-00-00 00:00:00 Select
+connect con1, localhost, foo,,;
+insert into some_db.t1(a) values (1);
+ERROR 42000: INSERT command denied to user 'foo'@'localhost' for table 't1'
+set role r_active_column;
+insert into some_db.t1(a) values (1);
+disconnect con1;
+connection default;
+revoke insert(a) on some_db.t1 from r_active_column;
+connect con1, localhost, foo,,;
+insert into some_db.t1(a) values (1);
+ERROR 42000: INSERT command denied to user 'foo'@'localhost' for table 't1'
+set role r_active_column;
+insert into some_db.t1(a) values (1);
+ERROR 42000: INSERT command denied to user 'foo'@'localhost' for table 't1'
+disconnect con1;
+connection default;
+drop role r_select_column;
+drop role r_active_column;
+drop user foo;
+drop database some_db;
diff --git a/mysql-test/suite/roles/roles_tables_priv-29465.test b/mysql-test/suite/roles/roles_tables_priv-29465.test
new file mode 100644
index 00000000000..550b05a408a
--- /dev/null
+++ b/mysql-test/suite/roles/roles_tables_priv-29465.test
@@ -0,0 +1,40 @@
+--source include/not_embedded.inc
+
+create user foo;
+create database some_db;
+create table some_db.t1 (a int, b int, secret int);
+
+create role r_select_column;
+create role r_active_column;
+grant r_select_column to r_active_column;
+grant r_active_column to foo;
+
+grant select(a) on some_db.t1 to r_select_column;
+select * from mysql.tables_priv order by user;
+grant insert(a) on some_db.t1 to r_active_column;
+select * from mysql.tables_priv order by user;
+
+--connect (con1, localhost, foo,,)
+--error ER_TABLEACCESS_DENIED_ERROR
+insert into some_db.t1(a) values (1);
+set role r_active_column;
+insert into some_db.t1(a) values (1);
+disconnect con1;
+
+connection default;
+revoke insert(a) on some_db.t1 from r_active_column;
+
+--connect (con1, localhost, foo,,)
+--error ER_TABLEACCESS_DENIED_ERROR
+insert into some_db.t1(a) values (1);
+set role r_active_column;
+--error ER_TABLEACCESS_DENIED_ERROR
+insert into some_db.t1(a) values (1);
+disconnect con1;
+
+connection default;
+
+drop role r_select_column;
+drop role r_active_column;
+drop user foo;
+drop database some_db;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index eae180837ae..ba457083b75 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -4813,7 +4813,7 @@ GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
const char *t, ulong p, ulong c)
- :GRANT_NAME(h,d,u,t,p, FALSE), cols(c)
+ :GRANT_NAME(h,d,u,t,p, FALSE), cols(c), init_cols(c)
{
init_hash();
}
@@ -6636,11 +6636,15 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* Fix old grants */
while ((column = column_iter++))
{
- grant_column = column_hash_search(grant_table,
- column->column.ptr(),
- column->column.length());
- if (grant_column)
- grant_column->rights&= ~(column->rights | rights);
+ grant_column = column_hash_search(grant_table,
+ column->column.ptr(),
+ column->column.length());
+ if (grant_column)
+ {
+ grant_column->init_rights&= ~(column->rights | rights);
+ // If this is a role, rights will need to be reconstructed.
+ grant_column->rights= grant_column->init_rights;
+ }
}
/* scan trough all columns to get new column grant */
column_priv= 0;
@@ -6648,13 +6652,14 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{
grant_column= (GRANT_COLUMN*)
my_hash_element(&grant_table->hash_columns, idx);
- grant_column->rights&= ~rights; // Fix other columns
- column_priv|= grant_column->rights;
+ grant_column->init_rights&= ~rights; // Fix other columns
+ grant_column->rights= grant_column->init_rights;
+ column_priv|= grant_column->init_rights;
}
}
else
{
- column_priv|= grant_table->cols;
+ column_priv|= grant_table->init_cols;
}