Skip to content

Commit 34ff156

Browse files
committed
In REFRESH MATERIALIZED VIEW, set user ID before running user code.
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
1 parent 48ca290 commit 34ff156

File tree

3 files changed

+44
-19
lines changed

3 files changed

+44
-19
lines changed

src/backend/commands/matview.c

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,17 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
164164
lockmode, 0,
165165
RangeVarCallbackOwnsTable, NULL);
166166
matviewRel = heap_open(matviewOid, NoLock);
167+
relowner = matviewRel->rd_rel->relowner;
168+
169+
/*
170+
* Switch to the owner's userid, so that any functions are run as that
171+
* user. Also lock down security-restricted operations and arrange to
172+
* make GUC variable changes local to this command.
173+
*/
174+
GetUserIdAndSecContext(&save_userid, &save_sec_context);
175+
SetUserIdAndSecContext(relowner,
176+
save_sec_context | SECURITY_RESTRICTED_OPERATION);
177+
save_nestlevel = NewGUCNestLevel();
167178

168179
/* Make sure it is a materialized view. */
169180
if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW)
@@ -268,19 +279,6 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
268279
*/
269280
SetMatViewPopulatedState(matviewRel, !stmt->skipData);
270281

271-
relowner = matviewRel->rd_rel->relowner;
272-
273-
/*
274-
* Switch to the owner's userid, so that any functions are run as that
275-
* user. Also arrange to make GUC variable changes local to this command.
276-
* Don't lock it down too tight to create a temporary table just yet. We
277-
* will switch modes when we are about to execute user code.
278-
*/
279-
GetUserIdAndSecContext(&save_userid, &save_sec_context);
280-
SetUserIdAndSecContext(relowner,
281-
save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
282-
save_nestlevel = NewGUCNestLevel();
283-
284282
/* Concurrent refresh builds new data in temp tablespace, and does diff. */
285283
if (concurrent)
286284
{
@@ -303,12 +301,6 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
303301
LockRelationOid(OIDNewHeap, AccessExclusiveLock);
304302
dest = CreateTransientRelDestReceiver(OIDNewHeap);
305303

306-
/*
307-
* Now lock down security-restricted operations.
308-
*/
309-
SetUserIdAndSecContext(relowner,
310-
save_sec_context | SECURITY_RESTRICTED_OPERATION);
311-
312304
/* Generate the data, if wanted. */
313305
if (!stmt->skipData)
314306
processed = refresh_matview_datafill(dest, dataQuery, queryString);

src/test/regress/expected/privileges.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,22 @@ CONTEXT: SQL function "unwanted_grant" statement 1
14361436
SQL statement "SELECT unwanted_grant()"
14371437
PL/pgSQL function sro_trojan() line 1 at PERFORM
14381438
SQL function "mv_action" statement 1
1439+
-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
1440+
SET SESSION AUTHORIZATION regress_sro_user;
1441+
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
1442+
IMMUTABLE LANGUAGE plpgsql AS $$
1443+
BEGIN
1444+
PERFORM unwanted_grant();
1445+
RAISE WARNING 'owned';
1446+
RETURN 1;
1447+
EXCEPTION WHEN OTHERS THEN
1448+
RETURN 2;
1449+
END$$;
1450+
CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c;
1451+
CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0;
1452+
\c -
1453+
REFRESH MATERIALIZED VIEW CONCURRENTLY sro_index_mv;
1454+
REFRESH MATERIALIZED VIEW sro_index_mv;
14391455
DROP OWNED BY regress_sro_user;
14401456
DROP ROLE regress_sro_user;
14411457
-- Admin options

src/test/regress/sql/privileges.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,23 @@ REFRESH MATERIALIZED VIEW sro_mv;
899899
REFRESH MATERIALIZED VIEW sro_mv;
900900
BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
901901

902+
-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions()
903+
SET SESSION AUTHORIZATION regress_sro_user;
904+
CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int
905+
IMMUTABLE LANGUAGE plpgsql AS $$
906+
BEGIN
907+
PERFORM unwanted_grant();
908+
RAISE WARNING 'owned';
909+
RETURN 1;
910+
EXCEPTION WHEN OTHERS THEN
911+
RETURN 2;
912+
END$$;
913+
CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c;
914+
CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0;
915+
\c -
916+
REFRESH MATERIALIZED VIEW CONCURRENTLY sro_index_mv;
917+
REFRESH MATERIALIZED VIEW sro_index_mv;
918+
902919
DROP OWNED BY regress_sro_user;
903920
DROP ROLE regress_sro_user;
904921

0 commit comments

Comments
 (0)