pgsql-v9.1-reworks-dml-checks.3.patch
application/octect-stream
Filename: pgsql-v9.1-reworks-dml-checks.3.patch
Type: application/octect-stream
Part: 0
Message:
Re: Reworks of DML permission checks
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v9
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 23 | 0 |
| src/backend/executor/execMain.c | 33 | 0 |
| src/backend/utils/adt/ri_triggers.c | 31 | 0 |
| src/include/executor/executor.h | 2 | 0 |
*** a/src/backend/commands/copy.c
--- b/src/backend/commands/copy.c
***************
*** 21,26 ****
--- 21,27 ----
#include <arpa/inet.h>
#include "access/heapam.h"
+ #include "access/sysattr.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
***************
*** 726,733 **** DoCopy(const CopyStmt *stmt, const char *queryString)
bool force_quote_all = false;
bool format_specified = false;
AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT);
- AclMode relPerms;
- AclMode remainingPerms;
ListCell *option;
TupleDesc tupDesc;
int num_phys_attrs;
--- 727,732 ----
***************
*** 988,993 **** DoCopy(const CopyStmt *stmt, const char *queryString)
--- 987,996 ----
if (stmt->relation)
{
+ RangeTblEntry *rte;
+ List *attnums;
+ ListCell *cur;
+
Assert(!stmt->query);
cstate->queryDesc = NULL;
***************
*** 997,1025 **** DoCopy(const CopyStmt *stmt, const char *queryString)
tupDesc = RelationGetDescr(cstate->rel);
! /* Check relation permissions. */
! relPerms = pg_class_aclmask(RelationGetRelid(cstate->rel), GetUserId(),
! required_access, ACLMASK_ALL);
! remainingPerms = required_access & ~relPerms;
! if (remainingPerms != 0)
! {
! /* We don't have table permissions, check per-column permissions */
! List *attnums;
! ListCell *cur;
! attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
! foreach(cur, attnums)
! {
! int attnum = lfirst_int(cur);
! if (pg_attribute_aclcheck(RelationGetRelid(cstate->rel),
! attnum,
! GetUserId(),
! remainingPerms) != ACLCHECK_OK)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! RelationGetRelationName(cstate->rel));
! }
}
/* check read-only transaction */
if (XactReadOnly && is_from && !cstate->rel->rd_islocaltemp)
--- 1000,1026 ----
tupDesc = RelationGetDescr(cstate->rel);
! /*
! * check relation permissions.
! * we built an RTE with the relation and columns to be accessed
! * to check for necessary privileges in the common way.
! */
! rte = makeNode(RangeTblEntry);
! rte->rtekind = RTE_RELATION;
! rte->relid = RelationGetRelid(cstate->rel);
! rte->requiredPerms = required_access;
! attnums = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
! foreach (cur, attnums)
! {
! int attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber;
! if (is_from)
! rte->modifiedCols = bms_add_member(rte->modifiedCols, attno);
! else
! rte->selectedCols = bms_add_member(rte->selectedCols, attno);
}
+ ExecCheckRTPerms(list_make1(rte), true);
/* check read-only transaction */
if (XactReadOnly && is_from && !cstate->rel->rd_islocaltemp)
*** a/src/backend/executor/execMain.c
--- b/src/backend/executor/execMain.c
***************
*** 75,82 **** static void ExecutePlan(EState *estate, PlanState *planstate,
long numberTuples,
ScanDirection direction,
DestReceiver *dest);
! static void ExecCheckRTPerms(List *rangeTable);
! static void ExecCheckRTEPerms(RangeTblEntry *rte);
static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
Plan *planTree);
--- 75,81 ----
long numberTuples,
ScanDirection direction,
DestReceiver *dest);
! static bool ExecCheckRTEPerms(RangeTblEntry *rte);
static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate,
Plan *planTree);
***************
*** 410,434 **** ExecutorRewind(QueryDesc *queryDesc)
* ExecCheckRTPerms
* Check access permissions for all relations listed in a range table.
*/
! static void
! ExecCheckRTPerms(List *rangeTable)
{
ListCell *l;
foreach(l, rangeTable)
{
! ExecCheckRTEPerms((RangeTblEntry *) lfirst(l));
}
if (ExecutorCheckPerms_hook)
! (*ExecutorCheckPerms_hook)(rangeTable);
}
/*
* ExecCheckRTEPerms
* Check access permissions for a single RTE.
*/
! static void
ExecCheckRTEPerms(RangeTblEntry *rte)
{
AclMode requiredPerms;
--- 409,446 ----
* ExecCheckRTPerms
* Check access permissions for all relations listed in a range table.
*/
! bool
! ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation)
{
ListCell *l;
+ bool result = true;
foreach(l, rangeTable)
{
! RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
!
! result = ExecCheckRTEPerms(rte);
! if (!result)
! {
! Assert(rte->rtekind == RTE_RELATION);
! if (ereport_on_violation)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(rte->relid));
! return false;
! }
}
if (ExecutorCheckPerms_hook)
! result = (*ExecutorCheckPerms_hook)(rangeTable,
! ereport_on_violation);
! return result;
}
/*
* ExecCheckRTEPerms
* Check access permissions for a single RTE.
*/
! static bool
ExecCheckRTEPerms(RangeTblEntry *rte)
{
AclMode requiredPerms;
***************
*** 445,458 **** ExecCheckRTEPerms(RangeTblEntry *rte)
* Join, subquery, and special RTEs need no checks.
*/
if (rte->rtekind != RTE_RELATION)
! return;
/*
* No work if requiredPerms is empty.
*/
requiredPerms = rte->requiredPerms;
if (requiredPerms == 0)
! return;
relOid = rte->relid;
--- 457,470 ----
* Join, subquery, and special RTEs need no checks.
*/
if (rte->rtekind != RTE_RELATION)
! return true;
/*
* No work if requiredPerms is empty.
*/
requiredPerms = rte->requiredPerms;
if (requiredPerms == 0)
! return true;
relOid = rte->relid;
***************
*** 480,487 **** ExecCheckRTEPerms(RangeTblEntry *rte)
* we can fail straight away.
*/
if (remainingPerms & ~(ACL_SELECT | ACL_INSERT | ACL_UPDATE))
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(relOid));
/*
* Check to see if we have the needed privileges at column level.
--- 492,498 ----
* we can fail straight away.
*/
if (remainingPerms & ~(ACL_SELECT | ACL_INSERT | ACL_UPDATE))
! return false;
/*
* Check to see if we have the needed privileges at column level.
***************
*** 501,508 **** ExecCheckRTEPerms(RangeTblEntry *rte)
{
if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ANY) != ACLCHECK_OK)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(relOid));
}
tmpset = bms_copy(rte->selectedCols);
--- 512,518 ----
{
if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ANY) != ACLCHECK_OK)
! return false;
}
tmpset = bms_copy(rte->selectedCols);
***************
*** 515,529 **** ExecCheckRTEPerms(RangeTblEntry *rte)
/* Whole-row reference, must have priv on all cols */
if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ALL) != ACLCHECK_OK)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(relOid));
}
else
{
! if (pg_attribute_aclcheck(relOid, col, userid, ACL_SELECT)
! != ACLCHECK_OK)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(relOid));
}
}
bms_free(tmpset);
--- 525,537 ----
/* Whole-row reference, must have priv on all cols */
if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ALL) != ACLCHECK_OK)
! return false;
}
else
{
! if (pg_attribute_aclcheck(relOid, col, userid,
! ACL_SELECT) != ACLCHECK_OK)
! return false;
}
}
bms_free(tmpset);
***************
*** 546,553 **** ExecCheckRTEPerms(RangeTblEntry *rte)
{
if (pg_attribute_aclcheck_all(relOid, userid, remainingPerms,
ACLMASK_ANY) != ACLCHECK_OK)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(relOid));
}
tmpset = bms_copy(rte->modifiedCols);
--- 554,560 ----
{
if (pg_attribute_aclcheck_all(relOid, userid, remainingPerms,
ACLMASK_ANY) != ACLCHECK_OK)
! return false;
}
tmpset = bms_copy(rte->modifiedCols);
***************
*** 562,576 **** ExecCheckRTEPerms(RangeTblEntry *rte)
}
else
{
! if (pg_attribute_aclcheck(relOid, col, userid, remainingPerms)
! != ACLCHECK_OK)
! aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! get_rel_name(relOid));
}
}
bms_free(tmpset);
}
}
}
/*
--- 569,583 ----
}
else
{
! if (pg_attribute_aclcheck(relOid, col, userid,
! remainingPerms) != ACLCHECK_OK)
! return false;
}
}
bms_free(tmpset);
}
}
+ return true;
}
/*
***************
*** 636,642 **** InitPlan(QueryDesc *queryDesc, int eflags)
/*
* Do permissions checks
*/
! ExecCheckRTPerms(rangeTable);
/*
* initialize the node's execution state
--- 643,649 ----
/*
* Do permissions checks
*/
! ExecCheckRTPerms(rangeTable, true);
/*
* initialize the node's execution state
*** a/src/backend/utils/adt/ri_triggers.c
--- b/src/backend/utils/adt/ri_triggers.c
***************
*** 31,40 ****
--- 31,42 ----
#include "postgres.h"
#include "access/xact.h"
+ #include "access/sysattr.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
+ #include "executor/executor.h"
#include "executor/spi.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
***************
*** 2624,2629 **** RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
--- 2626,2633 ----
char fkrelname[MAX_QUOTED_REL_NAME_LEN];
char pkattname[MAX_QUOTED_NAME_LEN + 3];
char fkattname[MAX_QUOTED_NAME_LEN + 3];
+ RangeTblEntry *pkrte;
+ RangeTblEntry *fkrte;
const char *sep;
int i;
int old_work_mem;
***************
*** 2632,2649 **** RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
SPIPlanPtr qplan;
/*
* Check to make sure current user has enough permissions to do the test
* query. (If not, caller can fall back to the trigger method, which
* works because it changes user IDs on the fly.)
*
* XXX are there any other show-stopper conditions to check?
*/
! if (pg_class_aclcheck(RelationGetRelid(fk_rel), GetUserId(), ACL_SELECT) != ACLCHECK_OK)
! return false;
! if (pg_class_aclcheck(RelationGetRelid(pk_rel), GetUserId(), ACL_SELECT) != ACLCHECK_OK)
! return false;
! ri_FetchConstraintInfo(&riinfo, trigger, fk_rel, false);
/*----------
* The query string built is:
--- 2636,2675 ----
SPIPlanPtr qplan;
/*
+ * Set up RI_ConstraintInfo
+ */
+ ri_FetchConstraintInfo(&riinfo, trigger, fk_rel, false);
+
+ /*
* Check to make sure current user has enough permissions to do the test
* query. (If not, caller can fall back to the trigger method, which
* works because it changes user IDs on the fly.)
*
* XXX are there any other show-stopper conditions to check?
*/
! pkrte = makeNode(RangeTblEntry);
! pkrte->rtekind = RTE_RELATION;
! pkrte->relid = RelationGetRelid(pk_rel);
! pkrte->requiredPerms = ACL_SELECT;
! fkrte = makeNode(RangeTblEntry);
! fkrte->rtekind = RTE_RELATION;
! fkrte->relid = RelationGetRelid(fk_rel);
! fkrte->requiredPerms = ACL_SELECT;
!
! for (i = 0; i < riinfo.nkeys; i++)
! {
! int attno;
!
! attno = riinfo.pk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
! pkrte->selectedCols = bms_add_member(pkrte->selectedCols, attno);
!
! attno = riinfo.fk_attnums[i] - FirstLowInvalidHeapAttributeNumber;
! fkrte->selectedCols = bms_add_member(fkrte->selectedCols, attno);
! }
!
! if (!ExecCheckRTPerms(list_make2(fkrte, pkrte), false))
! return false;
/*----------
* The query string built is:
*** a/src/include/executor/executor.h
--- b/src/include/executor/executor.h
***************
*** 75,81 **** typedef void (*ExecutorEnd_hook_type) (QueryDesc *queryDesc);
extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook;
/* Hook for plugins to get control in ExecCheckRTPerms() */
! typedef void (*ExecutorCheckPerms_hook_type) (List *);
extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
--- 75,81 ----
extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook;
/* Hook for plugins to get control in ExecCheckRTPerms() */
! typedef bool (*ExecutorCheckPerms_hook_type) (List *, bool);
extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook;
***************
*** 161,166 **** extern void standard_ExecutorRun(QueryDesc *queryDesc,
--- 161,167 ----
extern void ExecutorEnd(QueryDesc *queryDesc);
extern void standard_ExecutorEnd(QueryDesc *queryDesc);
extern void ExecutorRewind(QueryDesc *queryDesc);
+ extern bool ExecCheckRTPerms(List *rangeTable, bool ereport_on_violation);
extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
Relation resultRelationDesc,
Index resultRelationIndex,