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

Commit804b6b6

Browse files
committed
Fix column-privilege leak in error-message paths
While building error messages to return to the user,BuildIndexValueDescription, ExecBuildSlotValueDescription andri_ReportViolation would happily include the entire key or entire row inthe result returned to the user, even if the user didn't have access toview all of the columns being included.Instead, include only those columns which the user is providing or whichthe user has select rights on. If the user does not have any rightsto view the table or any of the columns involved then no detail isprovided and a NULL value is returned from BuildIndexValueDescriptionand ExecBuildSlotValueDescription. Note that, for key cases, the usermust have access to all of the columns for the key to be shown; apartial key will not be returned.Further, in master only, do not return any data for cases where rowsecurity is enabled on the relation and row security should be appliedfor the user. This required a bit of refactoring and moving of thingsaround related to RLS- note the addition of utils/misc/rls.c.Back-patch all the way, as column-level privileges are now in allsupported versions.This has been assignedCVE-2014-8161, but since the issue and the patchhave already been publicized on pgsql-hackers, there's no point in tryingto hide this commit.
1 parentacc2b1e commit804b6b6

File tree

20 files changed

+569
-194
lines changed

20 files changed

+569
-194
lines changed

‎src/backend/access/index/genam.c

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525
#include"lib/stringinfo.h"
2626
#include"miscadmin.h"
2727
#include"storage/bufmgr.h"
28+
#include"utils/acl.h"
2829
#include"utils/builtins.h"
2930
#include"utils/lsyscache.h"
3031
#include"utils/rel.h"
32+
#include"utils/rls.h"
3133
#include"utils/ruleutils.h"
3234
#include"utils/snapmgr.h"
35+
#include"utils/syscache.h"
3336
#include"utils/tqual.h"
3437

3538

@@ -155,6 +158,11 @@ IndexScanEnd(IndexScanDesc scan)
155158
* form "(key_name, ...)=(key_value, ...)". This is currently used
156159
* for building unique-constraint and exclusion-constraint error messages.
157160
*
161+
* Note that if the user does not have permissions to view all of the
162+
* columns involved then a NULL is returned. Returning a partial key seems
163+
* unlikely to be useful and we have no way to know which of the columns the
164+
* user provided (unlike in ExecBuildSlotValueDescription).
165+
*
158166
* The passed-in values/nulls arrays are the "raw" input to the index AM,
159167
* e.g. results of FormIndexDatum --- this is not necessarily what is stored
160168
* in the index, but it's what the user perceives to be stored.
@@ -164,13 +172,72 @@ BuildIndexValueDescription(Relation indexRelation,
164172
Datum*values,bool*isnull)
165173
{
166174
StringInfoDatabuf;
175+
Form_pg_indexidxrec;
176+
HeapTupleht_idx;
167177
intnatts=indexRelation->rd_rel->relnatts;
168178
inti;
179+
intkeyno;
180+
Oidindexrelid=RelationGetRelid(indexRelation);
181+
Oidindrelid;
182+
AclResultaclresult;
183+
184+
/*
185+
* Check permissions- if the user does not have access to view all of the
186+
* key columns then return NULL to avoid leaking data.
187+
*
188+
* First check if RLS is enabled for the relation. If so, return NULL
189+
* to avoid leaking data.
190+
*
191+
* Next we need to check table-level SELECT access and then, if
192+
* there is no access there, check column-level permissions.
193+
*/
194+
195+
/*
196+
* Fetch the pg_index tuple by the Oid of the index
197+
*/
198+
ht_idx=SearchSysCache1(INDEXRELID,ObjectIdGetDatum(indexrelid));
199+
if (!HeapTupleIsValid(ht_idx))
200+
elog(ERROR,"cache lookup failed for index %u",indexrelid);
201+
idxrec= (Form_pg_index)GETSTRUCT(ht_idx);
202+
203+
indrelid=idxrec->indrelid;
204+
Assert(indexrelid==idxrec->indexrelid);
205+
206+
/* RLS check- if RLS is enabled then we don't return anything. */
207+
if (check_enable_rls(indrelid,GetUserId(), true)==RLS_ENABLED)
208+
{
209+
ReleaseSysCache(ht_idx);
210+
returnNULL;
211+
}
212+
213+
/* Table-level SELECT is enough, if the user has it */
214+
aclresult=pg_class_aclcheck(indrelid,GetUserId(),ACL_SELECT);
215+
if (aclresult!=ACLCHECK_OK)
216+
{
217+
/*
218+
* No table-level access, so step through the columns in the
219+
* index and make sure the user has SELECT rights on all of them.
220+
*/
221+
for (keyno=0;keyno<idxrec->indnatts;keyno++)
222+
{
223+
AttrNumberattnum=idxrec->indkey.values[keyno];
224+
225+
aclresult=pg_attribute_aclcheck(indrelid,attnum,GetUserId(),
226+
ACL_SELECT);
227+
228+
if (aclresult!=ACLCHECK_OK)
229+
{
230+
/* No access, so clean up and return */
231+
ReleaseSysCache(ht_idx);
232+
returnNULL;
233+
}
234+
}
235+
}
236+
ReleaseSysCache(ht_idx);
169237

170238
initStringInfo(&buf);
171239
appendStringInfo(&buf,"(%s)=(",
172-
pg_get_indexdef_columns(RelationGetRelid(indexRelation),
173-
true));
240+
pg_get_indexdef_columns(indexrelid, true));
174241

175242
for (i=0;i<natts;i++)
176243
{

‎src/backend/access/nbtree/nbtinsert.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,16 +389,20 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel,
389389
{
390390
Datumvalues[INDEX_MAX_KEYS];
391391
boolisnull[INDEX_MAX_KEYS];
392+
char*key_desc;
392393

393394
index_deform_tuple(itup,RelationGetDescr(rel),
394395
values,isnull);
396+
397+
key_desc=BuildIndexValueDescription(rel,values,
398+
isnull);
399+
395400
ereport(ERROR,
396401
(errcode(ERRCODE_UNIQUE_VIOLATION),
397402
errmsg("duplicate key value violates unique constraint \"%s\"",
398403
RelationGetRelationName(rel)),
399-
errdetail("Key %s already exists.",
400-
BuildIndexValueDescription(rel,
401-
values,isnull)),
404+
key_desc ?errdetail("Key %s already exists.",
405+
key_desc) :0,
402406
errtableconstraint(heapRel,
403407
RelationGetRelationName(rel))));
404408
}

‎src/backend/commands/copy.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#include"parser/parse_relation.h"
4141
#include"nodes/makefuncs.h"
4242
#include"rewrite/rewriteHandler.h"
43-
#include"rewrite/rowsecurity.h"
4443
#include"storage/fd.h"
4544
#include"tcop/tcopprot.h"
4645
#include"utils/acl.h"
@@ -49,6 +48,7 @@
4948
#include"utils/memutils.h"
5049
#include"utils/portal.h"
5150
#include"utils/rel.h"
51+
#include"utils/rls.h"
5252
#include"utils/snapmgr.h"
5353

5454

@@ -163,6 +163,7 @@ typedef struct CopyStateData
163163
int*defmap;/* array of default att numbers */
164164
ExprState**defexprs;/* array of default att expressions */
165165
boolvolatile_defexprs;/* is any of defexprs volatile? */
166+
List*range_table;
166167

167168
/*
168169
* These variables are used to reduce overhead in textual COPY FROM.
@@ -789,6 +790,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
789790
Relationrel;
790791
Oidrelid;
791792
Node*query=NULL;
793+
RangeTblEntry*rte;
792794

793795
/* Disallow COPY to/from file or program except to superusers. */
794796
if (!pipe&& !superuser())
@@ -811,7 +813,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
811813
{
812814
TupleDesctupDesc;
813815
AclModerequired_access= (is_from ?ACL_INSERT :ACL_SELECT);
814-
RangeTblEntry*rte;
815816
List*attnums;
816817
ListCell*cur;
817818

@@ -857,7 +858,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
857858
* If RLS is not enabled for this, then just fall through to the
858859
* normal non-filtering relation handling.
859860
*/
860-
if (check_enable_rls(rte->relid,InvalidOid)==RLS_ENABLED)
861+
if (check_enable_rls(rte->relid,InvalidOid, false)==RLS_ENABLED)
861862
{
862863
SelectStmt*select;
863864
ColumnRef*cr;
@@ -920,6 +921,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
920921

921922
cstate=BeginCopyFrom(rel,stmt->filename,stmt->is_program,
922923
stmt->attlist,stmt->options);
924+
cstate->range_table=list_make1(rte);
923925
*processed=CopyFrom(cstate);/* copy from file to database */
924926
EndCopyFrom(cstate);
925927
}
@@ -928,6 +930,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
928930
cstate=BeginCopyTo(rel,query,queryString,relid,
929931
stmt->filename,stmt->is_program,
930932
stmt->attlist,stmt->options);
933+
cstate->range_table=list_make1(rte);
931934
*processed=DoCopyTo(cstate);/* copy from database to file */
932935
EndCopyTo(cstate);
933936
}
@@ -2277,6 +2280,7 @@ CopyFrom(CopyState cstate)
22772280
estate->es_result_relations=resultRelInfo;
22782281
estate->es_num_result_relations=1;
22792282
estate->es_result_relation_info=resultRelInfo;
2283+
estate->es_range_table=cstate->range_table;
22802284

22812285
/* Set up a tuple slot too */
22822286
myslot=ExecInitExtraTupleSlot(estate);

‎src/backend/commands/createas.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@
3838
#include"miscadmin.h"
3939
#include"parser/parse_clause.h"
4040
#include"rewrite/rewriteHandler.h"
41-
#include"rewrite/rowsecurity.h"
4241
#include"storage/smgr.h"
4342
#include"tcop/tcopprot.h"
4443
#include"utils/builtins.h"
4544
#include"utils/lsyscache.h"
4645
#include"utils/rel.h"
46+
#include"utils/rls.h"
4747
#include"utils/snapmgr.h"
4848

4949

@@ -446,7 +446,7 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
446446
* be enabled here. We don't actually support that currently, so throw
447447
* our own ereport(ERROR) if that happens.
448448
*/
449-
if (check_enable_rls(intoRelationId,InvalidOid)==RLS_ENABLED)
449+
if (check_enable_rls(intoRelationId,InvalidOid, false)==RLS_ENABLED)
450450
ereport(ERROR,
451451
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
452452
(errmsg("policies not yet implemented for this command"))));

