← Back to team overview

maria-developers team mailing list archive

Re: d08860b28f3: MDEV-22374: VIEW with security definer require FILE privilege from definer not invoker in case of INTO OUTFILE

 

Hi, Oleksandr!

On May 04, Oleksandr Byelkin wrote:
> revision-id: d08860b28f3 (mariadb-5.5.67-15-gd08860b28f3)
> parent(s): ac2604f923f
> author: Oleksandr Byelkin <sanja@xxxxxxxxxxx>
> committer: Oleksandr Byelkin <sanja@xxxxxxxxxxx>
> timestamp: 2020-04-28 09:16:33 +0200
> message:
> 
> MDEV-22374: VIEW with security definer require FILE privilege from definer not invoker in case of INTO OUTFILE
> 
> Check INTO OUTFILE clause always from invoker.
> 
> ---
>  mysql-test/r/view_grant.result | 21 +++++++++++++++++++++
>  mysql-test/t/view_grant.test   | 33 +++++++++++++++++++++++++++++++++
>  sql/sql_parse.cc               | 18 +++++++++---------
>  3 files changed, 63 insertions(+), 9 deletions(-)
> 
> diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
> index b2d3a0b8ca4..37dc6adc978 100644
> --- a/mysql-test/r/view_grant.result
> +++ b/mysql-test/r/view_grant.result
> @@ -1587,3 +1587,24 @@ USE test;
>  DROP DATABASE mysqltest1;
>  DROP USER 'mysqluser1'@'%';
>  DROP USER 'mysqluser2'@'%';
> +#
> +# MDEV-22374: VIEW with security definer require FILE privilege from definer
> +# not invoker in case of INTO OUTFILE
> +#
> +create user test@localhost;
> +grant select on test.* to test@localhost;
> +create table t1 (a int);
> +create definer=test@localhost sql security definer view v1 as select * from t1;
> +# check that ot works without view

typo "it"

> +select * INTO OUTFILE '../..//tmp/test_out_txt' from t1;
> +# check that ot works without file

same
why "//" ?

> +select * from v1;
> +a
> +# rights for file should be taken from current user not view
> +select * INTO OUTFILE '../../tmp/test_out_txt' from (select count(*) from v1) as dv1;
> +select * INTO OUTFILE '../..//tmp/test_out_txt' from (select * from v1) as dv1;
> +select * INTO OUTFILE '../..//tmp/test_out_txt' from v1;

same

> +drop view v1;

please add reverse tests too:

+create sql security definer view v1 as select * from t1;
+connect(con1, localhost, test);
+error 1045;
+select * INTO OUTFILE '../..//tmp/test_out_txt' from t1;
+select * from v1;
+error 1045;
+select * INTO OUTFILE '../../tmp/test_out_txt' from (select count(*) from v1) as dv1;
+error 1045;
+select * INTO OUTFILE '../..//tmp/test_out_txt' from (select * from v1) as dv1;
+error 1045;
+select * INTO OUTFILE '../..//tmp/test_out_txt' from v1;
+connection default;

> +drop table t1;
> +drop user test@localhost;
> +# End of 5.5 tests
> diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
> index ae5a6b4cd35..515990c879f 100644
> --- a/sql/sql_parse.cc
> +++ b/sql/sql_parse.cc
> @@ -2206,15 +2206,15 @@ mysql_execute_command(THD *thd)
>        lex->exchange != NULL implies SELECT .. INTO OUTFILE and this
>        requires FILE_ACL access.
>      */
> -    ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL :
> -      SELECT_ACL;
> -
> -    if (all_tables)
> -      res= check_table_access(thd,
> -                              privileges_requested,
> -                              all_tables, FALSE, UINT_MAX, FALSE);
> -    else
> -      res= check_access(thd, privileges_requested, any_db, NULL, NULL, 0, 0);
> +    if (lex->exchange)
> +      res= check_access(thd, FILE_ACL, any_db, NULL, NULL, 0, 0);
> +    if (!res)
> +    {
> +      if (all_tables)
> +        res= check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE);
> +      else
> +        res= check_access(thd, SELECT_ACL, any_db, NULL, NULL, 0, 0);
> +    }

No, I think this special check for a special SELECT ... INTO OUTFILE
case is wrong. Why does the server even checks global privileges via
views? It should not do it, I think, not for FILE not for any other
global or db level privilege. I'd try something like

diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -4699,7 +4699,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST >
       Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
       It will be checked during making view.
     */
-    tl->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+    tl->grant.orig_want_privilege= want_access & ~SHOW_VIEW_ACL & TABLE_ACLS;
   }
 
   mysql_rwlock_rdlock(&LOCK_grant);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5204,7 +5204,8 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIS>
        Register access for view underlying table.
        Remove SHOW_VIEW_ACL, because it will be checked during making view
      */
-    table_ref->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+    table_ref->grant.orig_want_privilege=
+      want_access & ~SHOW_VIEW_ACL & TABLE_ACLS;
 
     if (table_ref->schema_table_reformed)
     {

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