Thread: Loose ends after CVE-2020-14350 (extension installation hazards)

Loose ends after CVE-2020-14350 (extension installation hazards)

From
Tom Lane
Date:
Yesterday's releases included some fixes meant to make it harder
for a malicious user to sabotage an extension installation/update
script.  There are some things remaining to be done in the area,
though:

1. We don't have a way to make things adequately secure for extensions
that depend on other extensions.  As an example, suppose that Alice
installs the "cube" extension into schema1 and then installs
"earthdistance" into schema2.  The earthdistance install script will
run with search_path "schema2, schema1".  If schema2 is writable by
Bob, then Bob can create a type "schema2.cube" ahead of time, and
that will capture all the references to cube in the earthdistance
script.  Bob can similarly capture the references to cube functions
in earthdistance's domain constraints.  A partial solution to this
might be to extend the @extschema@ notation to allow specification
of a depended-on extension's schema.  Inventing freely, we could
imagine writing earthdistance's domain creation command like

CREATE DOMAIN earth AS @extschema(cube)@.cube
  CONSTRAINT not_point check(@extschema(cube)@.cube_is_point(value))
  CONSTRAINT not_3d check(@extschema(cube)@.cube_dim(value) <= 3)
  CONSTRAINT on_surface check(abs(@extschema(cube)@.cube_distance(value,
                              '(0)'::@extschema(cube)@.cube) /
                              earth() - '1'::float8) < '10e-7'::float8);

This is pretty tedious and error-prone; but as long as one is careful
to write only exact matches of function and operator argument types,
it's safe against CVE-2018-1058-style attacks, even if both extensions
are in publicly writable schemas.

However, in itself this can only fix references that are resolved during
execution of the extension script.  I don't see a good way to use the
idea to make earthdistance's SQL functions fully secure.  It won't do
to write, say,

CREATE FUNCTION ll_to_earth(float8, float8)
...
AS 'SELECT @extschema(cube)@.cube(...)';

because this will not survive somebody doing "ALTER EXTENSION cube SET
SCHEMA schema3".  I don't have a proposal for what to do about that.
Admittedly, we already disclaim security if you run queries with a
search_path that contains any untrusted schemas ... but it would be
nice if extensions could be written that (in themselves) are safe
regardless.  Peter E's proposal for parsing SQL function bodies at
creation time could perhaps fix this for SQL functions, but we still
have the issue for other PLs.

2. For the most part, the sorts of DDL commands you might use in an
extension script are not very subject to CVE-2018-1058-style attacks
because they specify relevant functions and operators exactly.  As long
as the objects you want are at the front of the search_path, there's no
way for an attacker to inject another, better match.  I did find one
exception that is not fixed as of today: lookup_agg_function() allows
inexact argument type matches for an aggregate's support functions,
so it could be possible to capture a reference if the intended support
function doesn't exactly match the aggregate's declared input and
transition data types.  This doesn't occur in any contrib modules
fortunately.  I do not see a way to make this better without breaking
the ability to use polymorphic support functions in a non-polymorphic
aggregate, since those are inherently not exact matches.

3. As Christoph Berg noted, the fixes in some extension update scripts
mean that plpgsql has to be installed while those scripts run.  How
much do we care, and if we do, what should we do about it?  I suggested
a band-aid fix of updating the base install scripts so that users don't
typically need to run the update scripts, but that's just a band-aid.
Maybe we could extend SQL enough so that plpgsql isn't needed to do
what those scripts have to do.  I'd initially thought of doing the
search path save-and-restore via

    SAVEPOINT s1;
    SET LOCAL search_path = pg_catalog, pg_temp;
    ... protected code here ...
    RELEASE SAVEPOINT s1;

but this does not work because SET LOCAL persists to the end of the
outer transaction.  Maybe we could invent a variant that only lasts
for the current subtransaction.

4. I noticed while testing that hstore--1.0--1.1.sql is completely
useless nowadays, so it might as well get dropped.  It fails with a
syntax error in every still-supported server version, since "=>" is
no longer a legal operator name.  There's no way to load hstore 1.0
into a modern server because of that, either.

Thoughts?

            regards, tom lane



Re: Loose ends after CVE-2020-14350 (extension installation hazards)

From
Chapman Flack
Date:
On 08/14/20 14:50, Tom Lane wrote:
>     SAVEPOINT s1;
>     SET LOCAL search_path = pg_catalog, pg_temp;
>     ... protected code here ...
>     RELEASE SAVEPOINT s1;
> 
> but this does not work because SET LOCAL persists to the end of the
> outer transaction.  Maybe we could invent a variant that only lasts
> for the current subtransaction.

This reminds me of the way the SQL standard overloads WITH to supply
lexically-scoped settings of things, as well as CTEs, mentioned a while
back. [1]

Would this provide additional incentive to implement that syntax,
generalized to support arbitrary GUCs and not just the handful of
specific settings the standard uses it for?

Regards,
-Chap



[1] https://www.postgresql.org/message-id/5AAEAE0F.20006%40anastigmatix.net



Re: Loose ends after CVE-2020-14350 (extension installation hazards)

From
Tom Lane
Date:
Chapman Flack <chap@anastigmatix.net> writes:
> On 08/14/20 14:50, Tom Lane wrote:
>> SAVEPOINT s1;
>> SET LOCAL search_path = pg_catalog, pg_temp;
>> ... protected code here ...
>> RELEASE SAVEPOINT s1;
>> but this does not work because SET LOCAL persists to the end of the
>> outer transaction.  Maybe we could invent a variant that only lasts
>> for the current subtransaction.

