Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit06414c0

Browse files
committed
Fix superuser concurrent refresh of matview owned by another.
Use SECURITY_LOCAL_USERID_CHANGE while building temporary tables;only escalate to SECURITY_RESTRICTED_OPERATION while potentiallyrunning user-supplied code. The more secure mode was preventingtemp table creation. Add regression tests to cover this problem.This fixes Bug #11208 reported by Bruno Emanuel de Andrade Silva.Backpatch to 9.4, where the bug was introduced.
1 parent3a3d3f9 commit06414c0

File tree

3 files changed

+70
-48
lines changed

3 files changed

+70
-48
lines changed

‎src/backend/commands/matview.c

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,13 @@ static void transientrel_receive(TupleTableSlot *slot, DestReceiver *self);
5959
staticvoidtransientrel_shutdown(DestReceiver*self);
6060
staticvoidtransientrel_destroy(DestReceiver*self);
6161
staticvoidrefresh_matview_datafill(DestReceiver*dest,Query*query,
62-
constchar*queryString,Oidrelowner);
62+
constchar*queryString);
6363

6464
staticchar*make_temptable_name_n(char*tempname,intn);
6565
staticvoidmv_GenerateOper(StringInfobuf,Oidopoid);
6666

67-
staticvoidrefresh_by_match_merge(OidmatviewOid,OidtempOid);
67+
staticvoidrefresh_by_match_merge(OidmatviewOid,OidtempOid,Oidrelowner,
68+
intsave_sec_context);
6869
staticvoidrefresh_by_heap_swap(OidmatviewOid,OidOIDNewHeap);
6970

7071
staticvoidOpenMatViewIncrementalMaintenance(void);
@@ -142,11 +143,14 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
142143
List*actions;
143144
Query*dataQuery;
144145
OidtableSpace;
145-
Oidowner;
146+
Oidrelowner;
146147
OidOIDNewHeap;
147148
DestReceiver*dest;
148149
boolconcurrent;
149150
LOCKMODElockmode;
151+
Oidsave_userid;
152+
intsave_sec_context;
153+
intsave_nestlevel;
150154

151155
/* Determine strength of lock needed. */
152156
concurrent=stmt->concurrent;
@@ -231,14 +235,25 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
231235
*/
232236
SetMatViewPopulatedState(matviewRel, !stmt->skipData);
233237

238+
relowner=matviewRel->rd_rel->relowner;
239+
240+
/*
241+
* Switch to the owner's userid, so that any functions are run as that
242+
* user. Also arrange to make GUC variable changes local to this command.
243+
* Don't lock it down too tight to create a temporary table just yet. We
244+
* will switch modes when we are about to execute user code.
245+
*/
246+
GetUserIdAndSecContext(&save_userid,&save_sec_context);
247+
SetUserIdAndSecContext(relowner,
248+
save_sec_context |SECURITY_LOCAL_USERID_CHANGE);
249+
save_nestlevel=NewGUCNestLevel();
250+
234251
/* Concurrent refresh builds new data in temp tablespace, and does diff. */
235252
if (concurrent)
236253
tableSpace=GetDefaultTablespace(RELPERSISTENCE_TEMP);
237254
else
238255
tableSpace=matviewRel->rd_rel->reltablespace;
239256

240-
owner=matviewRel->rd_rel->relowner;
241-
242257
/*
243258
* Create the transient table that will receive the regenerated data. Lock
244259
* it against access by any other process until commit (by which time it
@@ -249,9 +264,15 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
249264
LockRelationOid(OIDNewHeap,AccessExclusiveLock);
250265
dest=CreateTransientRelDestReceiver(OIDNewHeap);
251266

267+
/*
268+
* Now lock down security-restricted operations.
269+
*/
270+
SetUserIdAndSecContext(relowner,
271+
save_sec_context |SECURITY_RESTRICTED_OPERATION);
272+
252273
/* Generate the data, if wanted. */
253274
if (!stmt->skipData)
254-
refresh_matview_datafill(dest,dataQuery,queryString,owner);
275+
refresh_matview_datafill(dest,dataQuery,queryString);
255276

256277
heap_close(matviewRel,NoLock);
257278

@@ -262,7 +283,8 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
262283

263284
PG_TRY();
264285
{
265-
refresh_by_match_merge(matviewOid,OIDNewHeap);
286+
refresh_by_match_merge(matviewOid,OIDNewHeap,relowner,
287+
save_sec_context);
266288
}
267289
PG_CATCH();
268290
{
@@ -274,33 +296,26 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
274296
}
275297
else
276298
refresh_by_heap_swap(matviewOid,OIDNewHeap);
299+
300+
/* Roll back any GUC changes */
301+
AtEOXact_GUC(false,save_nestlevel);
302+
303+
/* Restore userid and security context */
304+
SetUserIdAndSecContext(save_userid,save_sec_context);
277305
}
278306

279307
/*
280308
* refresh_matview_datafill
281309
*/
282310
staticvoid
283311
refresh_matview_datafill(DestReceiver*dest,Query*query,
284-
constchar*queryString,Oidrelowner)
312+
constchar*queryString)
285313
{
286314
List*rewritten;
287315
PlannedStmt*plan;
288316
QueryDesc*queryDesc;
289-
Oidsave_userid;
290-
intsave_sec_context;
291-
intsave_nestlevel;
292317
Query*copied_query;
293318

294-
/*
295-
* Switch to the owner's userid, so that any functions are run as that
296-
* user. Also lock down security-restricted operations and arrange to
297-
* make GUC variable changes local to this command.
298-
*/
299-
GetUserIdAndSecContext(&save_userid,&save_sec_context);
300-
SetUserIdAndSecContext(relowner,
301-
save_sec_context |SECURITY_RESTRICTED_OPERATION);
302-
save_nestlevel=NewGUCNestLevel();
303-
304319
/* Lock and rewrite, using a copy to preserve the original query. */
305320
copied_query=copyObject(query);
306321
AcquireRewriteLocks(copied_query, true, false);
@@ -344,12 +359,6 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
344359
FreeQueryDesc(queryDesc);
345360

346361
PopActiveSnapshot();
347-
348-
/* Roll back any GUC changes */
349-
AtEOXact_GUC(false,save_nestlevel);
350-
351-
/* Restore userid and security context */
352-
SetUserIdAndSecContext(save_userid,save_sec_context);
353362
}
354363

355364
DestReceiver*
@@ -520,7 +529,8 @@ mv_GenerateOper(StringInfo buf, Oid opoid)
520529
* this command.
521530
*/
522531
staticvoid
523-
refresh_by_match_merge(OidmatviewOid,OidtempOid)
532+
refresh_by_match_merge(OidmatviewOid,OidtempOid,Oidrelowner,
533+
intsave_sec_context)
524534
{
525535
StringInfoDataquerybuf;
526536
RelationmatviewRel;
@@ -534,9 +544,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
534544
ListCell*indexoidscan;
535545
int16relnatts;
536546
bool*usedForQual;
537-
Oidsave_userid;
538-
intsave_sec_context;
539-
intsave_nestlevel;
540547

541548
initStringInfo(&querybuf);
542549
matviewRel=heap_open(matviewOid,NoLock);
@@ -587,6 +594,9 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
587594
SPI_getvalue(SPI_tuptable->vals[0],SPI_tuptable->tupdesc,1))));
588595
}
589596

597+
SetUserIdAndSecContext(relowner,
598+
save_sec_context |SECURITY_LOCAL_USERID_CHANGE);
599+
590600
/* Start building the query for creating the diff table. */
591601
resetStringInfo(&querybuf);
592602
appendStringInfo(&querybuf,
@@ -681,9 +691,12 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
681691
if (SPI_exec(querybuf.data,0)!=SPI_OK_UTILITY)
682692
elog(ERROR,"SPI_exec failed: %s",querybuf.data);
683693

694+
SetUserIdAndSecContext(relowner,
695+
save_sec_context |SECURITY_RESTRICTED_OPERATION);
696+
684697
/*
685698
* We have no further use for data from the "full-data" temp table, but we
686-
* must keep it around because its type isreference from the diff table.
699+
* must keep it around because its type isreferenced from the diff table.
687700
*/
688701

689702
/* Analyze the diff table. */
@@ -694,16 +707,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
694707

695708
OpenMatViewIncrementalMaintenance();
696709

697-
/*
698-
* Switch to the owner's userid, so that any functions are run as that
699-
* user. Also lock down security-restricted operations and arrange to
700-
* make GUC variable changes local to this command.
701-
*/
702-
GetUserIdAndSecContext(&save_userid,&save_sec_context);
703-
SetUserIdAndSecContext(matviewRel->rd_rel->relowner,
704-
save_sec_context |SECURITY_RESTRICTED_OPERATION);
705-
save_nestlevel=NewGUCNestLevel();
706-
707710
/* Deletes must come before inserts; do them first. */
708711
resetStringInfo(&querybuf);
709712
appendStringInfo(&querybuf,
@@ -724,12 +727,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
724727
if (SPI_exec(querybuf.data,0)!=SPI_OK_INSERT)
725728
elog(ERROR,"SPI_exec failed: %s",querybuf.data);
726729

727-
/* Roll back any GUC changes */
728-
AtEOXact_GUC(false,save_nestlevel);
729-
730-
/* Restore userid and security context */
731-
SetUserIdAndSecContext(save_userid,save_sec_context);
732-
733730
/* We're done maintaining the materialized view. */
734731
CloseMatViewIncrementalMaintenance();
735732
heap_close(tempRel,NoLock);

‎src/test/regress/expected/matview.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,3 +502,15 @@ SELECT * FROM mv_v;
502502

503503
DROP TABLE v CASCADE;
504504
NOTICE: drop cascades to materialized view mv_v
505+
-- make sure running as superuser works when MV owned by another role (bug #11208)
506+
CREATE ROLE user_dw;
507+
SET ROLE user_dw;
508+
CREATE TABLE foo_data AS SELECT i, md5(random()::text)
509+
FROM generate_series(1, 10) i;
510+
CREATE MATERIALIZED VIEW mv_foo AS SELECT * FROM foo_data;
511+
CREATE UNIQUE INDEX ON mv_foo (i);
512+
RESET ROLE;
513+
REFRESH MATERIALIZED VIEW mv_foo;
514+
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_foo;
515+
DROP OWNED BY user_dw CASCADE;
516+
DROP ROLE user_dw;

‎src/test/regress/sql/matview.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,16 @@ DELETE FROM v WHERE EXISTS ( SELECT * FROM mv_v WHERE mv_v.a = v.a );
194194
SELECT*FROM v;
195195
SELECT*FROM mv_v;
196196
DROPTABLE v CASCADE;
197+
198+
-- make sure running as superuser works when MV owned by another role (bug #11208)
199+
CREATE ROLE user_dw;
200+
SET ROLE user_dw;
201+
CREATETABLEfoo_dataASSELECT i, md5(random()::text)
202+
FROM generate_series(1,10) i;
203+
CREATE MATERIALIZED VIEW mv_fooASSELECT*FROM foo_data;
204+
CREATEUNIQUE INDEXON mv_foo (i);
205+
RESET ROLE;
206+
REFRESH MATERIALIZED VIEW mv_foo;
207+
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_foo;
208+
DROP OWNED BY user_dw CASCADE;
209+
DROP ROLE user_dw;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp