Thread: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
PG Bug reporting form
Date:
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
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Heikki Linnakangas
Date:
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)
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Bruce Momjian
Date:
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.
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Laurenz Albe
Date:
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
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Maxim Boguk
Date:
> 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
Senior Postgresql DBA
Phone UA: +380 99 143 0000
Phone AU: +61 45 218 5678
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Laurenz Albe
Date:
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
BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
"Wetmore, Matthew (CTR)"
Date:
> 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 wouldnot be a burden to adjust that ROLE's settings at time of creation. The doco is completely clear about MV owner, wecan just add to that note to make sure CREATE permission too.
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Tom Lane
Date:
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
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Bruce Momjian
Date:
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.
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Tom Lane
Date:
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
Re: BUG #18387: Erroneous permission checks and/or misleading error messages with refresh materialized view
From
Bruce Momjian
Date:
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.