Re: [v9.3] Row-Level Security

From: Kohei KaiGai <kaigai(at)kaigai(dot)gr(dot)jp>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Florian Pflug <fgp(at)phlo(dot)org>, Robert Haas <robertmhaas(at)gmail(dot)com>, PgHacker <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: [v9.3] Row-Level Security
Date: 2012-07-15 09:52:03
Message-ID: CADyhKSUXVffLJrmfMpi2xH=U+bFxu9Qa4w7kVhQoxkMfQOJ3yw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

The attached patch is a revised version of row-level security feature.

I added a feature to invalidate plan cache if user-id was switched
between planner and optimizer. It enabled to generate more optimized
plan than the previous approach; that adds hardwired "OR superuser()".

Example)
postgres=# PREPARE p1(int) AS SELECT * FROM t1 WHERE x > $1 AND f_leak(y);
PREPARE
postgres=# EXPLAIN (costs off) EXECUTE p1(2);
QUERY PLAN
-----------------------------------
Seq Scan on t1
Filter: (f_leak(y) AND (x > 2))
(2 rows)

postgres=# SET SESSION AUTHORIZATION alice;
SET
postgres=> EXPLAIN (costs off) EXECUTE p1(2);
QUERY PLAN
---------------------------------------------
Subquery Scan on t1
Filter: f_leak(t1.y)
-> Seq Scan on t1
Filter: ((x > 2) AND ((x % 2) = 0))
(4 rows)

On the other hand, I removed support for UPDATE / DELETE commands
in this revision, because I'm still uncertain on the implementation that I
adopted in the previous patch. I believe it helps to keep patch size being
minimum reasonable.
Due to same reason, RLS is not supported on COPY TO command.

According to the Robert's comment, I revised the place to inject
applyRowLevelSecurity(). The reason why it needed to patch on
adjust_appendrel_attrs_mutator() was, we handled expansion from
regular relation to sub-query after expand_inherited_tables().
In this revision, it was moved to the head of sub-query planner.

Even though I added a syscache entry for pg_rowlevelsec catalog,
it was revised to read the catalog on construction of relcache, like
trigger descriptor, because it enables to reduce cost to parse an
expression tree in text format and memory consumption of hash
slot.

This revision adds support on pg_dump, and also adds support
to include SubLinks in the row-level security policy.

Thanks,

2012/7/1 Kohei KaiGai <kaigai(at)kaigai(dot)gr(dot)jp>:
> 2012/6/28 Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>:
>> Kohei KaiGai <kaigai(at)kaigai(dot)gr(dot)jp> writes:
>>> 2012/6/27 Florian Pflug <fgp(at)phlo(dot)org>:
>>>> Hm, what happens if a SECURITY DEFINER functions returns a refcursor?
>>
>>> My impression is, here is no matter even if SECURITY DEFINER function
>>> returns refcursor.
>>
>> I think Florian has a point: it *should* work, but *will* it?
>>
>> I believe it works today, because the executor only applies permissions
>> checks during query startup. So those checks are executed while still
>> within the SECURITY DEFINER context, and should behave as expected.
>> Subsequently, the cursor portal is returned to caller and caller can
>> execute it to completion, no problem.
>>
>> However, with RLS security-related checks will happen throughout the
>> execution of the portal. They might do the wrong thing once the
>> SECURITY DEFINER function has been exited.
>>
> I tried the scenario that Florian pointed out.
>
> postgres=# CREATE OR REPLACE FUNCTION f_test(refcursor) RETURNS refcursor
> postgres-# SECURITY DEFINER LANGUAGE plpgsql
> postgres-# AS 'BEGIN OPEN $1 FOR SELECT current_user, * FROM t1;
> RETURN $1; END';
> CREATE FUNCTION
> postgres=# BEGIN;
> BEGIN
> postgres=# SELECT f_test('abc');
> f_test
> --------
> abc
> (1 row)
>
> postgres=# FETCH abc;
> current_user | a | b
> --------------+---+-----
> kaigai | 1 | aaa
> (1 row)
>
> postgres=# SET SESSION AUTHORIZATION alice;
> SET
> postgres=> FETCH abc;
> current_user | a | b
> --------------+---+-----
> alice | 2 | bbb
> (1 row)
>
> postgres=> SET SESSION AUTHORIZATION bob;
> SET
> postgres=> FETCH abc;
> current_user | a | b
> --------------+---+-----
> bob | 3 | ccc
> (1 row)
>
> Indeed, the output of "current_user" depends on the setting of session
> authorization, even though it was declared within security definer
> functions (thus, its security checks are applied on the privileges of
> function owner).
>
>> We might need to consider that a portal has a local value of
>> "current_user", which is kind of a pain, but probably doable.
>>
> It seems to me, it is an individual matter to be fixed independent
> from RLS feature. How about your opinion?
>
> If we go ahead, an idea to tackle this matter is switch user-id
> into saved one in the Portal at the beginning of PortanRun or
> PortalRunFetch.
>
> Thanks,
> --
> KaiGai Kohei <kaigai(at)kaigai(dot)gr(dot)jp>

--
KaiGai Kohei <kaigai(at)kaigai(dot)gr(dot)jp>

Attachment Content-Type Size
pgsql-v9.3-row-level-security.ro.v2.patch application/octet-stream 115.8 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Cédric Villemain 2012-07-15 10:52:32 Re: Use of rsync for data directory copying
Previous Message Stephen Frost 2012-07-15 05:02:01 Re: Use of rsync for data directory copying