‎src/backend/commands/matview.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,13 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
596596
elog(ERROR,"SPI_exec failed: %s",querybuf.data);
597597
if (SPI_processed>0)
598598
{
599+
/*
600+
* Note that this ereport() is returning data to the user. Generally,
601+
* we would want to make sure that the user has been granted access to
602+
* this data. However, REFRESH MAT VIEW is only able to be run by the
603+
* owner of the mat view (or a superuser) and therefore there is no
604+
* need to check for access to data in the mat view.
605+
*/
599606
ereport(ERROR,
600607
(errcode(ERRCODE_CARDINALITY_VIOLATION),
601608
errmsg("new data for \"%s\" contains duplicate rows without any null columns",

‎src/backend/commands/trigger.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ intSessionReplicationRole = SESSION_REPLICATION_ROLE_ORIGIN;
6565
/* How many levels deep into trigger execution are we? */
6666
staticintMyTriggerDepth=0;
6767

68+
/*
69+
* Note that this macro also exists in executor/execMain.c. There does not
70+
* appear to be any good header to put it into, given the structures that
71+
* it uses, so we let them be duplicated. Be sure to update both if one needs
72+
* to be changed, however.
73+
*/
6874
#defineGetModifiedColumns(relinfo,estate) \
6975
(rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->modifiedCols)
7076

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp