Commit 08eb37da authored by Tom Lane's avatar Tom Lane

Fix column privilege checking for cases where parent and child have different

attribute numbering.  Also, a parent whole-row reference should not require
select privilege on child columns that aren't inherited from the parent.
Problem diagnosed by KaiGai Kohei, though this isn't exactly his patch.
parent ff6c93bf
......@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.166 2009/02/25 03:30:37 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.167 2009/03/05 17:30:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -30,6 +30,7 @@
#include "access/heapam.h"
#include "access/sysattr.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
......@@ -95,6 +96,8 @@ static void make_inh_translation_list(Relation oldrelation,
Relation newrelation,
Index newvarno,
List **translated_vars);
static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
List *translated_vars);
static Node *adjust_appendrel_attrs_mutator(Node *node,
AppendRelInfo *context);
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
......@@ -1295,6 +1298,19 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
appinfo->parent_reloid = parentOID;
appinfos = lappend(appinfos, appinfo);
/*
* Translate the column permissions bitmaps to the child's attnums
* (we have to build the translated_vars list before we can do this).
* But if this is the parent table, leave copyObject's result alone.
*/
if (childOID != parentOID)
{
childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
appinfo->translated_vars);
}
/*
* Build a RowMarkClause if parent is marked FOR UPDATE/SHARE.
*/
......@@ -1437,6 +1453,59 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
*translated_vars = vars;
}
/*
* translate_col_privs
* Translate a bitmapset representing per-column privileges from the
* parent rel's attribute numbering to the child's.
*
* The only surprise here is that we don't translate a parent whole-row
* reference into a child whole-row reference. That would mean requiring
* permissions on all child columns, which is overly strict, since the
* query is really only going to reference the inherited columns. Instead
* we set the per-column bits for all inherited columns.
*/
static Bitmapset *
translate_col_privs(const Bitmapset *parent_privs,
List *translated_vars)
{
Bitmapset *child_privs = NULL;
bool whole_row;
int attno;
ListCell *lc;
/* System attributes have the same numbers in all tables */
for (attno = FirstLowInvalidHeapAttributeNumber+1; attno < 0; attno++)
{
if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
parent_privs))
child_privs = bms_add_member(child_privs,
attno - FirstLowInvalidHeapAttributeNumber);
}
/* Check if parent has whole-row reference */
whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
parent_privs);
/* And now translate the regular user attributes, using the vars list */
attno = InvalidAttrNumber;
foreach(lc, translated_vars)
{
Var *var = (Var *) lfirst(lc);
attno++;
if (var == NULL) /* ignore dropped columns */
continue;
Assert(IsA(var, Var));
if (whole_row ||
bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
parent_privs))
child_privs = bms_add_member(child_privs,
var->varattno - FirstLowInvalidHeapAttributeNumber);
}
return child_privs;
}
/*
* adjust_appendrel_attrs
* Copy the specified query or expression and translate Vars referring
......
......@@ -393,6 +393,48 @@ SET SESSION AUTHORIZATION regressuser3;
DELETE FROM atest5 WHERE one = 1; -- fail
ERROR: permission denied for relation atest5
DELETE FROM atest5 WHERE two = 2; -- ok
-- check inheritance cases
SET SESSION AUTHORIZATION regressuser1;
CREATE TABLE atestp1 (f1 int, f2 int) WITH OIDS;
CREATE TABLE atestp2 (fx int, fy int) WITH OIDS;
CREATE TABLE atestc (fz int) INHERITS (atestp1, atestp2);
GRANT SELECT(fx,fy,oid) ON atestp2 TO regressuser2;
GRANT SELECT(fx) ON atestc TO regressuser2;
SET SESSION AUTHORIZATION regressuser2;
SELECT fx FROM atestp2; -- ok
fx
----
(0 rows)
SELECT fy FROM atestp2; -- fail, no privilege on atestc.fy
ERROR: permission denied for relation atestc
SELECT atestp2 FROM atestp2; -- fail, no privilege on atestc.fy
ERROR: permission denied for relation atestc
SELECT oid FROM atestp2; -- fail, no privilege on atestc.oid
ERROR: permission denied for relation atestc
SET SESSION AUTHORIZATION regressuser1;
GRANT SELECT(fy,oid) ON atestc TO regressuser2;
SET SESSION AUTHORIZATION regressuser2;
SELECT fx FROM atestp2; -- still ok
fx
----
(0 rows)
SELECT fy FROM atestp2; -- ok
fy
----
(0 rows)
SELECT atestp2 FROM atestp2; -- ok
atestp2
---------
(0 rows)
SELECT oid FROM atestp2; -- ok
oid
-----
(0 rows)
-- privileges on functions, languages
-- switch to superuser
\c -
......@@ -791,6 +833,9 @@ DROP TABLE atest3;
DROP TABLE atest4;
DROP TABLE atest5;
DROP TABLE atest6;
DROP TABLE atestc;
DROP TABLE atestp1;
DROP TABLE atestp2;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
......
......@@ -267,6 +267,29 @@ SET SESSION AUTHORIZATION regressuser3;
DELETE FROM atest5 WHERE one = 1; -- fail
DELETE FROM atest5 WHERE two = 2; -- ok
-- check inheritance cases
SET SESSION AUTHORIZATION regressuser1;
CREATE TABLE atestp1 (f1 int, f2 int) WITH OIDS;
CREATE TABLE atestp2 (fx int, fy int) WITH OIDS;
CREATE TABLE atestc (fz int) INHERITS (atestp1, atestp2);
GRANT SELECT(fx,fy,oid) ON atestp2 TO regressuser2;
GRANT SELECT(fx) ON atestc TO regressuser2;
SET SESSION AUTHORIZATION regressuser2;
SELECT fx FROM atestp2; -- ok
SELECT fy FROM atestp2; -- fail, no privilege on atestc.fy
SELECT atestp2 FROM atestp2; -- fail, no privilege on atestc.fy
SELECT oid FROM atestp2; -- fail, no privilege on atestc.oid
SET SESSION AUTHORIZATION regressuser1;
GRANT SELECT(fy,oid) ON atestc TO regressuser2;
SET SESSION AUTHORIZATION regressuser2;
SELECT fx FROM atestp2; -- still ok
SELECT fy FROM atestp2; -- ok
SELECT atestp2 FROM atestp2; -- ok
SELECT oid FROM atestp2; -- ok
-- privileges on functions, languages
-- switch to superuser
......@@ -466,6 +489,9 @@ DROP TABLE atest3;
DROP TABLE atest4;
DROP TABLE atest5;
DROP TABLE atest6;
DROP TABLE atestc;
DROP TABLE atestp1;
DROP TABLE atestp2;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment