Re: [HACKERS] more RLS oversights

2015-11-23 Thread Stephen Frost
Noah,

* Noah Misch (n...@leadboat.com) wrote:
> On Tue, Jul 28, 2015 at 04:04:29PM -0700, Joe Conway wrote:
> > Pushed to HEAD and 9.5
> 
> I reviewed this commit, f781a0f "Create a pg_shdepend entry for each role in
> TO clause of policies."  

Thanks for the review!

> This commit rendered the
> http://www.postgresql.org/docs/devel/static/role-removal.html procedure[1]
> incomplete.  Before dropping a role, one must additionally drop each policy
> mentioning the role in pg_policy.polroles:
> 
> begin;
> create role alice;
> create table t (c int);
> grant select on table t to alice;
> create policy p0 on t to alice using (true);
> reassign owned by alice to current_user;
> drop owned by alice;
> drop role alice;
> rollback;
> 
> shdepDropOwned() ignores SHARED_DEPENDENCY_POLICY entries.  Should it instead
> remove the role from polroles, dropping the policy if that would empty
> polroles?  (Which should change, the documented role-removal procedure or the
> DROP OWNED treatment of policies?)

I would expect the DROP OWNED treatment of policies to be similar to the
DROP OWNED treatment of GRANTs.  I'm certainly of the opinion that this
is a bug which should be addressed.  As an FYI, Joe's laptop recently
got stolen and he's working to get back up to speed as quickly as he
can.  I've just put his new key into place on gitmaster (along with a
few other pginfra-related bits), but there's obviously a lot more for
him to be completely up and working again.

> Independently,
> http://www.postgresql.org/docs/devel/static/sql-drop-owned.html deserves an
> update since it discusses every other object type having role dependencies.

Agreed.

Thanks!

Stephen


signature.asc
Description: Digital signature


Re: [HACKERS] more RLS oversights

2015-11-22 Thread Noah Misch
On Tue, Jul 28, 2015 at 04:04:29PM -0700, Joe Conway wrote:
> On 07/27/2015 05:34 PM, Joe Conway wrote:
> > On 07/27/2015 01:13 PM, Alvaro Herrera wrote:
> >> Hmm, these are not ACL objects, so conceptually it seems cleaner
> >> to use a different symbol for this.  I think the catalog state
> >> and the error messages would be a bit confusing otherwise.
> > 
> > Ok -- done

> Pushed to HEAD and 9.5

I reviewed this commit, f781a0f "Create a pg_shdepend entry for each role in
TO clause of policies."  This commit rendered the
http://www.postgresql.org/docs/devel/static/role-removal.html procedure[1]
incomplete.  Before dropping a role, one must additionally drop each policy
mentioning the role in pg_policy.polroles:

begin;
create role alice;
create table t (c int);
grant select on table t to alice;
create policy p0 on t to alice using (true);
reassign owned by alice to current_user;
drop owned by alice;
drop role alice;
rollback;

shdepDropOwned() ignores SHARED_DEPENDENCY_POLICY entries.  Should it instead
remove the role from polroles, dropping the policy if that would empty
polroles?  (Which should change, the documented role-removal procedure or the
DROP OWNED treatment of policies?)  Independently,
http://www.postgresql.org/docs/devel/static/sql-drop-owned.html deserves an
update since it discusses every other object type having role dependencies.

Thanks,
nm

[1] That page did not exist until 2015-10-07 (commit 1ea0c73), after the
commit I'm reviewing here.


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-09-10 Thread Stephen Frost
Noah,

First off, thanks again for your review and comments on RLS.  Hopefully
this addresses the last remaining open item from that review.

* Noah Misch (n...@leadboat.com) wrote:
> On Wed, Feb 25, 2015 at 11:37:24PM -0500, Stephen Frost wrote:
> > +  
> > +   Referential integrity checks, such as unique or primary key constraints
> > +   and foreign key references, will bypass row security to ensure that
> > +   data integrity is maintained.  Care must be taken when developing
> > +   schemas and row level policies to avoid a "covert channel" leak of
> > +   information through these referential integrity checks.
> ...
> > +   /*
> > +* Row-level security should be disabled in the case where a foreign-key
> > +* relation is queried to check existence of tuples that references the
> > +* primary-key being modified.
> > +*/
> > +   temp_sec_context = save_sec_context | SECURITY_LOCAL_USERID_CHANGE;
> > +   if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK
> > +   || qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK_FROM_PK
> > +   || qkey->constr_queryno == RI_PLAN_RESTRICT_DEL_CHECKREF
> > +   || qkey->constr_queryno == RI_PLAN_RESTRICT_UPD_CHECKREF)
> > +   temp_sec_context |= SECURITY_ROW_LEVEL_DISABLED;
> 
> (5) This code does not use SECURITY_ROW_LEVEL_DISABLED for foreign keys with
> CASCADE, SET NULL or SET DEFAULT actions.  The associated documentation says
> nothing about this presumably-important distinction.

I believe the original intent was to only include the queries which were
against the primary table, but reviewing what ends up happening, that
clearly doesn't actually make sense.  As you note below, this is only
to address the 'row_security = force' mode, which I suspect is why it
wasn't picked up in earlier testing.

> Is SECURITY_ROW_LEVEL_DISABLED mode even needed?  We switch users to the owner
> of the FROM-clause table before running an RI query.  That means use of this
> mode can only matter under row_security=force, right?  I would rest easier if
> this mode went away, because it is a security landmine.  If user code managed
> to run in this mode, it would bypass every policy in the database.  (I find no
> such vulnerability today, because we use the mode only for parse analysis of
> ri_triggers.c queries.)

You're right, the reason for it to exist was to address the
'row_security = force' case.  I spent a bit of time considering that and
have come up with the attached for consideration (which needs additional
work before being committed, but should get the idea across clearly).

This removes the notion of SECURITY_ROW_LEVEL_DISABLED entirely and
instead ignores 'row_security = force' if InLocalUserIdChange() is true.
Further, this changes row_security to have GUC_NOT_WHILE_SEC_REST set.
I didn't set GUC_NO_RESET_ALL for it though as the default is for
row_security to be 'on'.

The biggest drawback that I can see to this is that users won't be able
to set the row_security GUC inside of a security definer function.  I
can imagine use-cases where someone might want to change it in a
security definer function but it doesn't seem like they're valuable
enough to counter your argument (which I agree with) that
SECURITY_ROW_LEVEL_DISABLED is a security landmine.

Another approach which I considered was to add a new 'RLS_IGNORE_FORCE'
flag, which would, again, ignore 'row_security=force' when set (meaning
owners would bypass RLS regardless of the actual row_security setting).
I didn't like adding that to sec_context though and it wasn't clear
where a good place would be.  Further, it seems like it'd be nice to
have a generic flag that says "we're running an internal referential
integrity operation, don't get in the way", though that could also be a
risky flag to have.  Such an approach would allow us to differentiate RI
queries from operations run under a security definer function though.

Thoughts?

Thanks!

Stephen
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
new file mode 100644
index 61edde9..647ea77
*** a/src/backend/utils/adt/ri_triggers.c
--- b/src/backend/utils/adt/ri_triggers.c
*** ri_PlanCheck(const char *querystr, int n
*** 2984,3001 
  	/* Switch to proper UID to perform check as */
  	GetUserIdAndSecContext(&save_userid, &save_sec_context);
  
- 	/*
- 	 * Row-level security should be disabled in the case where a foreign-key
- 	 * relation is queried to check existence of tuples that references the
- 	 * primary-key being modified.
- 	 */
  	temp_sec_context = save_sec_context | SECURITY_LOCAL_USERID_CHANGE;
- 	if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK
- 		|| qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK_FROM_PK
- 		|| qkey->constr_queryno == RI_PLAN_RESTRICT_DEL_CHECKREF
- 		|| qkey->constr_queryno == RI_PLAN_RESTRICT_UPD_CHECKREF)
- 		temp_sec_context |= SECURITY_ROW_LEVEL_DISABLED;
- 
  
  	SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
  		   t

Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 02:56 PM, Joe Conway wrote:
> On 07/29/2015 02:04 PM, Alvaro Herrera wrote:
>>> Why not just "in policy expressions"?  There's no third kind that does
>>> allow these.
>>
>> WFM
> 
> Sold! Will do it that way.

Committed/pushed to HEAD and 9.5.

Joe




-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 02:04 PM, Alvaro Herrera wrote:
>> Why not just "in policy expressions"?  There's no third kind that does
>> allow these.
> 
> WFM

Sold! Will do it that way.

Joe



-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Alvaro Herrera
Robert Haas wrote:
> On Wed, Jul 29, 2015 at 4:57 PM, Joe Conway  
> wrote:

> > The equivalent message for functions is:
> >   ".. are not allowed in functions in FROM"
> >
> > So how does this sound:
> > "... are not allowed in policies in USING and WITH CHECK expressions"
> > or perhaps more simply:
> > "... are not allowed in policies in USING and WITH CHECK"
> 
> Awkward.  The "in policies in" phrasing is just hard to read.

Yeah.  Besides, it's not really the same thing.

> Why not just "in policy expressions"?  There's no third kind that does
> allow these.

WFM

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Robert Haas
On Wed, Jul 29, 2015 at 4:57 PM, Joe Conway  wrote:
> On 07/29/2015 01:26 PM, Robert Haas wrote:
>> On Wed, Jul 29, 2015 at 3:58 PM, Alvaro Herrera
>>  wrote:
>>> I think this reads a bit funny.  What's a "POLICY USING" clause?  I
>>> expect that translators will treat the two words POLICY USING as a
>>> single token, and the result is not going to make any sense.
>>>
>>> Maybe "in a policy's USING and WITH CHECK expressions", or perhaps "in
>>> policies's USING and WITH CHECK exprs", not sure.
>>
>> Yeah, I don't see why we would capitalize POLICY there.
>
> The equivalent message for functions is:
>   ".. are not allowed in functions in FROM"
>
> So how does this sound:
> "... are not allowed in policies in USING and WITH CHECK expressions"
> or perhaps more simply:
> "... are not allowed in policies in USING and WITH CHECK"

Awkward.  The "in policies in" phrasing is just hard to read.  Why not
just "in policy expressions"?  There's no third kind that does allow
these.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 01:26 PM, Robert Haas wrote:
> On Wed, Jul 29, 2015 at 3:58 PM, Alvaro Herrera
>  wrote:
>> I think this reads a bit funny.  What's a "POLICY USING" clause?  I
>> expect that translators will treat the two words POLICY USING as a
>> single token, and the result is not going to make any sense.
>>
>> Maybe "in a policy's USING and WITH CHECK expressions", or perhaps "in
>> policies's USING and WITH CHECK exprs", not sure.
> 
> Yeah, I don't see why we would capitalize POLICY there.

The equivalent message for functions is:
  ".. are not allowed in functions in FROM"

So how does this sound:
"... are not allowed in policies in USING and WITH CHECK expressions"
or perhaps more simply:
"... are not allowed in policies in USING and WITH CHECK"

Joe



-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Robert Haas
On Wed, Jul 29, 2015 at 3:58 PM, Alvaro Herrera
 wrote:
> I think this reads a bit funny.  What's a "POLICY USING" clause?  I
> expect that translators will treat the two words POLICY USING as a
> single token, and the result is not going to make any sense.
>
> Maybe "in a policy's USING and WITH CHECK expressions", or perhaps "in
> policies's USING and WITH CHECK exprs", not sure.

Yeah, I don't see why we would capitalize POLICY there.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Alvaro Herrera
Joe Conway wrote:
> On 07/29/2015 02:41 AM, Dean Rasheed wrote:
> > I don't think there is any point in adding the new function
> > transformPolicyClause(), which is identical to transformWhereClause().
> > You can just use transformWhereClause() with EXPR_KIND_POLICY. It's
> > already used for lots of other expression kinds.
> 
> Ok -- I went back to using transformWhereClause. I'd still prefer to
> change the name -- more than half the uses of the function are for other
> than EXPR_KIND_WHERE -- but I don't feel that strongly about it.

Currently the comment about it says "for WHERE and allied", maybe this
should be a bit more explicit.  I think it was originally for things
like WHERE and HAVING, and usage slowly extended beyond that.  Does it
make sense to consider the USING clause in CREATE/ALTER POLICY as an
"allied" clause of WHERE?  I don't particularly think so.  I'm just
talking about a small rewording of the comment.

> > I think that check_agglevels_and_constraints() and
> > transformWindowFuncCall() could be made to emit more targeted error
> > messages for EXPR_KIND_POLICY, for example "aggregate functions are
> > not allowed in policy USING and WITH CHECK expressions".
>
> done

> + case EXPR_KIND_POLICY:
> + if (isAgg)
> + err = _("aggregate functions are not allowed in 
> POLICY USING and WITH CHECK expressions");
> + else
> + err = _("grouping operations are not allowed in 
> POLICY USING and WITH CHECK expressions");

I think this reads a bit funny.  What's a "POLICY USING" clause?  I
expect that translators will treat the two words POLICY USING as a
single token, and the result is not going to make any sense.

Maybe "in a policy's USING and WITH CHECK expressions", or perhaps "in
policies's USING and WITH CHECK exprs", not sure.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Dean Rasheed
On 29 July 2015 at 20:36, Joe Conway  wrote:
> On 07/29/2015 02:41 AM, Dean Rasheed wrote:
>> I don't think there is any point in adding the new function
>> transformPolicyClause(), which is identical to transformWhereClause().
>> You can just use transformWhereClause() with EXPR_KIND_POLICY. It's
>> already used for lots of other expression kinds.
>
>
> Ok -- I went back to using transformWhereClause. I'd still prefer to
> change the name -- more than half the uses of the function are for other
> than EXPR_KIND_WHERE -- but I don't feel that strongly about it.
>
>
>> There are a couple of places in test_rls_hooks.c that also need updating.
>
> done
>
>> I think that check_agglevels_and_constraints() and
>> transformWindowFuncCall() could be made to emit more targeted error
>> messages for EXPR_KIND_POLICY, for example "aggregate functions are
>> not allowed in policy USING and WITH CHECK expressions".
>
> done
>
> Unless there are other comments/objections, will commit this later today.
>

In the final error s/aggregate/window/. Other than that it looks good to me.

Regards,
Dean


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 02:41 AM, Dean Rasheed wrote:
> I don't think there is any point in adding the new function
> transformPolicyClause(), which is identical to transformWhereClause().
> You can just use transformWhereClause() with EXPR_KIND_POLICY. It's
> already used for lots of other expression kinds.


Ok -- I went back to using transformWhereClause. I'd still prefer to
change the name -- more than half the uses of the function are for other
than EXPR_KIND_WHERE -- but I don't feel that strongly about it.


> There are a couple of places in test_rls_hooks.c that also need updating.

done

> I think that check_agglevels_and_constraints() and
> transformWindowFuncCall() could be made to emit more targeted error
> messages for EXPR_KIND_POLICY, for example "aggregate functions are
> not allowed in policy USING and WITH CHECK expressions".

done

Unless there are other comments/objections, will commit this later today.

Joe

diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index d8b4390..bcf4a8f 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
*** CreatePolicy(CreatePolicyStmt *stmt)
*** 534,545 
  
  	qual = transformWhereClause(qual_pstate,
  copyObject(stmt->qual),
! EXPR_KIND_WHERE,
  "POLICY");
  
  	with_check_qual = transformWhereClause(with_check_pstate,
  		   copyObject(stmt->with_check),
! 		   EXPR_KIND_WHERE,
  		   "POLICY");
  
  	/* Fix up collation information */
--- 534,545 
  
  	qual = transformWhereClause(qual_pstate,
  copyObject(stmt->qual),
! EXPR_KIND_POLICY,
  "POLICY");
  
  	with_check_qual = transformWhereClause(with_check_pstate,
  		   copyObject(stmt->with_check),
! 		   EXPR_KIND_POLICY,
  		   "POLICY");
  
  	/* Fix up collation information */
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 707,713 
  		addRTEtoQuery(qual_pstate, rte, false, true, true);
  
  		qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
! 	EXPR_KIND_WHERE,
  	"POLICY");
  
  		/* Fix up collation information */
--- 707,713 
  		addRTEtoQuery(qual_pstate, rte, false, true, true);
  
  		qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
! 	EXPR_KIND_POLICY,
  	"POLICY");
  
  		/* Fix up collation information */
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 730,736 
  
  		with_check_qual = transformWhereClause(with_check_pstate,
  			   copyObject(stmt->with_check),
! 			   EXPR_KIND_WHERE,
  			   "POLICY");
  
  		/* Fix up collation information */
--- 730,736 
  
  		with_check_qual = transformWhereClause(with_check_pstate,
  			   copyObject(stmt->with_check),
! 			   EXPR_KIND_POLICY,
  			   "POLICY");
  
  		/* Fix up collation information */
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 478d8ca..e33adf5 100644
*** a/src/backend/parser/parse_agg.c
--- b/src/backend/parser/parse_agg.c
*** check_agglevels_and_constraints(ParseSta
*** 373,378 
--- 373,385 
  		case EXPR_KIND_WHERE:
  			errkind = true;
  			break;
+ 		case EXPR_KIND_POLICY:
+ 			if (isAgg)
+ err = _("aggregate functions are not allowed in POLICY USING and WITH CHECK expressions");
+ 			else
+ err = _("grouping operations are not allowed in POLICY USING and WITH CHECK expressions");
+ 
+ 			break;
  		case EXPR_KIND_HAVING:
  			/* okay */
  			break;
*** transformWindowFuncCall(ParseState *psta
*** 770,775 
--- 777,785 
  		case EXPR_KIND_WHERE:
  			errkind = true;
  			break;
+ 		case EXPR_KIND_POLICY:
+ 			err = _("aggregate functions are not allowed in POLICY USING and WITH CHECK expressions");
+ 			break;
  		case EXPR_KIND_HAVING:
  			errkind = true;
  			break;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0ff46dd..fa77ef1 100644
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*** transformSubLink(ParseState *pstate, Sub
*** 1672,1677 
--- 1672,1678 
  		case EXPR_KIND_FROM_SUBSELECT:
  		case EXPR_KIND_FROM_FUNCTION:
  		case EXPR_KIND_WHERE:
+ 		case EXPR_KIND_POLICY:
  		case EXPR_KIND_HAVING:
  		case EXPR_KIND_FILTER:
  		case EXPR_KIND_WINDOW_PARTITION:
*** ParseExprKindName(ParseExprKind exprKind
*** 3173,3178 
--- 3174,3181 
  			return "function in FROM";
  		case EXPR_KIND_WHERE:
  			return "WHERE";
+ 		case EXPR_KIND_POLICY:
+ 			return "POLICY";
  		case EXPR_KIND_HAVING:
  			return "HAVING";
  		case EXPR_KIND_FILTER:
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 7ecaffc..5249945 100644
*** a/src/include/parser/parse_node.h
--- b/src/include/parser/parse_node.h
*** typedef enum ParseExprKind
*** 63,69 
  	EXPR_KIND_INDEX_PREDICATE,	/* index predicate */
  	EXPR_

Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 08:46 AM, Joe Conway wrote:
> On 07/29/2015 01:01 AM, Dean Rasheed wrote:
>> The CreatePolicy() and AlterPolicy() changes look OK to me, but the
>> RemovePolicyById() change looks to be unnecessary ---
>> RemovePolicyById() is called only from doDeletion(), which in turned
>> is called only from deleteOneObject(), which already invokes the drop
>> hooks. So ISTM that RemovePolicyById() doesn't need to do anything,
>> right?
> 
> Seems correct. Will remove that change and commit it that way.

Pushed to HEAD and 9.5.

Joe




-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Dean Rasheed
On 29 July 2015 at 16:52, Joe Conway  wrote:
> On 07/29/2015 02:41 AM, Dean Rasheed wrote:
>> I don't think there is any point in adding the new function
>> transformPolicyClause(), which is identical to transformWhereClause().
>> You can just use transformWhereClause() with EXPR_KIND_POLICY. It's
>> already used for lots of other expression kinds.
>
> Yeah, I was debating that. Although I do think the name
> transformWhereClause() is unfortunate. Maybe it ought to be renamed
> transformBooleanExpr() or something similar?
>

I expect it's probably being used by other people's code though, so
renaming it might cause pain for quite a few people.

Regards,
Dean


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 02:41 AM, Dean Rasheed wrote:
> I don't think there is any point in adding the new function
> transformPolicyClause(), which is identical to transformWhereClause().
> You can just use transformWhereClause() with EXPR_KIND_POLICY. It's
> already used for lots of other expression kinds.

Yeah, I was debating that. Although I do think the name
transformWhereClause() is unfortunate. Maybe it ought to be renamed
transformBooleanExpr() or something similar?

> There are a couple of places in test_rls_hooks.c that also need updating.

Right -- thanks

> I think that check_agglevels_and_constraints() and
> transformWindowFuncCall() could be made to emit more targeted error
> messages for EXPR_KIND_POLICY, for example "aggregate functions are
> not allowed in policy USING and WITH CHECK expressions".

ok

Thanks for the review.

Joe




-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Joe Conway
On 07/29/2015 01:01 AM, Dean Rasheed wrote:
> The CreatePolicy() and AlterPolicy() changes look OK to me, but the
> RemovePolicyById() change looks to be unnecessary ---
> RemovePolicyById() is called only from doDeletion(), which in turned
> is called only from deleteOneObject(), which already invokes the drop
> hooks. So ISTM that RemovePolicyById() doesn't need to do anything,
> right?

Seems correct. Will remove that change and commit it that way.

Joe



-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Dean Rasheed
On 29 July 2015 at 05:02, Joe Conway  wrote:
> On 07/03/2015 10:03 AM, Noah Misch wrote:
>> (7) Using an aggregate function in a policy predicate elicits an inapposite
>> error message due to use of EXPR_KIND_WHERE for parse analysis.  Need a new
>> ParseExprKind.  Test case:
>
> Patch attached. Comments?
>

I don't think there is any point in adding the new function
transformPolicyClause(), which is identical to transformWhereClause().
You can just use transformWhereClause() with EXPR_KIND_POLICY. It's
already used for lots of other expression kinds.

There are a couple of places in test_rls_hooks.c that also need updating.

I think that check_agglevels_and_constraints() and
transformWindowFuncCall() could be made to emit more targeted error
messages for EXPR_KIND_POLICY, for example "aggregate functions are
not allowed in policy USING and WITH CHECK expressions".

Regards,
Dean


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-29 Thread Dean Rasheed
On 29 July 2015 at 02:36, Joe Conway  wrote:
> On 07/03/2015 10:03 AM, Noah Misch wrote:
>> (6) AlterPolicy() calls InvokeObjectPostAlterHook(PolicyRelationId, ...), but
>> CreatePolicy() and DropPolicy() lack their respective hook invocations.
>
> Patch attached. Actually AlterPolicy() was also missing its hook -- the
> existing InvokeObjectPostAlterHook() was only in rename_policy().
>
> I'm not 100% sure about the hook placement -- would appreciate if
> someone could confirm I got it correct.
>

The CreatePolicy() and AlterPolicy() changes look OK to me, but the
RemovePolicyById() change looks to be unnecessary ---
RemovePolicyById() is called only from doDeletion(), which in turned
is called only from deleteOneObject(), which already invokes the drop
hooks. So ISTM that RemovePolicyById() doesn't need to do anything,
right?

Regards,
Dean


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-28 Thread Joe Conway
On 07/03/2015 10:03 AM, Noah Misch wrote:
> (7) Using an aggregate function in a policy predicate elicits an inapposite
> error message due to use of EXPR_KIND_WHERE for parse analysis.  Need a new
> ParseExprKind.  Test case:

Patch attached. Comments?

Joe


diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 4642d7c..d8ef496 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
*** CreatePolicy(CreatePolicyStmt *stmt)
*** 532,545 
  		NULL, false, false);
  	addRTEtoQuery(with_check_pstate, rte, false, true, true);
  
! 	qual = transformWhereClause(qual_pstate,
  copyObject(stmt->qual),
! EXPR_KIND_WHERE,
  "POLICY");
  
! 	with_check_qual = transformWhereClause(with_check_pstate,
  		   copyObject(stmt->with_check),
! 		   EXPR_KIND_WHERE,
  		   "POLICY");
  
  	/* Fix up collation information */
--- 532,545 
  		NULL, false, false);
  	addRTEtoQuery(with_check_pstate, rte, false, true, true);
  
! 	qual = transformPolicyClause(qual_pstate,
  copyObject(stmt->qual),
! EXPR_KIND_POLICY,
  "POLICY");
  
! 	with_check_qual = transformPolicyClause(with_check_pstate,
  		   copyObject(stmt->with_check),
! 		   EXPR_KIND_POLICY,
  		   "POLICY");
  
  	/* Fix up collation information */
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 704,711 
  
  		addRTEtoQuery(qual_pstate, rte, false, true, true);
  
! 		qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
! 	EXPR_KIND_WHERE,
  	"POLICY");
  
  		/* Fix up collation information */
--- 704,711 
  
  		addRTEtoQuery(qual_pstate, rte, false, true, true);
  
! 		qual = transformPolicyClause(qual_pstate, copyObject(stmt->qual),
! 	EXPR_KIND_POLICY,
  	"POLICY");
  
  		/* Fix up collation information */
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 726,734 
  
  		addRTEtoQuery(with_check_pstate, rte, false, true, true);
  
! 		with_check_qual = transformWhereClause(with_check_pstate,
  			   copyObject(stmt->with_check),
! 			   EXPR_KIND_WHERE,
  			   "POLICY");
  
  		/* Fix up collation information */
--- 726,734 
  
  		addRTEtoQuery(with_check_pstate, rte, false, true, true);
  
! 		with_check_qual = transformPolicyClause(with_check_pstate,
  			   copyObject(stmt->with_check),
! 			   EXPR_KIND_POLICY,
  			   "POLICY");
  
  		/* Fix up collation information */
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index 478d8ca..b79e73d 100644
*** a/src/backend/parser/parse_agg.c
--- b/src/backend/parser/parse_agg.c
*** check_agglevels_and_constraints(ParseSta
*** 373,378 
--- 373,381 
  		case EXPR_KIND_WHERE:
  			errkind = true;
  			break;
+ 		case EXPR_KIND_POLICY:
+ 			errkind = true;
+ 			break;
  		case EXPR_KIND_HAVING:
  			/* okay */
  			break;
*** transformWindowFuncCall(ParseState *psta
*** 770,775 
--- 773,781 
  		case EXPR_KIND_WHERE:
  			errkind = true;
  			break;
+ 		case EXPR_KIND_POLICY:
+ 			errkind = true;
+ 			break;
  		case EXPR_KIND_HAVING:
  			errkind = true;
  			break;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 5980856..7063e5f 100644
*** a/src/backend/parser/parse_clause.c
--- b/src/backend/parser/parse_clause.c
*** transformWhereClause(ParseState *pstate,
*** 1465,1470 
--- 1465,1491 
  	return qual;
  }
  
+ /*
+  * transformPolicyClause -
+  *	  Transform USING and WITH CHECK expr to make sure it is of type boolean.
+  *
+  * constructName does not affect the semantics, but is used in error messages
+  */
+ Node *
+ transformPolicyClause(ParseState *pstate, Node *clause,
+ 	  ParseExprKind exprKind, const char *constructName)
+ {
+ 	Node	   *qual;
+ 
+ 	if (clause == NULL)
+ 		return NULL;
+ 
+ 	qual = transformExpr(pstate, clause, exprKind);
+ 
+ 	qual = coerce_to_boolean(pstate, qual, constructName);
+ 
+ 	return qual;
+ }
  
  /*
   * transformLimitClause -
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0ff46dd..fa77ef1 100644
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*** transformSubLink(ParseState *pstate, Sub
*** 1672,1677 
--- 1672,1678 
  		case EXPR_KIND_FROM_SUBSELECT:
  		case EXPR_KIND_FROM_FUNCTION:
  		case EXPR_KIND_WHERE:
+ 		case EXPR_KIND_POLICY:
  		case EXPR_KIND_HAVING:
  		case EXPR_KIND_FILTER:
  		case EXPR_KIND_WINDOW_PARTITION:
*** ParseExprKindName(ParseExprKind exprKind
*** 3173,3178 
--- 3174,3181 
  			return "function in FROM";
  		case EXPR_KIND_WHERE:
  			return "WHERE";
+ 		case EXPR_KIND_POLICY:
+ 			return "POLICY";
  		case EXPR_KIND_HAVING:
  			return "HAVING";
  		case EXPR_KIND_FILTER:
diff --git a/src/include/parser/parse_claus

Re: [HACKERS] more RLS oversights

2015-07-28 Thread Joe Conway
On 07/03/2015 10:03 AM, Noah Misch wrote:
> (6) AlterPolicy() calls InvokeObjectPostAlterHook(PolicyRelationId, ...), but
> CreatePolicy() and DropPolicy() lack their respective hook invocations.

Patch attached. Actually AlterPolicy() was also missing its hook -- the
existing InvokeObjectPostAlterHook() was only in rename_policy().

I'm not 100% sure about the hook placement -- would appreciate if
someone could confirm I got it correct.

Joe

diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 4642d7c..77aaaca 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
*** RemovePolicyById(Oid policy_id)
*** 410,415 
--- 410,417 
  	if (!HeapTupleIsValid(tuple))
  		elog(ERROR, "could not find tuple for policy %u", policy_id);
  
+ 	InvokeObjectDropHook(PolicyRelationId, policy_id, 0);
+ 
  	/*
  	 * Open and exclusive-lock the relation the policy belong to.
  	 */
*** CreatePolicy(CreatePolicyStmt *stmt)
*** 629,634 
--- 631,638 
  	 SHARED_DEPENDENCY_POLICY);
  	}
  
+ 	InvokeObjectPostCreateHook(PolicyRelationId, policy_id, 0);
+ 
  	/* Invalidate Relation Cache */
  	CacheInvalidateRelcache(target_table);
  
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 860,865 
--- 864,871 
  	 SHARED_DEPENDENCY_POLICY);
  	}
  
+ 	InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
+ 
  	heap_freetuple(new_tuple);
  
  	/* Invalidate Relation Cache */

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-28 Thread Joe Conway
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/28/2015 11:50 AM, Stephen Frost wrote:
> * Joe Conway (joe.con...@crunchydata.com) wrote:
>> On 07/03/2015 10:03 AM, Noah Misch wrote:
>>> (4) When DefineQueryRewrite() is about to convert a table to a
>>> view, it checks the table for features unavailable to views.
>>> For example, it rejects tables having triggers.  It omits to
>>> reject tables having relrowsecurity or a pg_policy record.
>>> Test case:
>> 
>> Please see the attached patch for this issue. Comments?
> 
> Looks good to me.

Thanks -- pushed to HEAD and 9.5

Joe


-BEGIN PGP SIGNATURE-
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVuA+UAAoJEDfy90M199hlrtYQAJGVucRtarWTQoP39of8IYXE
OoAi+q6CKEJWEJdVHmnnCwMc6y0lx0+Qugpb5SAVqMG/0oYvZ/bnvvN5OHMxujCI
bw7A/eJ62BILAt07Oczs1gtt+k4PT1001c4jFjgSC6AV51cZ9UM+d0b4C2YhKcm7
B4tycmC/yGxa5UFT6vdOhneILzBeOMLxgMXKouoD7Gnf4UKh1KUWxxWKU9q0Kl7d
mvRJke1wj/+WfquO09g33+1jHCsnbV4fcQ1q8RQbFPItpqcp4alsuuIYzLiPRbbs
VtZYurFLpjKdJg8OuHw9IYNbDjPZoEuv5eV16aSjOJxnngcXROxwXOwZMVaCuQMq
1D5FoUunJqsqlxVKggJJLfBt9uM/gafjmnRHGBZftfX/A3ZM6c6YewA68Nxo+rTE
xtgA+n1lzWsahje0n2KSFUNRSCqdWcnLQ/HtnVcNjGdFdCxeUDQ5kUAE1hFCMCXe
5eqAvohQQ25RiurZ1rI1IfUoeAPRDp3nvgcMMM7FQMmv6oKNBLr2RivVz0ZE17vd
Htz0y0cPx8mJgEHKMJrV/yF9odECTxevBzkO5rASLCLnGHEYp8WZfqWO/s/HoujS
KU99lfzOfnyBIyl2zIGSmkmCvUIqaP1cUP5xMHIedNhjDRy/Rt6IxwA9qEtgUokI
sC6BWHpxd19RAh5NLXCK
=NFOR
-END PGP SIGNATURE-


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-28 Thread Joe Conway
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/27/2015 05:34 PM, Joe Conway wrote:
> On 07/27/2015 01:13 PM, Alvaro Herrera wrote:
>> Hmm, these are not ACL objects, so conceptually it seems cleaner
>> to use a different symbol for this.  I think the catalog state
>> and the error messages would be a bit confusing otherwise.
> 
> Ok -- done
> 
>> Isn't this leaking the previously allocated array?  Not sure
>> it's all that critical, but still.  (I don't think you really
>> need to call palloc at all here.)
> 
> Agreed -- I think the attached is a bit cleaner.
> 
> Any other comments or concerns?

Pushed to HEAD and 9.5

Joe


-BEGIN PGP SIGNATURE-
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVuAp9AAoJEDfy90M199hlokgP/2RVYjPiwM0EcE9pAdGP3Uqa
qkCqj5cPq/5SdLH553h/Xd6056qwchoMJYQo9RZzzVR4wS4HPyeZ00e33RrJZbtm
MGvjat1NJWEyl03y1AwAy9c9yHCRJa5vQlKtm0v2xWDG3xXqwejz/SK2ijw2IWVW
W1/7OnObbquHa7a+IsO1ndXoI0jECzOFDXY6YzFVJuPAf3asOHT44lJbHkfUq3Kv
k5eK14Xrb3kcYqhBQg+eG50lr1aRDj8yDlYQuoGmw/dg/X0TyAo2v+AOaFrN8rXD
igsYaMDafsXY55izkiRuNfcYZAnHC7hNVt+ffV+wLycCTiaEEflp+BCxLTYmh53T
xDB39Lr0Sz7AP77l0M9hbMr3Ao3GA1KFOc9OfRN11eSo5Y6uDtpMeOIFBAke6hxl
DanWPc/YmXzacga99xzOQglDZkDWTohWsEDwniRJmi7UC0Z/gwZ2P60OnwE1lqbd
eOmUu0JZCwklInWoDo9XmWdfp9+OrviGNm0vhQbplhEm/LC9PqBB/DOy44QjSv84
jfY/iMPn8uvGqWiQ/65za1O/1QsRukgp5PVnj7TyNojSskSuAYOF5BcFVIdB7krj
ZKHChreUMVw1nH8py4HkdPOXTHmAItV9/9T2c/UUuJWAECiLy+tIY/if+Tzi+Zn6
nRm99YM401PAsRKLyn0m
=gYmH
-END PGP SIGNATURE-


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-28 Thread Stephen Frost
* Joe Conway (joe.con...@crunchydata.com) wrote:
> On 07/03/2015 10:03 AM, Noah Misch wrote:
> > (4) When DefineQueryRewrite() is about to convert a table to a view, it 
> > checks
> > the table for features unavailable to views.  For example, it rejects tables
> > having triggers.  It omits to reject tables having relrowsecurity or a
> > pg_policy record.  Test case:
> 
> Please see the attached patch for this issue. Comments?

Looks good to me.

Thanks!

Stephen


signature.asc
Description: Digital signature


Re: [HACKERS] more RLS oversights

2015-07-28 Thread Joe Conway
On 07/03/2015 10:03 AM, Noah Misch wrote:
> (4) When DefineQueryRewrite() is about to convert a table to a view, it checks
> the table for features unavailable to views.  For example, it rejects tables
> having triggers.  It omits to reject tables having relrowsecurity or a
> pg_policy record.  Test case:

Please see the attached patch for this issue. Comments?

Thanks,

Joe

diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 17b48d4..aa858fa 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
*** get_relation_policy_oid(Oid relid, const
*** 1002,1004 
--- 1002,1033 
  
  	return policy_oid;
  }
+ 
+ /*
+  * relation_has_policies - Determine if relation has any policies
+  */
+ bool
+ relation_has_policies(Relation rel)
+ {
+ 	Relation	catalog;
+ 	ScanKeyData skey;
+ 	SysScanDesc sscan;
+ 	HeapTuple	policy_tuple;
+ 	bool		ret = false;
+ 
+ 	catalog = heap_open(PolicyRelationId, AccessShareLock);
+ 	ScanKeyInit(&skey,
+ Anum_pg_policy_polrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+ 	sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
+ 			   NULL, 1, &skey);
+ 	policy_tuple = systable_getnext(sscan);
+ 	if (HeapTupleIsValid(policy_tuple))
+ 		ret = true;
+ 
+ 	systable_endscan(sscan);
+ 	heap_close(catalog, AccessShareLock);
+ 
+ 	return ret;
+ }
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index a88d73e..39c83a6 100644
*** a/src/backend/rewrite/rewriteDefine.c
--- b/src/backend/rewrite/rewriteDefine.c
***
*** 27,32 
--- 27,33 
  #include "catalog/objectaccess.h"
  #include "catalog/pg_rewrite.h"
  #include "catalog/storage.h"
+ #include "commands/policy.h"
  #include "miscadmin.h"
  #include "nodes/nodeFuncs.h"
  #include "parser/parse_utilcmd.h"
*** DefineQueryRewrite(char *rulename,
*** 410,420 
  		 *
  		 * If so, check that the relation is empty because the storage for the
  		 * relation is going to be deleted.  Also insist that the rel not have
! 		 * any triggers, indexes, or child tables.  (Note: these tests are too
! 		 * strict, because they will reject relations that once had such but
! 		 * don't anymore.  But we don't really care, because this whole
! 		 * business of converting relations to views is just a kluge to allow
! 		 * dump/reload of views that participate in circular dependencies.)
  		 */
  		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
  			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
--- 411,422 
  		 *
  		 * If so, check that the relation is empty because the storage for the
  		 * relation is going to be deleted.  Also insist that the rel not have
! 		 * any triggers, indexes, child tables, policies, or RLS enabled.
! 		 * (Note: these tests are too strict, because they will reject
! 		 * relations that once had such but don't anymore.  But we don't
! 		 * really care, because this whole business of converting relations
! 		 * to views is just a kluge to allow dump/reload of views that
! 		 * participate in circular dependencies.)
  		 */
  		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
  			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
*** DefineQueryRewrite(char *rulename,
*** 451,456 
--- 453,470 
  		 errmsg("could not convert table \"%s\" to a view because it has child tables",
  RelationGetRelationName(event_relation;
  
+ 			if (event_relation->rd_rel->relrowsecurity)
+ ereport(ERROR,
+ 		(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 		 errmsg("could not convert table \"%s\" to a view because it has row security enabled",
+ RelationGetRelationName(event_relation;
+ 
+ 			if (relation_has_policies(event_relation))
+ ereport(ERROR,
+ 		(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 		 errmsg("could not convert table \"%s\" to a view because it has row security policies",
+ RelationGetRelationName(event_relation;
+ 
  			RelisBecomingView = true;
  		}
  	}
diff --git a/src/include/commands/policy.h b/src/include/commands/policy.h
index ac322e0..be00043 100644
*** a/src/include/commands/policy.h
--- b/src/include/commands/policy.h
*** extern Oid get_relation_policy_oid(Oid r
*** 31,35 
--- 31,36 
  
  extern ObjectAddress rename_policy(RenameStmt *stmt);
  
+ extern bool relation_has_policies(Relation rel);
  
  #endif   /* POLICY_H */
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 72361e8..2a8db6d 100644
*** a/src/test/regress/expected/rowsecurity.out
--- b/src/test/regress/expected/rowsecurity.out
*** SELECT * FROM coll_t;
*** 2908,2913 
--- 2908,2936 
  
  ROLLBACK;
  --
+ -- Converting table to view
+ --
+ BEGIN;
+ SET ROW_SECURITY = FORCE;
+ CREATE TABLE t (c int);
+ CREATE POLICY p ON t USING (c % 2 = 1);
+ 

Re: [HACKERS] more RLS oversights

2015-07-27 Thread Joe Conway
On 07/03/2015 10:03 AM, Noah Misch wrote:
>> +static void
>> +dumpPolicy(Archive *fout, PolicyInfo *polinfo)
> ...
>> +if (polinfo->polqual != NULL)
>> +appendPQExpBuffer(query, " USING %s", polinfo->polqual);
> 
> (3) The USING clause needs parentheses; a dump+reload failed like so:

Also needed for WITH CHECK. Fix pushed to 9.5 and HEAD.

Joe




-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers



Re: [HACKERS] more RLS oversights

2015-07-27 Thread Joe Conway
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/27/2015 01:13 PM, Alvaro Herrera wrote:
> Hmm, these are not ACL objects, so conceptually it seems cleaner to
> use a different symbol for this.  I think the catalog state and the
> error messages would be a bit confusing otherwise.

Ok -- done

> Isn't this leaking the previously allocated array?  Not sure it's
> all that critical, but still.  (I don't think you really need to
> call palloc at all here.)

Agreed -- I think the attached is a bit cleaner.

Any other comments or concerns?

- -- 
Joe Conway
-BEGIN PGP SIGNATURE-
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVts3+AAoJEDfy90M199hlzTIQAJ6LEOrEEhHEjsoVvCT6TUAu
pMQl/LWmb0s3/vF9o5VFTpVd21k0LxcggD+DdbxSagiw1WpLK5x67C9Lj5uuFn/d
3a95nFnQje3ciQJaAKS4XcGyx8+6rHPZqfBRC1rARbLuDHrwpKqmbKwvpQCud4xN
kD7OolYk5Gd3cId0xH0XBHuwLVJg4Bt/MAexrcHn+kXuQoF8V6iOjnmBI/BHvTQy
w4j4ov7DpWSAR1ZiCTCkF2ZuNd9TJ8FmAEtSDVrlWMxB9J+9PU5oTfD50jp62BTz
wycANVYmbpCyZ7DAAiqopt3IQFIiF/1bYwzWH3/M8RRMKJF8HNyE8KBPDyC/doO5
0c0poCugJI2wOhumLGJShizgSAS85vqijh2Uxpp2yQxdStMnADykzT4Nb5EnEJVE
i7OKy6w+2xyilfFGEWhHfS7uo5Y0zBorhpjgT9fRaqPBGoK4jYwZoO8w97SUd9aS
kNXOCfmFxvcDFSZIYZP77pOeJZR2dLCbr+X9bF1Fz5S4FVkgCXVOp9rmsqzgxoDh
lcpkDh9zPPezdczRkfq/qCf0lmzGg8apdqdr7+g8DxU+01OvPspEdpovQQN0HXlM
m5Kbny4KCWhAgBTyAsOFTEy6lK7u4KsHV1cee3bG+ev65czbQ14gGRMJc/Lhm6Gg
Apcn/UcF14vLWxYVo6lS
=pS6L
-END PGP SIGNATURE-
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 9096ee5..7781c56 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***
*** 5793,5798 
--- 5793,5808 
  
  
  
+  SHARED_DEPENDENCY_POLICY (r)
+  
+   
+The referenced object (which must be a role) is mentioned as the
+target of a dependent policy object.
+   
+  
+ 
+ 
+ 
   SHARED_DEPENDENCY_PIN (p)
   

diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 34fe4e2..43076c9 100644
*** a/src/backend/catalog/pg_shdepend.c
--- b/src/backend/catalog/pg_shdepend.c
*** storeObjectDescription(StringInfo descs,
*** 1083,1088 
--- 1083,1090 
  appendStringInfo(descs, _("owner of %s"), objdesc);
  			else if (deptype == SHARED_DEPENDENCY_ACL)
  appendStringInfo(descs, _("privileges for %s"), objdesc);
+ 			else if (deptype == SHARED_DEPENDENCY_POLICY)
+ appendStringInfo(descs, _("target of %s"), objdesc);
  			else
  elog(ERROR, "unrecognized dependency type: %d",
  	 (int) deptype);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 17b48d4..9544f75 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
***
*** 22,27 
--- 22,28 
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/objectaccess.h"
+ #include "catalog/pg_authid.h"
  #include "catalog/pg_policy.h"
  #include "catalog/pg_type.h"
  #include "commands/policy.h"
***
*** 48,54 
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  		  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static ArrayType *policy_role_list_to_array(List *roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
--- 49,55 
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  		  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static Datum *policy_role_list_to_array(List *roles, int *num_roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
*** parse_policy_command(const char *cmd_nam
*** 130,159 
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of role ids.
   */
! static ArrayType *
! policy_role_list_to_array(List *roles)
  {
! 	ArrayType  *role_ids;
! 	Datum	   *temp_array;
  	ListCell   *cell;
- 	int			num_roles;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 		temp_array = (Datum *) palloc(sizeof(Datum));
! 		temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		role_ids = construct_array(temp_array, 1, OIDOID, sizeof(Oid), true,
!    'i');
! 		return role_ids;
  	}
  
! 	num_roles = list_length(roles);
! 	temp_array = (Datum *) palloc(num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
--- 131,158 
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of
!  *	 role id Datums.
   */
! static Datum *
! policy_role_list_to_array(List *roles, int *num_roles)
  {
! 	Datum	   *role_oids;
  	ListCell   *cell;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 	   *num_roles = 1;
! 		role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
! 		role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		return role_oids;
  	}
  
!*num_roles = li

Re: [HACKERS] more RLS oversights

2015-07-27 Thread Alvaro Herrera
Joe Conway wrote:
> -BEGIN PGP SIGNED MESSAGE-
> Hash: SHA1
> 
> On 07/03/2015 10:03 AM, Noah Misch wrote:
> > (2) CreatePolicy() and AlterPolicy() omit to create a pg_shdepend
> > entry for each role in the TO clause.  Test case:
> 
> Please see the attached patch. Note that I used SHARED_DEPENDENCY_ACL
> for this. It seems appropriate, but possibly we should invent a new
> shared dependency type for this use case? Comments?

Hmm, these are not ACL objects, so conceptually it seems cleaner to use
a different symbol for this.  I think the catalog state and the error
messages would be a bit confusing otherwise.

>   if (spec->roletype == ROLESPEC_PUBLIC)
>   {
> ! Datum   *tmp_role_oids;
> ! 
> ! if (*num_roles != 1)
>   ereport(WARNING,
>   
> (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
>errmsg("ignoring roles 
> specified other than public"),
> errhint("All roles are members of the 
> public role.")));
> !*num_roles = 1;
> ! tmp_role_oids = (Datum *) palloc(*num_roles * 
> sizeof(Datum));
> ! tmp_role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);

Isn't this leaking the previously allocated array?  Not sure it's all
that critical, but still.  (I don't think you really need to call palloc
at all here.)

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-26 Thread Joe Conway
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/03/2015 10:03 AM, Noah Misch wrote:
> (2) CreatePolicy() and AlterPolicy() omit to create a pg_shdepend
> entry for each role in the TO clause.  Test case:

Please see the attached patch. Note that I used SHARED_DEPENDENCY_ACL
for this. It seems appropriate, but possibly we should invent a new
shared dependency type for this use case? Comments?

Thanks,

Joe

-BEGIN PGP SIGNATURE-
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVtSlAAAoJEDfy90M199hlrkIP/0BqMj30JpJVj3H5pIopU0RZ
pesBzFzzsWmt2QmasX9hajRfo6eXQAWPmKQmw/NDTJvHHNACxLdo0MHE7A9y7No7
aZIFTm0KhnG4jpzxfzpGqQ4ron5Vsc2TlNQgCBYCtbEEtuD0mV2qmcuTkqGte7iB
7iqneRBhmTYBy63X7S0ir4AhDi+JJg8P4F7YuU/XMcha5v5CpNJAToPpW7mCoZ8O
9w/RbXCHso7p1DIxfx4tfxVwLQ7j7G2j0rXbuA2e6OKfwZWWrk5E8Wnvc3xy3yCY
J37fcjOxFdhU/j1j+Tr90LYOSuRu5fQ4z6PmmsPkBM3T0Vllz/nNP64aVKbmHzga
szrIBERRs2icKa4OI08qZF42ObIEv0/t/NuyrXpegY6awRNNNsjyZvwM+51zdjw1
fuWh+2rObzh3RDH8lPB0N0rVfDMM+wU85Vaekckv/7UQ/pbWcwsYD/tykA1engQ8
Ww8kBAEct4dWdqppTqvLLxLgo4d+vuiS1mJ7SRY2aZFRX8QQ8TfB3eObETUsU4/X
9UWyMn+E0Au9ICX+wfD4whaBKst8EuO36qOZx0oZt+++EMOlzypgkCCxDtZO0KWd
KZHbtmJXHFVH+ihbEGXAKMIx+gLqSDG3IKy9MIJxpB3JY3XSdBNqobL2hiQy36/w
svK7i+mEYmUCQ6pB1j8c
=P1AS
-END PGP SIGNATURE-
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 17b48d4..20ac54e 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
***
*** 22,27 
--- 22,28 
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/objectaccess.h"
+ #include "catalog/pg_authid.h"
  #include "catalog/pg_policy.h"
  #include "catalog/pg_type.h"
  #include "commands/policy.h"
***
*** 48,54 
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  		  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static ArrayType *policy_role_list_to_array(List *roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
--- 49,55 
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  		  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static Datum *policy_role_list_to_array(List *roles, int *num_roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
*** parse_policy_command(const char *cmd_nam
*** 130,159 
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of role ids.
   */
! static ArrayType *
! policy_role_list_to_array(List *roles)
  {
! 	ArrayType  *role_ids;
! 	Datum	   *temp_array;
  	ListCell   *cell;
- 	int			num_roles;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 		temp_array = (Datum *) palloc(sizeof(Datum));
! 		temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		role_ids = construct_array(temp_array, 1, OIDOID, sizeof(Oid), true,
!    'i');
! 		return role_ids;
  	}
  
! 	num_roles = list_length(roles);
! 	temp_array = (Datum *) palloc(num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
--- 131,158 
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of
!  *	 role id Datums.
   */
! static Datum *
! policy_role_list_to_array(List *roles, int *num_roles)
  {
! 	Datum	   *role_oids;
  	ListCell   *cell;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 	   *num_roles = 1;
! 		role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
! 		role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		return role_oids;
  	}
  
!*num_roles = list_length(roles);
! 	role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
*** policy_role_list_to_array(List *roles)
*** 164,187 
  		 */
  		if (spec->roletype == ROLESPEC_PUBLIC)
  		{
! 			if (num_roles != 1)
  ereport(WARNING,
  		(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  		 errmsg("ignoring roles specified other than public"),
  	  errhint("All roles are members of the public role.")));
! 			temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
! 			num_roles = 1;
! 			break;
  		}
  		else
! 			temp_array[i++] =
  ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
  	}
  
! 	role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
! 			   'i');
! 
! 	return role_ids;
  }
  
  /*
--- 163,187 
  		 */
  		if (spec->roletype == ROLESPEC_PUBLIC)
  		{
! 			Datum   *tmp_role_oids;
! 
! 			if (*num_roles != 1)
  ereport(WARNING,
  		(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  		 errmsg("ignoring roles specified other than public"),
  	  errhint("All roles are members of the public role.")));
! 		   *num_roles = 1;
! 			tmp_role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
! 			tmp_role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
! 
! 			return tmp_r

Re: [HACKERS] more RLS oversights

2015-07-11 Thread Joe Conway
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 07/10/2015 06:15 PM, Noah Misch wrote:
> On Fri, Jul 10, 2015 at 03:08:53PM -0700, Joe Conway wrote:
>> On 07/03/2015 10:03 AM, Noah Misch wrote:
>>> (1) CreatePolicy() and AlterPolicy() omit to call
>>> assign_expr_collations() on the node trees.
> 
>> The attached fixes this issue for me, but I am unsure whether we
>> really need/want the regression test. Given the recent push to
>> increase test coverage maybe so.
> 
> I wouldn't remove the test from your patch.
> 

Ok -- pushed.

- -- 
Joe Conway
-BEGIN PGP SIGNATURE-
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVoYj2AAoJEDfy90M199hleBcP/3anI8IIEkFyPiUDX0QvzfEM
EOBm+AdolwgAvscU6RaDbrVXJlE32YbSWsXhtXOA5jJvhY80ln3YO+ko1ONWV3dW
iYbvSO+zQalHDqmID2bqbnY/k+7GTGWPCTsSLMsmUK7P0QCVP2f02lCukqr4yWpH
tIVbOfb0A1+Mrb9dxta43Bj32maBBiEpWIwaebotik6BmfwHNeeaZ082PUJQvaqS
wtshrlctAaCsCyjQnNiPvtD9mw0rlSWOhNDc7R8KGflWnwXmBlyu7jD4aFHKcPZO
v1ErqG2Z0allm3p6snpFbiunQssVpHgF7V8FcWxIReu73lV25ig3Ix56MoUXHIOq
a2Y5iAfRw106V1GA6ARW0kjCaE0DrRcfA6/Um8LeEhw44cvUBZkhXx/ozt0t62pz
6mvhKN4UjmO/XfbA9GEN7b9kDz+LZtMFQ1PqcH7mK3OYKgGfYTAdJOA7qwHuWMBC
MGVHP5WEUCJEToTNyzVe0matOH8+IHS4LQ9qAtUFVCmhh27FK0m8kjoZAmT/xDk5
uNcMG9mvBOTZe5EmVdC1gywDOsRntzAgWM1SFBK2v0YEgj3YarKll839Jm+dNHGZ
nxjniR/XJkNxISrTN6Qq797nhYsmpqRg+d7ZVk0GxmhfNNp/f2SFRVB9/9ovrk4x
//7pllazs48qu6e/3eYK
=EEZ7
-END PGP SIGNATURE-


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-10 Thread Joe Conway
On 07/03/2015 10:03 AM, Noah Misch wrote:
> (1) CreatePolicy() and AlterPolicy() omit to call assign_expr_collations() on
> the node trees.  Test case:
> 
> begin;
> set row_security = force;
> create table t (c) as values ('bar'::text);
> create policy p on t using (c < ('foo'::text COLLATE "C"));
> alter table t enable row level security;
> table pg_policy;  -- note ":inputcollid 0"
> select * from t;  -- ERROR:  could not determine which collation ...
> rollback;

The attached fixes this issue for me, but I am unsure whether we really
need/want the regression test. Given the recent push to increase test
coverage maybe so. Any objections?

Joe


diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 11efc9f..7232983 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
*** CreatePolicy(CreatePolicyStmt *stmt)
*** 538,543 
--- 538,547 
  		   EXPR_KIND_WHERE,
  		   "POLICY");
  
+ 	/* Fix up collation information */
+ 	assign_expr_collations(qual_pstate, qual);
+ 	assign_expr_collations(with_check_pstate, with_check_qual);
+ 
  	/* Open pg_policy catalog */
  	pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
  
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 681,686 
--- 685,693 
  	EXPR_KIND_WHERE,
  	"POLICY");
  
+ 		/* Fix up collation information */
+ 		assign_expr_collations(qual_pstate, qual);
+ 
  		qual_parse_rtable = qual_pstate->p_rtable;
  		free_parsestate(qual_pstate);
  	}
*** AlterPolicy(AlterPolicyStmt *stmt)
*** 701,706 
--- 708,716 
  			   EXPR_KIND_WHERE,
  			   "POLICY");
  
+ 		/* Fix up collation information */
+ 		assign_expr_collations(with_check_pstate, with_check_qual);
+ 
  		with_check_parse_rtable = with_check_pstate->p_rtable;
  		free_parsestate(with_check_pstate);
  	}
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 4073c1b..eabfd93 100644
*** a/src/test/regress/expected/rowsecurity.out
--- b/src/test/regress/expected/rowsecurity.out
*** ERROR:  permission denied for relation c
*** 2730,2735 
--- 2730,2756 
  RESET SESSION AUTHORIZATION;
  DROP TABLE copy_t;
  --
+ -- Collation support
+ --
+ BEGIN;
+ SET row_security = force;
+ CREATE TABLE coll_t (c) AS VALUES ('bar'::text);
+ CREATE POLICY coll_p ON coll_t USING (c < ('foo'::text COLLATE "C"));
+ ALTER TABLE coll_t ENABLE ROW LEVEL SECURITY;
+ SELECT (string_to_array(polqual, ':'))[7] AS inputcollid FROM pg_policy WHERE polrelid = 'coll_t'::regclass;
+inputcollid
+ --
+  inputcollid 950 
+ (1 row)
+ 
+ SELECT * FROM coll_t;
+   c  
+ -
+  bar
+ (1 row)
+ 
+ ROLLBACK;
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index fdd9b89..782824a 100644
*** a/src/test/regress/sql/rowsecurity.sql
--- b/src/test/regress/sql/rowsecurity.sql
*** RESET SESSION AUTHORIZATION;
*** 1088,1093 
--- 1088,1105 
  DROP TABLE copy_t;
  
  --
+ -- Collation support
+ --
+ BEGIN;
+ SET row_security = force;
+ CREATE TABLE coll_t (c) AS VALUES ('bar'::text);
+ CREATE POLICY coll_p ON coll_t USING (c < ('foo'::text COLLATE "C"));
+ ALTER TABLE coll_t ENABLE ROW LEVEL SECURITY;
+ SELECT (string_to_array(polqual, ':'))[7] AS inputcollid FROM pg_policy WHERE polrelid = 'coll_t'::regclass;
+ SELECT * FROM coll_t;
+ ROLLBACK;
+ 
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-10 Thread Noah Misch
On Fri, Jul 10, 2015 at 03:08:53PM -0700, Joe Conway wrote:
> On 07/03/2015 10:03 AM, Noah Misch wrote:
> > (1) CreatePolicy() and AlterPolicy() omit to call assign_expr_collations() 
> > on
> > the node trees.

> The attached fixes this issue for me, but I am unsure whether we really
> need/want the regression test. Given the recent push to increase test
> coverage maybe so.

I wouldn't remove the test from your patch.


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] more RLS oversights

2015-07-06 Thread Stephen Frost
Noah,

* Noah Misch (n...@leadboat.com) wrote:
> On Wed, Feb 25, 2015 at 11:37:24PM -0500, Stephen Frost wrote:
> > * Stephen Frost (sfr...@snowman.net) wrote:
> > > I agree that it's great that we're catching issues prior to when the
> > > feature is released and look forward to anything else you (or anyone
> > > else!) finds.
> > 
> > I've pushed a fix for this.  Please let me know if you see any other
> > issues or run into any problems.
> 
> (1) CreatePolicy() and AlterPolicy() omit to call assign_expr_collations() on
> the node trees.  Test case:

Will fix.

> (2) CreatePolicy() and AlterPolicy() omit to create a pg_shdepend entry for
> each role in the TO clause.  Test case:

Will fix.

> > +static void
> > +dumpPolicy(Archive *fout, PolicyInfo *polinfo)
> ...
> > +   if (polinfo->polqual != NULL)
> > +   appendPQExpBuffer(query, " USING %s", polinfo->polqual);
> 
> (3) The USING clause needs parentheses; a dump+reload failed like so:

Will fix.

> Add the same parentheses to psql \d output also, keeping that output similar
> to the SQL syntax.

Yup.

> (3a) I found this by hacking the rowsecurity.sql regression test to not drop
> its objects, then running the pg_upgrade test suite.  New features that affect
> pg_dump should leave objects in the regression database to test the pg_dump
> support via that suite.

Will fix.

> (4) When DefineQueryRewrite() is about to convert a table to a view, it checks
> the table for features unavailable to views.  For example, it rejects tables
> having triggers.  It omits to reject tables having relrowsecurity or a
> pg_policy record.  Test case:

Will fix.

> > +  
> > +   Referential integrity checks, such as unique or primary key constraints
> > +   and foreign key references, will bypass row security to ensure that
> > +   data integrity is maintained.  Care must be taken when developing
> > +   schemas and row level policies to avoid a "covert channel" leak of
> > +   information through these referential integrity checks.
> ...
> > +   /*
> > +* Row-level security should be disabled in the case where a foreign-key
> > +* relation is queried to check existence of tuples that references the
> > +* primary-key being modified.
> > +*/
> > +   temp_sec_context = save_sec_context | SECURITY_LOCAL_USERID_CHANGE;
> > +   if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK
> > +   || qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK_FROM_PK
> > +   || qkey->constr_queryno == RI_PLAN_RESTRICT_DEL_CHECKREF
> > +   || qkey->constr_queryno == RI_PLAN_RESTRICT_UPD_CHECKREF)
> > +   temp_sec_context |= SECURITY_ROW_LEVEL_DISABLED;
> 
> (5) This code does not use SECURITY_ROW_LEVEL_DISABLED for foreign keys with
> CASCADE, SET NULL or SET DEFAULT actions.  The associated documentation says
> nothing about this presumably-important distinction.

Agreed, will fix.

> Is SECURITY_ROW_LEVEL_DISABLED mode even needed?  We switch users to the owner
> of the FROM-clause table before running an RI query.  That means use of this
> mode can only matter under row_security=force, right?  I would rest easier if
> this mode went away, because it is a security landmine.  If user code managed
> to run in this mode, it would bypass every policy in the database.  (I find no
> such vulnerability today, because we use the mode only for parse analysis of
> ri_triggers.c queries.)

That's a very interesting point..  At first blush, I agree, it shouldn't
be necessary.  I'll play with it and see if I can get everything to work
properly without it.

> (6) AlterPolicy() calls InvokeObjectPostAlterHook(PolicyRelationId, ...), but
> CreatePolicy() and DropPolicy() lack their respective hook invocations.

Will fix.

> (7) Using an aggregate function in a policy predicate elicits an inapposite
> error message due to use of EXPR_KIND_WHERE for parse analysis.  Need a new
> ParseExprKind.  Test case:

Will fix.

Thanks a lot for your review!  Much appreciated.

Stephen


signature.asc
Description: Digital signature


Re: [HACKERS] more RLS oversights

2015-07-03 Thread Noah Misch
On Wed, Feb 25, 2015 at 11:37:24PM -0500, Stephen Frost wrote:
> * Stephen Frost (sfr...@snowman.net) wrote:
> > I agree that it's great that we're catching issues prior to when the
> > feature is released and look forward to anything else you (or anyone
> > else!) finds.
> 
> I've pushed a fix for this.  Please let me know if you see any other
> issues or run into any problems.

(1) CreatePolicy() and AlterPolicy() omit to call assign_expr_collations() on
the node trees.  Test case:

begin;
set row_security = force;
create table t (c) as values ('bar'::text);
create policy p on t using (c < ('foo'::text COLLATE "C"));
alter table t enable row level security;
table pg_policy;  -- note ":inputcollid 0"
select * from t;  -- ERROR:  could not determine which collation ...
rollback;


(2) CreatePolicy() and AlterPolicy() omit to create a pg_shdepend entry for
each role in the TO clause.  Test case:

begin;
create role alice;
create table t (c) as values ('bar'::text);
grant select on table t to alice;
create policy p on t to alice using (true);
select refclassid::regclass, refobjid, refobjsubid, deptype
  from pg_depend where classid = 'pg_policy'::regclass;
select refclassid::regclass, refobjid, deptype
  from pg_shdepend where classid = 'pg_policy'::regclass;
savepoint q; drop role alice; rollback to q;
revoke all on table t from alice;
\d t
drop role alice;
\d t
rollback;


> +static void
> +dumpPolicy(Archive *fout, PolicyInfo *polinfo)
...
> + if (polinfo->polqual != NULL)
> + appendPQExpBuffer(query, " USING %s", polinfo->polqual);

(3) The USING clause needs parentheses; a dump+reload failed like so:

pg_restore: [archiver (db)] could not execute query: ERROR:  syntax error at or 
near "CASE"
LINE 2: CASE
^
Command was: CREATE POLICY "p2" ON "category" FOR ALL TO PUBLIC USING 
CASE
WHEN ("current_user"() = 'rls_regress_user1'::"name") THE...

Add the same parentheses to psql \d output also, keeping that output similar
to the SQL syntax.

(3a) I found this by hacking the rowsecurity.sql regression test to not drop
its objects, then running the pg_upgrade test suite.  New features that affect
pg_dump should leave objects in the regression database to test the pg_dump
support via that suite.


(4) When DefineQueryRewrite() is about to convert a table to a view, it checks
the table for features unavailable to views.  For example, it rejects tables
having triggers.  It omits to reject tables having relrowsecurity or a
pg_policy record.  Test case:

begin;
set row_security = force;
create table t (c) as select * from generate_series(1,5);
create policy p on t using (c % 2 = 1);
alter table t enable row level security;
table t;
truncate t;
create rule "_RETURN" as on select to t do instead
  select * from generate_series(1,5) t0(c);
table t;
select polrelid::regclass from pg_policy;
select relrowsecurity from pg_class where oid = 't'::regclass;
rollback;


> +  
> +   Referential integrity checks, such as unique or primary key constraints
> +   and foreign key references, will bypass row security to ensure that
> +   data integrity is maintained.  Care must be taken when developing
> +   schemas and row level policies to avoid a "covert channel" leak of
> +   information through these referential integrity checks.
...
> + /*
> +  * Row-level security should be disabled in the case where a foreign-key
> +  * relation is queried to check existence of tuples that references the
> +  * primary-key being modified.
> +  */
> + temp_sec_context = save_sec_context | SECURITY_LOCAL_USERID_CHANGE;
> + if (qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK
> + || qkey->constr_queryno == RI_PLAN_CHECK_LOOKUPPK_FROM_PK
> + || qkey->constr_queryno == RI_PLAN_RESTRICT_DEL_CHECKREF
> + || qkey->constr_queryno == RI_PLAN_RESTRICT_UPD_CHECKREF)
> + temp_sec_context |= SECURITY_ROW_LEVEL_DISABLED;

(5) This code does not use SECURITY_ROW_LEVEL_DISABLED for foreign keys with
CASCADE, SET NULL or SET DEFAULT actions.  The associated documentation says
nothing about this presumably-important distinction.

Is SECURITY_ROW_LEVEL_DISABLED mode even needed?  We switch users to the owner
of the FROM-clause table before running an RI query.  That means use of this
mode can only matter under row_security=force, right?  I would rest easier if
this mode went away, because it is a security landmine.  If user code managed
to run in this mode, it would bypass every policy in the database.  (I find no
such vulnerability today, because we use the mode only for parse analysis of
ri_triggers.c queries.)


(6) AlterPolicy() calls InvokeObjectPostAlterHook(PolicyRelationId, ...), but
CreatePolicy() and DropPolicy() lack their respective hook invocations.


(7) Using an aggregate function in a policy predicate elicits an inapposite
error message due to use of EXPR_KIND_WHERE for parse analysis.  Need a new
ParseExprKind.  Test case:

begin;
set row

Re: [HACKERS] more RLS oversights

2015-02-25 Thread Stephen Frost
Robert, all,

* Stephen Frost (sfr...@snowman.net) wrote:
> * Robert Haas (robertmh...@gmail.com) wrote:
> > I happened to notice this morning while hacking that the
> > "hasRowSecurity" fields added to PlannerGlobal and PlannedStmt have
> > not been given proper nodefuncs.c support.  Both need to be added to
> > outfuncs.c, and the latter to copyfuncs.c.  The latter omission may
> > well be a security bug, although I haven't attempted to verify that,
> > but fortunately this isn't released yet.
> 
> I saw this and will address it.  Would be great if you wouldn't mind
> CC'ing me directly on anything RLS-related, same as you CC'd me on the
> column-privilege backpatch.  I expect I'll probably notice anyway, but
> I'll see them faster when I'm CC'd.
> 
> I agree that it's great that we're catching issues prior to when the
> feature is released and look forward to anything else you (or anyone
> else!) finds.

I've pushed a fix for this.  Please let me know if you see any other
issues or run into any problems.

Thanks!

Stephen


signature.asc
Description: Digital signature


Re: [HACKERS] more RLS oversights

2015-02-09 Thread Stephen Frost
Robert,

* Robert Haas (robertmh...@gmail.com) wrote:
> I happened to notice this morning while hacking that the
> "hasRowSecurity" fields added to PlannerGlobal and PlannedStmt have
> not been given proper nodefuncs.c support.  Both need to be added to
> outfuncs.c, and the latter to copyfuncs.c.  The latter omission may
> well be a security bug, although I haven't attempted to verify that,
> but fortunately this isn't released yet.

I saw this and will address it.  Would be great if you wouldn't mind
CC'ing me directly on anything RLS-related, same as you CC'd me on the
column-privilege backpatch.  I expect I'll probably notice anyway, but
I'll see them faster when I'm CC'd.

I agree that it's great that we're catching issues prior to when the
feature is released and look forward to anything else you (or anyone
else!) finds.

Thanks!

Stephen


signature.asc
Description: Digital signature


[HACKERS] more RLS oversights

2015-02-07 Thread Robert Haas
I happened to notice this morning while hacking that the
"hasRowSecurity" fields added to PlannerGlobal and PlannedStmt have
not been given proper nodefuncs.c support.  Both need to be added to
outfuncs.c, and the latter to copyfuncs.c.  The latter omission may
well be a security bug, although I haven't attempted to verify that,
but fortunately this isn't released yet.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers