Re: copy.c handling for RLS is insecure - Mailing list pgsql-hackers

From Robert Haas
Subject Re: copy.c handling for RLS is insecure
Date
Msg-id CA+TgmoathzDf9Dk-bc11+ZYKkNXjHmKxBSQDMHuWs3Ajs0+o_g@mail.gmail.com
Whole thread Raw
In response to Re: copy.c handling for RLS is insecure  (Stephen Frost <sfrost@snowman.net>)
Responses Re: copy.c handling for RLS is insecure
Re: copy.c handling for RLS is insecure
List pgsql-hackers
On Mon, Oct 6, 2014 at 2:49 PM, Stephen Frost <sfrost@snowman.net> wrote:
> * Robert Haas (robertmhaas@gmail.com) wrote:
>> In DoCopy, some RLS-specific code constructs a SelectStmt to handle
>> the case where COPY TO is invoked on an RLS-protected relation.  But I
>> think this step is bogus in two ways:
>>
>>             /* Build FROM clause */
>>             from = makeRangeVar(NULL, RelationGetRelationName(rel), 1);
>>
>> First, because relations are schema objects, there could be multiple
>> relations with the same name.  The RangeVar might end up referring to
>> a different one of those objects than the user originally specified.
>
> Argh.  That's certainly no good.  It should just be using the RangeVar
> relation passed in from CopyStmt, no?

I don't think that's adequate.  You can't do a RangeVar-to-OID
translation, use the resulting OID for some security-relevant
decision, and then repeat the RangeVar-to-OID translation and hope you
get the same answer.  That's what led to CVE-2014-0062, fixed by
commit 5f173040e324f6c2eebb90d86cf1b0cdb5890f0a.  I can't work out
off-hand whether the issue is exploitable in this instance, but it
sure seems like a bad idea to rely on it not being so.

> We don't have to address the case
> where it's NULL (tho we should perhaps Assert(), just to be sure), as
> that would only happen in the COPY select_with_parens ... production and
> this is only for the normal 'COPY relname' case.

The antecedent of "it" in "the case where it's NULL" is unclear to me.

> Hmm, that's certainly an interesting point, but I'm trying to work out
> how this is different from normal COPY..?  pg_analyze_and_rewrite()
> happens for both cases down in BeginCopy().

As far as I can see, the previous code only looked up any given name
once.  If you got a relation name, DoCopy() looked it up, and then
BeginCopy() references it only by the passed-down Relation descriptor;
if you got a query, DoCopy() ignores it, and then BeginCopy.  All of
which is fine, at least AFAICS; if you think otherwise, that should be
reported to pgsql-security.  The problem with your code is that you
start with a relation name (and thus look it up in DoCopy()) and then
construct a query (which causes the name to be looked up again when
the query is passed to pg_analyze_and_rewrite() from BeginCopy()) --
and the lookup might not get the same answer both times.  That is, not
to put to fine a point on it, bad news.

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



pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: copy.c handling for RLS is insecure
Next
From: Robert Haas
Date:
Subject: Re: copy.c handling for RLS is insecure