agora inbox for pgsql-hackers@postgresql.orghelp / color / mirror / Atom feed
[PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. 4+ messages / 1 participants [nested] [flat]
* [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. @ 2022-05-09 15:35 Noah Misch <noah@leadboat.com> 0 siblings, 0 replies; 4+ messages in thread From: Noah Misch @ 2022-05-09 15:35 UTC (permalink / raw) It intended to, but did not, achieve this. Adopt the new standard of setting user ID just after locking the relation. Back-patch to v10 (all supported versions). Reviewed by Simon Riggs. Reported by Alvaro Herrera. Security: CVE-2022-1552 --- src/backend/commands/matview.c | 30 +++++++++++------------------- src/test/regress/expected/privileges.out | 15 +++++++++++++++ src/test/regress/sql/privileges.sql | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 19 deletions(-) --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -164,6 +164,17 @@ lockmode, false, false, RangeVarCallbackOwnsTable, NULL); matviewRel = heap_open(matviewOid, NoLock); + relowner = matviewRel->rd_rel->relowner; + + /* + * Switch to the owner's userid, so that any functions are run as that + * user. Also lock down security-restricted operations and arrange to + * make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); /* Make sure it is a materialized view. */ if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW) @@ -269,19 +280,6 @@ */ SetMatViewPopulatedState(matviewRel, !stmt->skipData); - relowner = matviewRel->rd_rel->relowner; - - /* - * Switch to the owner's userid, so that any functions are run as that - * user. Also arrange to make GUC variable changes local to this command. - * Don't lock it down too tight to create a temporary table just yet. We - * will switch modes when we are about to execute user code. - */ - GetUserIdAndSecContext(&save_userid, &save_sec_context); - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - save_nestlevel = NewGUCNestLevel(); - /* Concurrent refresh builds new data in temp tablespace, and does diff. */ if (concurrent) { @@ -304,12 +302,6 @@ LockRelationOid(OIDNewHeap, AccessExclusiveLock); dest = CreateTransientRelDestReceiver(OIDNewHeap); - /* - * Now lock down security-restricted operations. - */ - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_RESTRICTED_OPERATION); - /* Generate the data, if wanted. */ if (!stmt->skipData) refresh_matview_datafill(dest, dataQuery, queryString); --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -1323,6 +1323,21 @@ SQL statement "SELECT unwanted_grant()" PL/pgSQL function sro_trojan() line 1 at PERFORM SQL function "mv_action" statement 1 +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; -- Admin options --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -824,6 +824,22 @@ REFRESH MATERIALIZED VIEW sro_mv; BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT; +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; + DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; --Gfegn71+neI+QTr7 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="CVE-2022-1552_88b39e6148_adapted_for_9.6.patch" ^ permalink raw reply [nested|flat] 4+ messages in thread
* [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. @ 2022-05-09 15:35 Noah Misch <noah@leadboat.com> 0 siblings, 0 replies; 4+ messages in thread From: Noah Misch @ 2022-05-09 15:35 UTC (permalink / raw) It intended to, but did not, achieve this. Adopt the new standard of setting user ID just after locking the relation. Back-patch to v10 (all supported versions). Reviewed by Simon Riggs. Reported by Alvaro Herrera. Security: CVE-2022-1552 --- src/backend/commands/matview.c | 30 +++++++++++------------------- src/test/regress/expected/privileges.out | 15 +++++++++++++++ src/test/regress/sql/privileges.sql | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 19 deletions(-) --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -161,6 +161,17 @@ lockmode, false, false, RangeVarCallbackOwnsTable, NULL); matviewRel = heap_open(matviewOid, NoLock); + relowner = matviewRel->rd_rel->relowner; + + /* + * Switch to the owner's userid, so that any functions are run as that + * user. Also lock down security-restricted operations and arrange to + * make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); /* Make sure it is a materialized view. */ if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW) @@ -233,19 +244,6 @@ */ SetMatViewPopulatedState(matviewRel, !stmt->skipData); - relowner = matviewRel->rd_rel->relowner; - - /* - * Switch to the owner's userid, so that any functions are run as that - * user. Also arrange to make GUC variable changes local to this command. - * Don't lock it down too tight to create a temporary table just yet. We - * will switch modes when we are about to execute user code. - */ - GetUserIdAndSecContext(&save_userid, &save_sec_context); - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - save_nestlevel = NewGUCNestLevel(); - /* Concurrent refresh builds new data in temp tablespace, and does diff. */ if (concurrent) tableSpace = GetDefaultTablespace(RELPERSISTENCE_TEMP); @@ -262,12 +260,6 @@ LockRelationOid(OIDNewHeap, AccessExclusiveLock); dest = CreateTransientRelDestReceiver(OIDNewHeap); - /* - * Now lock down security-restricted operations. - */ - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_RESTRICTED_OPERATION); - /* Generate the data, if wanted. */ if (!stmt->skipData) refresh_matview_datafill(dest, dataQuery, queryString); --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -1266,6 +1266,21 @@ SQL statement "SELECT unwanted_grant()" PL/pgSQL function sro_trojan() line 1 at PERFORM SQL function "mv_action" statement 1 +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; -- Admin options --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -784,6 +784,22 @@ REFRESH MATERIALIZED VIEW sro_mv; BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT; +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; + DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; --Gfegn71+neI+QTr7 Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="CVE-2022-1552_88b39e6148_adapted_for_9.4.patch" ^ permalink raw reply [nested|flat] 4+ messages in thread
* [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. @ 2022-05-09 15:35 Noah Misch <noah@leadboat.com> 0 siblings, 0 replies; 4+ messages in thread From: Noah Misch @ 2022-05-09 15:35 UTC (permalink / raw) It intended to, but did not, achieve this. Adopt the new standard of setting user ID just after locking the relation. Back-patch to v10 (all supported versions). Reviewed by Simon Riggs. Reported by Alvaro Herrera. Security: CVE-2022-1552 --- src/backend/commands/matview.c | 30 +++++++++++------------------- src/test/regress/expected/privileges.out | 15 +++++++++++++++ src/test/regress/sql/privileges.sql | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 19 deletions(-) --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -164,6 +164,17 @@ lockmode, false, false, RangeVarCallbackOwnsTable, NULL); matviewRel = heap_open(matviewOid, NoLock); + relowner = matviewRel->rd_rel->relowner; + + /* + * Switch to the owner's userid, so that any functions are run as that + * user. Also lock down security-restricted operations and arrange to + * make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); /* Make sure it is a materialized view. */ if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW) @@ -269,19 +280,6 @@ */ SetMatViewPopulatedState(matviewRel, !stmt->skipData); - relowner = matviewRel->rd_rel->relowner; - - /* - * Switch to the owner's userid, so that any functions are run as that - * user. Also arrange to make GUC variable changes local to this command. - * Don't lock it down too tight to create a temporary table just yet. We - * will switch modes when we are about to execute user code. - */ - GetUserIdAndSecContext(&save_userid, &save_sec_context); - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - save_nestlevel = NewGUCNestLevel(); - /* Concurrent refresh builds new data in temp tablespace, and does diff. */ if (concurrent) { @@ -304,12 +302,6 @@ LockRelationOid(OIDNewHeap, AccessExclusiveLock); dest = CreateTransientRelDestReceiver(OIDNewHeap); - /* - * Now lock down security-restricted operations. - */ - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_RESTRICTED_OPERATION); - /* Generate the data, if wanted. */ if (!stmt->skipData) refresh_matview_datafill(dest, dataQuery, queryString); --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -1323,6 +1323,21 @@ SQL statement "SELECT unwanted_grant()" PL/pgSQL function sro_trojan() line 1 at PERFORM SQL function "mv_action" statement 1 +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; -- Admin options --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -824,6 +824,22 @@ REFRESH MATERIALIZED VIEW sro_mv; BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT; +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; + DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; --i8OOMDZy1VRtDE1s Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="CVE-2022-1552_commit_ef792f7856_adapted_for_9.4.patch" ^ permalink raw reply [nested|flat] 4+ messages in thread
* [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. @ 2022-05-09 15:35 Noah Misch <noah@leadboat.com> 0 siblings, 0 replies; 4+ messages in thread From: Noah Misch @ 2022-05-09 15:35 UTC (permalink / raw) It intended to, but did not, achieve this. Adopt the new standard of setting user ID just after locking the relation. Back-patch to v10 (all supported versions). Reviewed by Simon Riggs. Reported by Alvaro Herrera. Security: CVE-2022-1552 --- src/backend/commands/matview.c | 30 +++++++++++------------------- src/test/regress/expected/privileges.out | 15 +++++++++++++++ src/test/regress/sql/privileges.sql | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 19 deletions(-) --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -161,6 +161,17 @@ lockmode, false, false, RangeVarCallbackOwnsTable, NULL); matviewRel = heap_open(matviewOid, NoLock); + relowner = matviewRel->rd_rel->relowner; + + /* + * Switch to the owner's userid, so that any functions are run as that + * user. Also lock down security-restricted operations and arrange to + * make GUC variable changes local to this command. + */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(relowner, + save_sec_context | SECURITY_RESTRICTED_OPERATION); + save_nestlevel = NewGUCNestLevel(); /* Make sure it is a materialized view. */ if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW) @@ -233,19 +244,6 @@ */ SetMatViewPopulatedState(matviewRel, !stmt->skipData); - relowner = matviewRel->rd_rel->relowner; - - /* - * Switch to the owner's userid, so that any functions are run as that - * user. Also arrange to make GUC variable changes local to this command. - * Don't lock it down too tight to create a temporary table just yet. We - * will switch modes when we are about to execute user code. - */ - GetUserIdAndSecContext(&save_userid, &save_sec_context); - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_LOCAL_USERID_CHANGE); - save_nestlevel = NewGUCNestLevel(); - /* Concurrent refresh builds new data in temp tablespace, and does diff. */ if (concurrent) tableSpace = GetDefaultTablespace(RELPERSISTENCE_TEMP); @@ -262,12 +260,6 @@ LockRelationOid(OIDNewHeap, AccessExclusiveLock); dest = CreateTransientRelDestReceiver(OIDNewHeap); - /* - * Now lock down security-restricted operations. - */ - SetUserIdAndSecContext(relowner, - save_sec_context | SECURITY_RESTRICTED_OPERATION); - /* Generate the data, if wanted. */ if (!stmt->skipData) refresh_matview_datafill(dest, dataQuery, queryString); --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -1266,6 +1266,21 @@ SQL statement "SELECT unwanted_grant()" PL/pgSQL function sro_trojan() line 1 at PERFORM SQL function "mv_action" statement 1 +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; -- Admin options --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -784,6 +784,22 @@ REFRESH MATERIALIZED VIEW sro_mv; BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT; +-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int + IMMUTABLE LANGUAGE plpgsql AS $$ +BEGIN + PERFORM unwanted_grant(); + RAISE WARNING 'owned'; + RETURN 1; +EXCEPTION WHEN OTHERS THEN + RETURN 2; +END$$; +CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; +CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; +\c - +REFRESH MATERIALIZED VIEW sro_index_mv; + DROP OWNED BY regress_sro_user; DROP ROLE regress_sro_user; --i8OOMDZy1VRtDE1s-- ^ permalink raw reply [nested|flat] 4+ messages in thread
end of thread, other threads:[~2022-05-09 15:35 UTC | newest] Thread overview: 4+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2022-05-09 15:35 [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. Noah Misch <noah@leadboat.com> 2022-05-09 15:35 [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. Noah Misch <noah@leadboat.com> 2022-05-09 15:35 [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. Noah Misch <noah@leadboat.com> 2022-05-09 15:35 [PATCH] In REFRESH MATERIALIZED VIEW, set user ID before running user code. Noah Misch <noah@leadboat.com>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox