Bug#7391 - Multi-table UPDATE security regression

  Add in missing privilege checks. 
  Tests for the privileges.
parent d54d79fa
...@@ -156,3 +156,67 @@ select host,db,user,select_priv,insert_priv from mysql.db where db="db6123"; ...@@ -156,3 +156,67 @@ select host,db,user,select_priv,insert_priv from mysql.db where db="db6123";
host db user select_priv insert_priv host db user select_priv insert_priv
delete from mysql.user where user='test6123'; delete from mysql.user where user='test6123';
drop database db6123; drop database db6123;
create database mysqltest_1;
create database mysqltest_2;
create table mysqltest_1.t1 select 1 a, 2 q;
create table mysqltest_1.t2 select 1 b, 2 r;
create table mysqltest_2.t1 select 1 c, 2 s;
create table mysqltest_2.t2 select 1 d, 2 t;
grant update (a) on mysqltest_1.t1 to mysqltest_3@localhost;
grant select (b) on mysqltest_1.t2 to mysqltest_3@localhost;
grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost;
grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost;
show grants for mysqltest_3@localhost;
Grants for mysqltest_3@localhost
GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost'
GRANT SELECT (b) ON `mysqltest_1`.`t2` TO 'mysqltest_3'@'localhost'
GRANT SELECT (c) ON `mysqltest_2`.`t1` TO 'mysqltest_3'@'localhost'
GRANT UPDATE (a) ON `mysqltest_1`.`t1` TO 'mysqltest_3'@'localhost'
GRANT UPDATE (d) ON `mysqltest_2`.`t2` TO 'mysqltest_3'@'localhost'
update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1;
UPDATE command denied to user: 'mysqltest_3@localhost' for column 'q' in table 't1'
update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1;
select command denied to user: 'mysqltest_3@localhost' for table 't1'
update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1;
UPDATE command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1'
update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2;
SELECT command denied to user: 'mysqltest_3@localhost' for column 's' in table 't1'
update mysqltest_1.t1, mysqltest_2.t2 set a=10,d=10;
update mysqltest_1.t1, mysqltest_2.t1 set a=20 where c=20;
select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2;
a q b r
10 2 1 2
select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2;
c s d t
1 2 10 2
revoke all on mysqltest_1.t1 from mysqltest_3@localhost;
revoke all on mysqltest_1.t2 from mysqltest_3@localhost;
revoke all on mysqltest_2.t1 from mysqltest_3@localhost;
revoke all on mysqltest_2.t2 from mysqltest_3@localhost;
grant all on mysqltest_2.* to mysqltest_3@localhost;
grant select on *.* to mysqltest_3@localhost;
flush privileges;
use mysqltest_1;
update mysqltest_2.t1, mysqltest_2.t2 set c=500,d=600;
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
UPDATE command denied to user: 'mysqltest_3@localhost' for column 'a' in table 't1'
use mysqltest_2;
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
Access denied for user: 'mysqltest_3@localhost' to database 'mysqltest_1'
update mysqltest_2.t1, mysqltest_1.t2 set c=100,b=200;
Access denied for user: 'mysqltest_3@localhost' to database 'mysqltest_1'
update mysqltest_1.t1, mysqltest_2.t2 set a=100,d=200;
Access denied for user: 'mysqltest_3@localhost' to database 'mysqltest_1'
select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2;
a q b r
10 2 1 2
select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2;
c s d t
500 2 600 2
delete from mysql.user where user='mysqltest_3';
delete from mysql.db where user="mysqltest_3";
delete from mysql.tables_priv where user="mysqltest_3";
delete from mysql.columns_priv where user="mysqltest_3";
flush privileges;
drop database mysqltest_1;
drop database mysqltest_2;
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
drop table if exists t1; drop table if exists t1;
--enable_warnings --enable_warnings
connect (master,localhost,root,,);
connection master;
# #
# Test that SSL options works properly # Test that SSL options works properly
# #
...@@ -114,3 +116,73 @@ grant usage on db6123.* to test6123 identified by 'magic123'; ...@@ -114,3 +116,73 @@ grant usage on db6123.* to test6123 identified by 'magic123';
select host,db,user,select_priv,insert_priv from mysql.db where db="db6123"; select host,db,user,select_priv,insert_priv from mysql.db where db="db6123";
delete from mysql.user where user='test6123'; delete from mysql.user where user='test6123';
drop database db6123; drop database db6123;
#
# Bug#7391: Cross-database multi-table UPDATE security problem
#
create database mysqltest_1;
create database mysqltest_2;
create table mysqltest_1.t1 select 1 a, 2 q;
create table mysqltest_1.t2 select 1 b, 2 r;
create table mysqltest_2.t1 select 1 c, 2 s;
create table mysqltest_2.t2 select 1 d, 2 t;
#test the column privileges
grant update (a) on mysqltest_1.t1 to mysqltest_3@localhost;
grant select (b) on mysqltest_1.t2 to mysqltest_3@localhost;
grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost;
grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost;
connect (conn1,localhost,mysqltest_3,,);
connection conn1;
show grants for mysqltest_3@localhost;
--error 1143
update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1;
--error 1142
update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1;
--error 1143
update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1;
--error 1143
update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2;
#the following two should work
update mysqltest_1.t1, mysqltest_2.t2 set a=10,d=10;
update mysqltest_1.t1, mysqltest_2.t1 set a=20 where c=20;
connection master;
select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2;
select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2;
revoke all on mysqltest_1.t1 from mysqltest_3@localhost;
revoke all on mysqltest_1.t2 from mysqltest_3@localhost;
revoke all on mysqltest_2.t1 from mysqltest_3@localhost;
revoke all on mysqltest_2.t2 from mysqltest_3@localhost;
#test the db/table level privileges
grant all on mysqltest_2.* to mysqltest_3@localhost;
grant select on *.* to mysqltest_3@localhost;
flush privileges;
disconnect conn1;
connect (conn2,localhost,mysqltest_3,,);
connection conn2;
use mysqltest_1;
update mysqltest_2.t1, mysqltest_2.t2 set c=500,d=600;
# the following failed before, should fail now.
--error 1143
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
use mysqltest_2;
#the following used to succeed, it must fail now.
--error 1044
update mysqltest_1.t1, mysqltest_1.t2 set a=100,b=200;
--error 1044
update mysqltest_2.t1, mysqltest_1.t2 set c=100,b=200;
--error 1044
update mysqltest_1.t1, mysqltest_2.t2 set a=100,d=200;
#lets see the result
connection master;
select t1.*,t2.* from mysqltest_1.t1,mysqltest_1.t2;
select t1.*,t2.* from mysqltest_2.t1,mysqltest_2.t2;
delete from mysql.user where user='mysqltest_3';
delete from mysql.db where user="mysqltest_3";
delete from mysql.tables_priv where user="mysqltest_3";
delete from mysql.columns_priv where user="mysqltest_3";
flush privileges;
drop database mysqltest_1;
drop database mysqltest_2;
...@@ -465,21 +465,34 @@ int mysql_multi_update(THD *thd, ...@@ -465,21 +465,34 @@ int mysql_multi_update(THD *thd,
*/ */
for (tl= table_list ; tl ; tl=tl->next) for (tl= table_list ; tl ; tl=tl->next)
{ {
TABLE_LIST *save= tl->next;
TABLE *table= tl->table; TABLE *table= tl->table;
uint wants;
tl->next= 0;
if (update_map & table->map) if (update_map & table->map)
{ {
DBUG_PRINT("info",("setting table `%s` for update", tl->alias)); DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
tl->lock_type= thd->lex.lock_option; tl->lock_type= thd->lex.lock_option;
tl->updating= 1; tl->updating= 1;
wants= UPDATE_ACL;
} }
else else
{ {
DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias)); DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
tl->lock_type= TL_READ; tl->lock_type= TL_READ;
tl->updating= 0; tl->updating= 0;
wants= SELECT_ACL;
} }
if (!using_lock_tables) if (!using_lock_tables)
tl->table->reginfo.lock_type= tl->lock_type; tl->table->reginfo.lock_type= tl->lock_type;
if (check_access(thd, wants, tl->db, &tl->grant.privilege, 0, 0) ||
(grant_option && check_grant(thd, wants, tl, 0, 0)))
{
tl->next= save;
DBUG_RETURN(0);
}
tl->next= save;
} }
/* Relock the tables with the correct modes */ /* Relock the tables with the correct modes */
...@@ -541,6 +554,13 @@ int mysql_multi_update(THD *thd, ...@@ -541,6 +554,13 @@ int mysql_multi_update(THD *thd,
} }
} }
/*
If we have no WHERE clause, make it true otherwise the Select
examines the privileges
*/
if (!conds)
conds= new Item_int("1", 1LL, 1);
if (!(result=new multi_update(thd, table_list, fields, values, if (!(result=new multi_update(thd, table_list, fields, values,
handle_duplicates))) handle_duplicates)))
DBUG_RETURN(-1); DBUG_RETURN(-1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment