Re: Security leak with trigger functions?

From: Chapman Flack <chap(at)anastigmatix(dot)net>
To: Peter Eisentraut <peter_e(at)gmx(dot)net>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-hackers(at)postgresql(dot)org, Albe Laurenz <all(at)adv(dot)magwien(dot)gv(dot)at>
Subject: Re: Security leak with trigger functions?
Date: 2018-01-22 21:04:30
Message-ID: b1be2d05-b9fd-b9db-ea7f-38253e4e4bab@anastigmatix.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 12/14/2006 01:17 PM, Peter Eisentraut wrote:
> Tom Lane wrote:
>> Peter Eisentraut <peter_e(at)gmx(dot)net> writes:
>>> By extrapolation of the SQL standard, I'd say we'd need to check
>>> the EXECUTE privilege of the function at run time.
>>
>> Certainly EXECUTE privilege is what to check, but whose privilege?
>
> ...
> ("The authorization identifier of the owner of the schema that includes
> the trigger descriptor of TR is pushed onto the authorization stack.")
>
> PostgreSQL only allows a trigger action of "call this function", so in
> the SQL standard context that would mean we'd need to check the EXECUTE
> privilege of the owner of the trigger. The trick is figuring out who
> the owner is. If it's the owner of the table, then TRIGGER privilege
> is effectively total control over the owner of the table. If it's
> whoever created the trigger, it might be useful, but I don't see how
> that is compatible with the intent of the SQL standard.

Hmm, it's been not quite a dozen years, have there been later threads
that followed up on this discussion?

Is it still accurate to describe the status quo as:

- Triggers can be created only by a role with TRIGGER on the
relation and EXECUTE on the function, checked at trigger creation
time.

- Once created, triggers are executed with no local userid change (so,
just as whatever role issued whatever DML fired the trigger), and
without a check for EXECUTE on the function at that time, except:

- Internal trigger functions implementing RI checks will execute their
queries as "the owner of whichever table the query touches (the
referenced table for verification of FK inserts, the referencing
table when cascading a PK change)."
https://www.postgresql.org/message-id/5761.1509733215%40sss.pgh.pa.us

It seems to me that the 2006 conversation was complicated by the
fact that PostgreSQL triggers don't have owners of their own, and
don't have schema-qualified names, as triggers in the SQL standard do.
So the conversation was going in the direction of running as the owner
of the relation, but for the obvious consequence that it would turn
TRIGGER permission into an equivalent of the relation owner's identity.

If the idea of changing the current behavior at all could be thinkable,
could one think about changing it more along SQL standard lines, by
letting a trigger itself have a schema, and executing as the owner
of the schema?

This seems to me not too different from just letting a trigger have
an owner, and executing as that, which could seem less roundabout.
OTOH, going through the schema has the advantage of following the
standard, and may allow a little more flexibility in setting up
delegated authority; a schema with a certain owner can be created,
CREATE(*) on that schema can be selectively granted, enabling grantees
to create trigger declarations in that schema, applying to any
relations they have TRIGGER permission for. Either way, TRIGGER
permission is left with something useful to mean, unlike the
execute-as-relation-owner case, where the meaning of TRIGGER sort of
evaporates.

(*) a different permission might be better here, as many existing
schemas probably grant CREATE to roles today without intending that
they be able to create triggers that execute as the schema owner.
TRIGGER might work, having no existing meaning on a schema.

I think the execute-as-relation-owner idea might not easily fit
situations where different roles with cross-cutting concerns all have
their own reasons to put triggers on a given relation, but should not
otherwise have the same permissions or run with the same id. I think
such situations could easily be accommodated in a model where triggers
have schemas and execute as the schema owner.

I could imagine a graceful migration plan:

1. Give pg_trigger a tgnamespace column, but allow it to be null
or InvalidOid, meaning a trigger that should have the current
behavior, executed with no local userid change. Conversely, a
trigger with a valid tgnamespace gets executed as the owner
of that schema.

2. pg_upgrade preserves existing triggers as triggers with no
namespace. The grammar is altered to allow a schema when creating
a trigger (and to allow ALTER TRIGGER SET SCHEMA).

3. Permission checks for schemaless triggers stay as they are now:
EXECUTE on the function checked at for the trigger's creator at
creation time, but not at run time. For triggers in schemas, the
schema owner is who must have EXECUTE on the function.

4. It could still be possible to avoid runtime permission checks,
the existence of EXECUTE for the right role being checked at
trigger creation time, if REVOKE EXECUTE on a trigger function
includes a check through pg_depend for triggers whose execute
right would be lost. Those would be (a) any triggers with schemas
owned by a role having EXECUTE revoked, and (b) any schema-less
triggers at all (as there's no telling whose permission might
have been checked at the time they were created).

The simple check in 4(b) could be implemented on its own, without any
of the rest, as a simple way to plug the "security leak" in the status
quo.

Thoughts?

-Chap

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Stephen Frost 2018-01-22 21:15:20 Re: [HACKERS] Lazy hash table for XidInMVCCSnapshot (helps Zipfian a bit)
Previous Message Tom Lane 2018-01-22 21:03:21 Re: pgsql: Move handling of database properties from pg_dumpall into pg_dum