Subject: Re: PG16.1 security breach?

From: Joe Conway <[email-masked]>
Date: Fri, 7 Jun 2024 09:22:21 -0400

On 6/7/24 07:04, Zwettler Markus (OIZ) wrote:
> I am running the following on Postgres 16.1 in database "postgres" as a 
> superuser:

<snip>

> create or replace function oiz.f_set_dbowner (p_dbowner text, p_dbname text)

<snip>

> create role testuser with password 'testuser' login;

<snip>

> than this new role is able to execute the function oiz.f_set_dbowner 
> immediately even I did not grant execute on this function to this role!

See:
https://www.postgresql.org/docs/current/sql-createfunction.html

In particular, this part:
8<------------------------
Another point to keep in mind is that by default, execute privilege is 
granted to PUBLIC for newly created functions (see Section 5.7 for more 
information). Frequently you will wish to restrict use of a security 
definer function to only some users. To do that, you must revoke the 
default PUBLIC privileges and then grant execute privilege selectively. 
To avoid having a window where the new function is accessible to all, 
create it and set the privileges within a single transaction. For example:
8<------------------------

HTH,

-- 
Joe Conway
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

---

From: "Zwettler Markus (OIZ)" <[email-masked]>
Date: Fri, 7 Jun 2024 13:54:23 +0000

> -----Ursprüngliche Nachricht-----
> Von: Joe Conway <[email-masked]>
> Gesendet: Freitag, 7. Juni 2024 15:22
> An: Zwettler Markus (OIZ) <[email-masked]>; pgsql-
> [email-masked]
> Betreff: [Extern] Re: PG16.1 security breach?
> 
> Another point to keep in mind is that by default, execute privilege is granted to
> PUBLIC for newly created functions (see Section 5.7 for more information).
> Frequently you will wish to restrict use of a security definer function to only some
> users. To do that, you must revoke the default PUBLIC privileges and then grant
> execute privilege selectively.
> To avoid having a window where the new function is accessible to all, create it and
> set the privileges within a single transaction. For example:
> --- Externe Email: Vorsicht mit Anhängen, Links oder dem Preisgeben von
> Informationen ---

Argh. No! What a bad habit!

Might be good idea for an enhancement request to create a global parameter to disable this habit.

Thanks Markus

---

From: Laurenz Albe <[email-masked]>
Date: Fri, 07 Jun 2024 16:32:44 +0200

> Might be good idea for an enhancement request to create a global parameter to disable this habit.

I don't see the problem, since the default execution mode for functions is
SECURITY INVOKER.

But you can easily change that:

  ALTER DEFAULT PRIVILEGES FOR ROLE function_creator REVOKE EXECUTE ON FUNCTION FROM PUBLIC;

Yours,
Laurenz Albe

---

From: Adrian Klaver <[email-masked]>
Date: Fri, 7 Jun 2024 07:35:58 -0700

> Might be good idea for an enhancement request to create a global parameter to disable this habit.

Read this

https://www.postgresql.org/docs/current/ddl-priv.html

through several times, it will make things clearer. In particular the 
part that starts "PostgreSQL grants privileges on some types of objects 
to PUBLIC by default when the objects are created. ..."

-- 
Adrian Klaver
[email-masked]

---

From: "David G. Johnston" <[email-masked]>
Date: Fri, 7 Jun 2024 07:42:31 -0700

On Friday, June 7, 2024, Laurenz Albe <[email-masked]> wrote:

> granted to

You named function_creator here when in this example the role creating the
new object is postgres.  How is it that the default privilege granted to
public doesn’t seem to care who the object creator is yet when revoking the
grant one supposedly can only do so within the scope of a single role?

David J.

---

From: Laurenz Albe <[email-masked]>
Date: Mon, 10 Jun 2024 11:21:42 +0200

On Fri, 2024-06-07 at 07:42 -0700, David G. Johnston wrote:
> You named function_creator here when in this example the role creating the new object is postgres.

Then use "postgres" rather than "function_creator".

An ALTER DEFAULT PRIVILEGES statement always only changes default privileges for objects
created by a certain user.

> How is it that the default privilege granted to public doesn’t seem to care who the object creator
> is yet when revoking the grant one supposedly can only do so within the scope of a single role?

I don't understand what you wrote.  ALTER DEFAULT PRIVILEGES also only applies to objects
created by a single role when you grant default privileges.

Yours,
Laurenz Albe

---

From: "David G. Johnston" <[email-masked]>
Date: Wed, 12 Jun 2024 13:35:21 -0700

> created by a single role when you grant default privileges.
I think my point is that a paragraph like the following may be a useful
addition:

If one wishes to remove the default privilege granted to public to execute
all newly created procedures it is necessary to revoke that privilege for
every superuser in the system as well as any roles that directly have
create permission on a schema and also those that inherit a create
permission on a schema.  Lastly, any new roles created in the future with
direct or indirect create permission on a schema must also be altered.  In
other words, the first time a role creates a routine the default privileges
involved with that creation will including granting execute to public,
unless said default privileges have already been revoked.

Maybe generalized to any of the default privileges.  I find the existing
wording to gloss over the fact that one cannot just decide up front they
want to not allow these default privileges to public once on a system-wide
basis but must continually maintain the default privileges as new roles are
added that are allowed to create different objects, directly or otherwise.

David J.