Thread

  1. BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    PG Bug reporting form <noreply@postgresql.org> — 2024-03-11T20:10:08Z

    The following bug has been logged on the website:
    
    Bug reference:      18387
    Logged by:          Maxim Boguk
    Email address:      maxim.boguk@gmail.com
    PostgreSQL version: 16.2
    Operating system:   Linux
    Description:        
    
    Hi,
    
    There are weird behavior with permission checks for refresh materialized
    view for superuser.
    Reproducer script (run from postgres):
    
    create role test_role;
    create database test with owner postgres;
    \c test
    create table test as select 1 val;
    create materialized view test_mv as select * from test;
    REFRESH MATERIALIZED VIEW test_mv;
    create unique index test_mv_pk on test_mv(val);
    REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    alter materialized view test_mv owner to test_role;
    REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    select * from test;
    revoke temporary on database test from public;
    \c test
    REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    REFRESH MATERIALIZED VIEW test_mv;
    
    Reproducer log (starting from interesting part):
    test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    REFRESH MATERIALIZED VIEW
    test=# alter materialized view test_mv owner to test_role;
    ALTER MATERIALIZED VIEW
    test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    ERROR:  permission denied for table test
    --what??? N1
    
    --check that im not hallucinating
    test=# select * from test;
     val 
    -----
       1
    (1 row)
    
    test=# revoke temporary on database test from public;
    REVOKE
    test=# \c test
    You are now connected to database "test" as user "postgres".
    test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    ERROR:  permission denied to create temporary tables in database "test"
    --what??? N2
    
    test=# REFRESH MATERIALIZED VIEW test_mv;
    ERROR:  permission denied for table test
    --without CONCURRENTLY wrong behavior too
    
    
  2. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Heikki Linnakangas <hlinnaka@iki.fi> — 2024-03-11T23:02:16Z

    On 11/03/2024 22:10, PG Bug reporting form wrote:
    > Reproducer log (starting from interesting part):
    > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > REFRESH MATERIALIZED VIEW
    > test=# alter materialized view test_mv owner to test_role;
    > ALTER MATERIALIZED VIEW
    > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > ERROR:  permission denied for table test
    > --what??? N1
    > 
    > --check that im not hallucinating
    > test=# select * from test;
    >   val
    > -----
    >     1
    > (1 row)
    
    So far, this is working correctly. REFRESH MATERIALIZED VIEW runs with 
    the permissions of the materialized view's owner. In this case, the 
    owner is 'test_role', which doesn't have select permission on the table.
    
    > test=# revoke temporary on database test from public;
    > REVOKE
    > test=# \c test
    > You are now connected to database "test" as user "postgres".
    > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > ERROR:  permission denied to create temporary tables in database "test"
    > --what??? N2
    
    That's interesting. REFRESH MATERIALIZED VIEW CONCURRENTLY uses 
    temporary tables internally, which fails if the user doesn't have 
    permissions to create temporary tables.
    
    I guess we need to allow creating such internal temporary tables, 
    despite the missing permission. That'll need some careful analysis to 
    make sure we don't accidentally allow creating other temporary tables...
    
    -- 
    Heikki Linnakangas
    Neon (https://neon.tech)
    
    
    
    
    
  3. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Bruce Momjian <bruce@momjian.us> — 2024-03-11T23:21:50Z

    On Tue, Mar 12, 2024 at 01:02:16AM +0200, Heikki Linnakangas wrote:
    > On 11/03/2024 22:10, PG Bug reporting form wrote:
    > > Reproducer log (starting from interesting part):
    > > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > > REFRESH MATERIALIZED VIEW
    > > test=# alter materialized view test_mv owner to test_role;
    > > ALTER MATERIALIZED VIEW
    > > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > > ERROR:  permission denied for table test
    > > --what??? N1
    > > 
    > > --check that im not hallucinating
    > > test=# select * from test;
    > >   val
    > > -----
    > >     1
    > > (1 row)
    > 
    > So far, this is working correctly. REFRESH MATERIALIZED VIEW runs with the
    > permissions of the materialized view's owner. In this case, the owner is
    > 'test_role', which doesn't have select permission on the table.
    
    Can we do a better job of suggesting the cause of the failure?
    
    -- 
      Bruce Momjian  <bruce@momjian.us>        https://momjian.us
      EDB                                      https://enterprisedb.com
    
      Only you can decide what is important to you.
    
    
    
    
  4. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Laurenz Albe <laurenz.albe@cybertec.at> — 2024-03-12T07:34:40Z

    On Tue, 2024-03-12 at 01:02 +0200, Heikki Linnakangas wrote:
    > test=# \c test
    > > You are now connected to database "test" as user "postgres".
    > > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > > ERROR:  permission denied to create temporary tables in database "test"
    > > --what??? N2
    > 
    > That's interesting. REFRESH MATERIALIZED VIEW CONCURRENTLY uses 
    > temporary tables internally, which fails if the user doesn't have 
    > permissions to create temporary tables.
    > 
    > I guess we need to allow creating such internal temporary tables, 
    > despite the missing permission. That'll need some careful analysis to 
    > make sure we don't accidentally allow creating other temporary tables...
    
    Wouldn't it be sufficient to document that fact, perhaps add an
    error hint and require the MV owner to have TEMP on the database?
    
    That's not an outrageous requirement, and it couldn't open any
    security back doors.
    
    Yours,
    Laurenz Albe
    
    
    
    
  5. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Maxim Boguk <maxim.boguk@gmail.com> — 2024-03-12T10:40:31Z

    >
    > > test=# REFRESH MATERIALIZED VIEW CONCURRENTLY test_mv;
    > > ERROR:  permission denied for table test
    > > --what??? N1
    > >
    > > --check that im not hallucinating
    > > test=# select * from test;
    > >   val
    > > -----
    > >     1
    > > (1 row)
    >
    > So far, this is working correctly. REFRESH MATERIALIZED VIEW runs with
    > the permissions of the materialized view's owner. In this case, the
    > owner is 'test_role', which doesn't have select permission on the table.
    >
    
    This decision led to a strange (and only one known to me) case when a
    superuser cannot do something in the database.
    (so far I have yet to see any other possible scenario when a command run by
    superuser fails with permission error).
    
    May I suggest a change to always allow superuser run REFRESH MATERIALIZED
    VIEW (may be via set role or similar mechanics)?
    
    Without that I think it's possible build a case of the database which could
    be dumped but cannot be restored without errors
    (restore from MV owner cannot be done because dump contains create
    extension (for a sample) and restore from superuser cannot be done because
    refresh MV permission check).
    
    
    
    -- 
    Maxim Boguk
    Senior Postgresql DBA
    
    Phone UA: +380 99 143 0000
    Phone AU: +61  45 218 5678
    
  6. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Laurenz Albe <laurenz.albe@cybertec.at> — 2024-03-12T12:22:33Z

    On Tue, 2024-03-12 at 12:40 +0200, Maxim Boguk wrote:
    > May I suggest a change to always allow superuser run
    > REFRESH MATERIALIZED VIEW (may be via set role or similar mechanics)?
    
    If the query ran with superuser permissions, that would be
    a security problem:
    
      CREATE TABLE log (t text);
    
      CREATE FUNCTION f() RETURNS integer LANGUAGE sql
         AS 'INSERT INTO log VALUES (''x''); SELECT 42';
    
      CREATE MATERIALIZED VIEW v AS SELECT f();
    
    Now imagine you create a malicious trigger on "log" and
    get a superuser to refresh the materialized view.
    
    
    I don't see why it should be a problem if a superuser gets
    "permission denied" in such a case.  They can also get it if
    they call a SECURITY DEFINER function owned by a non-superuser.
    
    Yours,
    Laurenz Albe
    
    
    
    
  7. BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Wetmore, Matthew (CTR) <matthew.wetmore@evernorth.com> — 2024-03-12T13:51:46Z

     
    > I guess we need to allow creating such internal temporary tables, 
    > despite the missing permission. That'll need some careful analysis to 
    > make sure we don't accidentally allow creating other temporary tables...
    
    Wouldn't it be sufficient to document that fact, perhaps add an error hint and require the MV owner to have TEMP on the database?
    
    That's not an outrageous requirement, and it couldn't open any security back doors.
    
    
    Agree. We already have to create a new user (well, that’s what I do) for MV's anyway for the REFRESH by owner only, it would not be a burden to adjust that ROLE's settings at time of creation.  The doco is completely clear about MV owner, we can just add to that note to make sure CREATE permission too.
    
    
  8. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Tom Lane <tgl@sss.pgh.pa.us> — 2024-03-12T14:08:14Z

    Laurenz Albe <laurenz.albe@cybertec.at> writes:
    > On Tue, 2024-03-12 at 01:02 +0200, Heikki Linnakangas wrote:
    >> I guess we need to allow creating such internal temporary tables, 
    >> despite the missing permission. That'll need some careful analysis to 
    >> make sure we don't accidentally allow creating other temporary tables...
    
    > Wouldn't it be sufficient to document that fact, perhaps add an
    > error hint and require the MV owner to have TEMP on the database?
    
    +1.  I don't see a need for this to be a low-permissions feature.
    
    			regards, tom lane
    
    
    
    
  9. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Bruce Momjian <bruce@momjian.us> — 2024-03-13T17:08:09Z

    On Tue, Mar 12, 2024 at 01:22:33PM +0100, Laurenz Albe wrote:
    > On Tue, 2024-03-12 at 12:40 +0200, Maxim Boguk wrote:
    > > May I suggest a change to always allow superuser run
    > > REFRESH MATERIALIZED VIEW (may be via set role or similar mechanics)?
    > 
    > If the query ran with superuser permissions, that would be
    > a security problem:
    > 
    >   CREATE TABLE log (t text);
    > 
    >   CREATE FUNCTION f() RETURNS integer LANGUAGE sql
    >      AS 'INSERT INTO log VALUES (''x''); SELECT 42';
    > 
    >   CREATE MATERIALIZED VIEW v AS SELECT f();
    > 
    > Now imagine you create a malicious trigger on "log" and
    > get a superuser to refresh the materialized view.
    > 
    > 
    > I don't see why it should be a problem if a superuser gets
    > "permission denied" in such a case.  They can also get it if
    > they call a SECURITY DEFINER function owned by a non-superuser.
    
    Can we improve the error that superusers get so they realize how to fix
    it?
    
    -- 
      Bruce Momjian  <bruce@momjian.us>        https://momjian.us
      EDB                                      https://enterprisedb.com
    
      Only you can decide what is important to you.
    
    
    
    
  10. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Tom Lane <tgl@sss.pgh.pa.us> — 2024-03-13T18:32:55Z

    Bruce Momjian <bruce@momjian.us> writes:
    > On Tue, Mar 12, 2024 at 01:22:33PM +0100, Laurenz Albe wrote:
    >> I don't see why it should be a problem if a superuser gets
    >> "permission denied" in such a case.  They can also get it if
    >> they call a SECURITY DEFINER function owned by a non-superuser.
    
    > Can we improve the error that superusers get so they realize how to fix
    > it?
    
    I think there's been a policy of being minimalistic on
    permission-denied errors to avoid giving away security information,
    but I'm not sure how much sense that really makes.  We already show
    the specific object that didn't have permissions.  I think it would
    be good for these errors to also mention the specific role whose
    permissions were checked.  Perhaps also show the specific privileges
    that were missing --- although it might be hard to do that in a
    non-confusing way for complicated cases, such as queries that are
    valid if you have either table- or column-level permissions.
    
    If we just add the role I'd envision
    
    ERROR:  permission denied to role "foo" for [object]
    
    although with any more detail that would get too long.
    Another way could be
    
    ERROR:  permission denied for [object]
    DETAIL:  Role "foo" lacks permission [permission].
    
    Mentioning the role that was checked should address the concern
    of "I'm a superuser, why did I get this error?".  However,
    fixing it requires knowing which privilege to grant.  I'm not
    sure if that's always obvious.
    
    			regards, tom lane
    
    
    
    
  11. Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view

    Bruce Momjian <bruce@momjian.us> — 2024-03-15T02:36:10Z

    On Wed, Mar 13, 2024 at 02:32:55PM -0400, Tom Lane wrote:
    > I think there's been a policy of being minimalistic on
    > permission-denied errors to avoid giving away security information,
    > but I'm not sure how much sense that really makes.  We already show
    > the specific object that didn't have permissions.  I think it would
    > be good for these errors to also mention the specific role whose
    > permissions were checked.  Perhaps also show the specific privileges
    > that were missing --- although it might be hard to do that in a
    > non-confusing way for complicated cases, such as queries that are
    > valid if you have either table- or column-level permissions.
    > 
    > If we just add the role I'd envision
    > 
    > ERROR:  permission denied to role "foo" for [object]
    > 
    > although with any more detail that would get too long.
    > Another way could be
    > 
    > ERROR:  permission denied for [object]
    > DETAIL:  Role "foo" lacks permission [permission].
    > 
    > Mentioning the role that was checked should address the concern
    > of "I'm a superuser, why did I get this error?".  However,
    > fixing it requires knowing which privilege to grant.  I'm not
    > sure if that's always obvious.
    
    If we don't want to expand the error, and I can see why we might not
    want to, giving the detailed error only for the superuser would be safe,
    I think, since they are already the superuser.
    
    Personal note:  my son Matthew got this error when using photoview
    software, and I was confused why the superuser was getting a permission
    error.
    
    -- 
      Bruce Momjian  <bruce@momjian.us>        https://momjian.us
      EDB                                      https://enterprisedb.com
    
      Only you can decide what is important to you.