> This reminds me of the way the SQL standard overloads WITH to supply
> lexically-scoped settings of things, as well as CTEs, mentioned a while
> back. [1]
> Would this provide additional incentive to implement that syntax,
> generalized to support arbitrary GUCs and not just the handful of
> specific settings the standard uses it for?

Hmm.  I see a few things not to like about that:

(1) It's hard to see how the WITH approach could work for GUCs
that need to take effect during raw parsing, such as the much-detested
standard_conforming_strings.  Ideally we'd not have any such GUCs, for
the reasons explained at the top of gram.y, but I dunno that we'll ever
get there.

(2) We only have WITH for DML (SELECT/INSERT/UPDATE/DELETE), not utility
commands.  Maybe that's enough for the cases at hand.  Or maybe we'd be
willing to do whatever's needful to handle WITH attached to a utility
command, but that could be a pretty large addition of work.

(3) If the SQL syntax is really just "WITH variable value [, ...]"
then I'm afraid we're going to have a lot of parse-ambiguity problems
with wedging full SET syntax into that.  The ability for the righthand
side to be a comma-separated list is certainly going to go out the
window, and we have various other special cases like "SET TIME ZONE"
that aren't going to work.  Again, maybe we don't need a full solution,
but it seems like it's gonna be a kluge.

(4) You'd need to repeat the WITH for each SQL command, IIUC.  Could
get tedious.

So maybe this is worth doing just for more standards compliance, but
it doesn't really seem like a nicer solution than subtransaction-
scoped SET.

            regards, tom lane



Re: Loose ends after CVE-2020-14350 (extension installation hazards)

From
Chapman Flack
Date:
On 08/14/20 15:38, Tom Lane wrote:

> (3) If the SQL syntax is really just "WITH variable value [, ...]"
> then I'm afraid we're going to have a lot of parse-ambiguity problems
> with wedging full SET syntax into that.  The ability for the righthand

There is precedent in the SET command for having one general syntax
usable for any GUC, and specialized ones for a few 'special' GUCs
(search_path, client_encoding, timezone).

Maybe WITH could be done the same way, inventing some less thorny syntax
for the general case

   WITH (foo = bar, baz), (quux = 42), XMLBINARY BASE64, a AS (SELECT...)

and treating just the few like XMLBINARY that appear in the standard
as having equivalent specialized productions?

The only examples of the syntax in the standard that are coming to mind
right now are those I've seen in the SQL/XML part, but I feel like I have
seen others, as if the committee kind of likes their WITH local-setting-
of-something syntax, and additional examples may continue to appear.

Regards,
-Chap



Re: Loose ends after CVE-2020-14350 (extension installation hazards)

From
Noah Misch
Date:
On Fri, Aug 14, 2020 at 02:50:32PM -0400, Tom Lane wrote:
> However, in itself this can only fix references that are resolved during
> execution of the extension script.  I don't see a good way to use the
> idea to make earthdistance's SQL functions fully secure.  It won't do
> to write, say,
> 
> CREATE FUNCTION ll_to_earth(float8, float8)
> ...
> AS 'SELECT @extschema(cube)@.cube(...)';
> 
> because this will not survive somebody doing "ALTER EXTENSION cube SET
> SCHEMA schema3".  I don't have a proposal for what to do about that.

Another challenge is verifying that the body qualified everything.  Via a
simple matter of programming, CREATE EXTENSION could verify that CREATE-time
code observes schema qualification rules.  That would not extend to function
bodies.

> Admittedly, we already disclaim security if you run queries with a
> search_path that contains any untrusted schemas ... but it would be
> nice if extensions could be written that (in themselves) are safe
> regardless.

Yes.  Even when safety is not a concern, it's a quality problem for the
functions to error out when search_path lacks some schema.  As you know, we
get recurring reports about that, e.g.
https://www.postgresql.org/message-id/flat/16534-69f25077c45f34a5%40postgresql.org

> Peter E's proposal for parsing SQL function bodies at
> creation time could perhaps fix this for SQL functions, but we still
> have the issue for other PLs.

Yes.  The SQL-specific feature could do enough to let a future version of
earthdistance be trusted.

> 2. [...] lookup_agg_function() allows
> inexact argument type matches for an aggregate's support functions,
> so it could be possible to capture a reference if the intended support
> function doesn't exactly match the aggregate's declared input and
> transition data types.

Should CREATE AGGREGATE support "FINALFUNC = foo(sometype)" input to constrain
the lookup?  (It does accept the syntax, but "sometype" is unused and need not
even denote an extant type.)

> 3. As Christoph Berg noted, the fixes in some extension update scripts
> mean that plpgsql has to be installed while those scripts run.  How
> much do we care, and if we do, what should we do about it?

I propose not caring at all.  Since we have dump/reload of "REVOKE USAGE ON
LANGUAGE plpgsql FROM PUBLIC", extensions requiring plpgsql are fine.  (It
could be a problem in a "superuser = false" extension, but core isn't doing
those.)  Even saddling plpgsql with a pin dependency would be fine.

> 4. I noticed while testing that hstore--1.0--1.1.sql is completely
> useless nowadays, so it might as well get dropped.  It fails with a
> syntax error in every still-supported server version, since "=>" is
> no longer a legal operator name.  There's no way to load hstore 1.0
> into a modern server because of that, either.

The chance of this getting reported from the field has been dropping for
several years.  It's negligible now.

Thanks,
nm