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

Commit6214e2b

Browse files
committed
Fix permission checks on constraint violation errors on partitions.
If a cross-partition UPDATE violates a constraint on the target partition,and the columns in the new partition are in different physical order thanin the parent, the error message can reveal columns that the user does nothave SELECT permission on. A similar bug was fixed earlier in commit804b6b6.The cause of the bug is that the callers of theExecBuildSlotValueDescription() function got confused when constructingthe list of modified columns. If the tuple was routed from a parent, weconverted the tuple to the parent's format, but the list of modifiedcolumns was grabbed directly from the child's RTE entry.ExecUpdateLockMode() had a similar issue. That lead to confusion on whichcolumns are key columns, leading to wrong tuple lock being taken on tablesreferenced by foreign keys, when a row is updated with INSERT ON CONFLICTUPDATE. A new isolation test is added for that corner case.With this patch, the ri_RangeTableIndex field is no longer set forpartitions that don't have an entry in the range table. Previously, it wasset to the RTE entry of the parent relation, but that was confusing.NOTE: This modifies the ResultRelInfo struct, replacing theri_PartitionRoot field with ri_RootResultRelInfo. That's a bit risky tobackpatch, because it breaks any extensions accessing the field. Thechange that ri_RangeTableIndex is not set for partitions could potentiallybreak extensions, too. The ResultRelInfos are visible to FDWs at least,and this patch required small changes to postgres_fdw. Nevertheless, thisseem like the least bad option. I don't think these fields widely used inextensions; I don't think there are FDWs out there that uses the FDW"direct update" API, other than postgres_fdw. If there is, you will get acompilation error, so hopefully it is caught quickly.Backpatch to 11, where support for both cross-partition UPDATEs, and uniqueindexes on partitioned tables, were added.Reviewed-by: Amit LangoteSecurity:CVE-2021-3393
1 parent617fffe commit6214e2b

File tree

18 files changed

+368
-98
lines changed

18 files changed

+368
-98
lines changed

‎contrib/postgres_fdw/postgres_fdw.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,7 +2025,7 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
20252025
PgFdwModifyState*fmstate;
20262026
ModifyTable*plan=castNode(ModifyTable,mtstate->ps.plan);
20272027
EState*estate=mtstate->ps.state;
2028-
IndexresultRelation=resultRelInfo->ri_RangeTableIndex;
2028+
IndexresultRelation;
20292029
Relationrel=resultRelInfo->ri_RelationDesc;
20302030
RangeTblEntry*rte;
20312031
TupleDesctupdesc=RelationGetDescr(rel);
@@ -2077,17 +2077,20 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
20772077
}
20782078

20792079
/*
2080-
* If the foreign table is a partition, we need to create a new RTE
2080+
* If the foreign table is a partition that doesn't have a corresponding
2081+
* RTE entry, we need to create a new RTE
20812082
* describing the foreign table for use by deparseInsertSql and
20822083
* create_foreign_modify() below, after first copying the parent's RTE and
20832084
* modifying some fields to describe the foreign partition to work on.
20842085
* However, if this is invoked by UPDATE, the existing RTE may already
20852086
* correspond to this partition if it is one of the UPDATE subplan target
20862087
* rels; in that case, we can just use the existing RTE as-is.
20872088
*/
2088-
rte=exec_rt_fetch(resultRelation,estate);
2089-
if (rte->relid!=RelationGetRelid(rel))
2089+
if (resultRelInfo->ri_RangeTableIndex==0)
20902090
{
2091+
ResultRelInfo*rootResultRelInfo=resultRelInfo->ri_RootResultRelInfo;
2092+
2093+
rte=exec_rt_fetch(rootResultRelInfo->ri_RangeTableIndex,estate);
20912094
rte=copyObject(rte);
20922095
rte->relid=RelationGetRelid(rel);
20932096
rte->relkind=RELKIND_FOREIGN_TABLE;
@@ -2099,8 +2102,15 @@ postgresBeginForeignInsert(ModifyTableState *mtstate,
20992102
* Vars contained in those expressions.
21002103
*/
21012104
if (plan&&plan->operation==CMD_UPDATE&&
2102-
resultRelation==plan->rootRelation)
2105+
rootResultRelInfo->ri_RangeTableIndex==plan->rootRelation)
21032106
resultRelation=mtstate->resultRelInfo[0].ri_RangeTableIndex;
2107+
else
2108+
resultRelation=rootResultRelInfo->ri_RangeTableIndex;
2109+
}
2110+
else
2111+
{
2112+
resultRelation=resultRelInfo->ri_RangeTableIndex;
2113+
rte=exec_rt_fetch(resultRelation,estate);
21042114
}
21052115

21062116
/* Construct the SQL command string. */

‎src/backend/access/common/tupconvert.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,57 @@ execute_attr_map_slot(AttrMap *attrMap,
226226
returnout_slot;
227227
}
228228

229+
/*
230+
* Perform conversion of bitmap of columns according to the map.
231+
*
232+
* The input and output bitmaps are offset by
233+
* FirstLowInvalidHeapAttributeNumber to accommodate system cols, like the
234+
* column-bitmaps in RangeTblEntry.
235+
*/
236+
Bitmapset*
237+
execute_attr_map_cols(AttrMap*attrMap,Bitmapset*in_cols)
238+
{
239+
Bitmapset*out_cols;
240+
intout_attnum;
241+
242+
/* fast path for the common trivial case */
243+
if (in_cols==NULL)
244+
returnNULL;
245+
246+
/*
247+
* For each output column, check which input column it corresponds to.
248+
*/
249+
out_cols=NULL;
250+
251+
for (out_attnum=FirstLowInvalidHeapAttributeNumber;
252+
out_attnum <=attrMap->maplen;
253+
out_attnum++)
254+
{
255+
intin_attnum;
256+
257+
if (out_attnum<0)
258+
{
259+
/* System column. No mapping. */
260+
in_attnum=out_attnum;
261+
}
262+
elseif (out_attnum==0)
263+
continue;
264+
else
265+
{
266+
/* normal user column */
267+
in_attnum=attrMap->attnums[out_attnum-1];
268+
269+
if (in_attnum==0)
270+
continue;
271+
}
272+
273+
if (bms_is_member(in_attnum-FirstLowInvalidHeapAttributeNumber,in_cols))
274+
out_cols=bms_add_member(out_cols,out_attnum-FirstLowInvalidHeapAttributeNumber);
275+
}
276+
277+
returnout_cols;
278+
}
279+
229280
/*
230281
* Free a TupleConversionMap structure.
231282
*/

‎src/backend/commands/copyfrom.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ CopyFrom(CopyFromState cstate)
666666
mtstate->ps.state=estate;
667667
mtstate->operation=CMD_INSERT;
668668
mtstate->resultRelInfo=resultRelInfo;
669+
mtstate->rootResultRelInfo=resultRelInfo;
669670

670671
if (resultRelInfo->ri_FdwRoutine!=NULL&&
671672
resultRelInfo->ri_FdwRoutine->BeginForeignInsert!=NULL)

‎src/backend/commands/explain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3694,7 +3694,7 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors,
36943694
/* Should we explicitly label target relations? */
36953695
labeltargets= (mtstate->mt_nplans>1||
36963696
(mtstate->mt_nplans==1&&
3697-
mtstate->resultRelInfo->ri_RangeTableIndex!=node->nominalRelation));
3697+
mtstate->resultRelInfo[0].ri_RangeTableIndex!=node->nominalRelation));
36983698

36993699
if (labeltargets)
37003700
ExplainOpenGroup("Target Tables","Target Tables", false,es);

‎src/backend/commands/trigger.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,6 @@ intSessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
7070
/* How many levels deep into trigger execution are we? */
7171
staticintMyTriggerDepth=0;
7272

73-
/*
74-
* The authoritative version of this macro is in executor/execMain.c. Be sure
75-
* to keep everything in sync.
76-
*/
77-
#defineGetAllUpdatedColumns(relinfo,estate) \
78-
(bms_union(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols, \
79-
exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols))
80-
8173
/* Local function prototypes */
8274
staticvoidSetTriggerFlags(TriggerDesc*trigdesc,Trigger*trigger);
8375
staticboolGetTupleForTrigger(EState*estate,
@@ -2643,7 +2635,10 @@ ExecBSUpdateTriggers(EState *estate, ResultRelInfo *relinfo)
26432635
CMD_UPDATE))
26442636
return;
26452637

2646-
updatedCols=GetAllUpdatedColumns(relinfo,estate);
2638+
/* statement-level triggers operate on the parent table */
2639+
Assert(relinfo->ri_RootResultRelInfo==NULL);
2640+
2641+
updatedCols=ExecGetAllUpdatedCols(relinfo,estate);
26472642

26482643
LocTriggerData.type=T_TriggerData;
26492644
LocTriggerData.tg_event=TRIGGER_EVENT_UPDATE |
@@ -2684,10 +2679,13 @@ ExecASUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
26842679
{
26852680
TriggerDesc*trigdesc=relinfo->ri_TrigDesc;
26862681

2682+
/* statement-level triggers operate on the parent table */
2683+
Assert(relinfo->ri_RootResultRelInfo==NULL);
2684+
26872685
if (trigdesc&&trigdesc->trig_update_after_statement)
26882686
AfterTriggerSaveEvent(estate,relinfo,TRIGGER_EVENT_UPDATE,
26892687
false,NULL,NULL,NIL,
2690-
GetAllUpdatedColumns(relinfo,estate),
2688+
ExecGetAllUpdatedCols(relinfo,estate),
26912689
transition_capture);
26922690
}
26932691

@@ -2757,7 +2755,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
27572755
TRIGGER_EVENT_ROW |
27582756
TRIGGER_EVENT_BEFORE;
27592757
LocTriggerData.tg_relation=relinfo->ri_RelationDesc;
2760-
updatedCols=GetAllUpdatedColumns(relinfo,estate);
2758+
updatedCols=ExecGetAllUpdatedCols(relinfo,estate);
27612759
LocTriggerData.tg_updatedcols=updatedCols;
27622760
for (i=0;i<trigdesc->numtriggers;i++)
27632761
{
@@ -2858,7 +2856,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
28582856

28592857
AfterTriggerSaveEvent(estate,relinfo,TRIGGER_EVENT_UPDATE,
28602858
true,oldslot,newslot,recheckIndexes,
2861-
GetAllUpdatedColumns(relinfo,estate),
2859+
ExecGetAllUpdatedCols(relinfo,estate),
28622860
transition_capture);
28632861
}
28642862
}

‎src/backend/executor/execIndexing.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,6 @@ typedef enum
124124
CEOUC_LIVELOCK_PREVENTING_WAIT
125125
}CEOUC_WAIT_MODE;
126126

127-
/*
128-
* The authoritative version of these macro are in executor/execMain.c. Be
129-
* sure to keep everything in sync.
130-
*/
131-
#defineGetUpdatedColumns(relinfo,estate) \
132-
(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->updatedCols)
133-
#defineGetExtraUpdatedColumns(relinfo,estate) \
134-
(exec_rt_fetch((relinfo)->ri_RangeTableIndex, estate)->extraUpdatedCols)
135-
136127
staticboolcheck_exclusion_or_unique_constraint(Relationheap,Relationindex,
137128
IndexInfo*indexInfo,
138129
ItemPointertupleid,
@@ -944,8 +935,8 @@ static bool
944935
index_unchanged_by_update(ResultRelInfo*resultRelInfo,EState*estate,
945936
IndexInfo*indexInfo,RelationindexRelation)
946937
{
947-
Bitmapset*updatedCols=GetUpdatedColumns(resultRelInfo,estate);
948-
Bitmapset*extraUpdatedCols=GetExtraUpdatedColumns(resultRelInfo,estate);
938+
Bitmapset*updatedCols=ExecGetUpdatedCols(resultRelInfo,estate);
939+
Bitmapset*extraUpdatedCols=ExecGetExtraUpdatedCols(resultRelInfo,estate);
949940
Bitmapset*allUpdatedCols;
950941
boolhasexpression= false;
951942
List*idxExprs;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp