diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2024-12-28 16:08:50 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2024-12-28 16:08:50 -0500 |
commit | 3d1ecc92a0d15eb299ea37c9842b3367eddc0081 (patch) | |
tree | 97ede5352eef79a0fc3ce729caf6a18d0f1db5f6 /src/backend/utils/init/postinit.c | |
parent | 83bb52375630ce93660bde938ffba93c6dc7fc63 (diff) | |
download | postgresql-3d1ecc92a0d15eb299ea37c9842b3367eddc0081.tar.gz postgresql-3d1ecc92a0d15eb299ea37c9842b3367eddc0081.zip |
Exclude parallel workers from connection privilege/limit checks.
Cause parallel workers to not check datallowconn, rolcanlogin, and
ACL_CONNECT privileges. The leader already checked these things
(except for rolcanlogin which might have been checked for a different
role). Re-checking can accomplish little except to induce unexpected
failures in applications that might not even be aware that their query
has been parallelized. We already had the principle that parallel
workers rely on their leader to pass a valid set of authorization
information, so this change just extends that a bit further.
Also, modify the ReservedConnections, datconnlimit and rolconnlimit
logic so that these limits are only enforced against regular backends,
and only regular backends are counted while checking if the limits
were already reached. Previously, background processes that had an
assigned database or role were subject to these limits (with rather
random exclusions for autovac workers and walsenders), and the set of
existing processes that counted against each limit was quite haphazard
as well. The point of these limits, AFAICS, is to ensure the
availability of PGPROC slots for regular backends. Since all other
types of processes have their own separate pools of PGPROC slots, it
makes no sense either to enforce these limits against them or to count
them while enforcing the limit.
While edge-case failures of these sorts have been possible for a
long time, the problem got a good deal worse with commit 5a2fed911
(CVE-2024-10978), which caused parallel workers to make some of these
checks using the leader's current role where before we had used its
AuthenticatedUserId, thus allowing parallel queries to fail after
SET ROLE. The previous behavior was fairly accidental and I have
no desire to return to it.
This patch includes reverting 73c9f91a1, which was an emergency hack
to suppress these same checks in some cases. It wasn't complete,
as shown by a recent bug report from Laurenz Albe. We can also revert
fd4d93d26 and 492217301, which hacked around the same problems in one
regression test.
In passing, remove the special case for autovac workers in
CheckMyDatabase; it seems cleaner to have AutoVacWorkerMain pass
the INIT_PG_OVERRIDE_ALLOW_CONNS flag, now that that does what's
needed.
Like 5a2fed911, back-patch to supported branches (which sadly no
longer includes v12).
Discussion: https://postgr.es/m/1808397.1735156190@sss.pgh.pa.us
Diffstat (limited to 'src/backend/utils/init/postinit.c')
-rw-r--r-- | src/backend/utils/init/postinit.c | 40 |
1 files changed, 13 insertions, 27 deletions
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 27716c2d233..81ec949a02f 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -22,7 +22,6 @@ #include "access/genam.h" #include "access/heapam.h" #include "access/htup_details.h" -#include "access/parallel.h" #include "access/session.h" #include "access/sysattr.h" #include "access/tableam.h" @@ -339,13 +338,13 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect * These checks are not enforced when in standalone mode, so that there is * a way to recover from disabling all access to all databases, for * example "UPDATE pg_database SET datallowconn = false;". - * - * We do not enforce them for autovacuum worker processes either. */ - if (IsUnderPostmaster && !IsAutoVacuumWorkerProcess()) + if (IsUnderPostmaster) { /* * Check that the database is currently allowing connections. + * (Background processes can override this test and the next one by + * setting override_allow_connections.) */ if (!dbform->datallowconn && !override_allow_connections) ereport(FATAL, @@ -358,7 +357,7 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect * is redundant, but since we have the flag, might as well check it * and save a few cycles.) */ - if (!am_superuser && + if (!am_superuser && !override_allow_connections && pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CONNECT) != ACLCHECK_OK) ereport(FATAL, @@ -367,7 +366,9 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect errdetail("User does not have CONNECT privilege."))); /* - * Check connection limit for this database. + * Check connection limit for this database. We enforce the limit + * only for regular backends, since other process types have their own + * PGPROC pools. * * There is a race condition here --- we create our PGPROC before * checking for other PGPROCs. If two backends did this at about the @@ -377,6 +378,7 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect * just document that the connection limit is approximate. */ if (dbform->datconnlimit >= 0 && + AmRegularBackendProcess() && !am_superuser && CountDBConnections(MyDatabaseId) > dbform->datconnlimit) ereport(FATAL, @@ -851,23 +853,7 @@ InitPostgres(const char *in_dbname, Oid dboid, else { InitializeSessionUserId(username, useroid); - - /* - * In a parallel worker, set am_superuser based on the - * authenticated user ID, not the current role. This is pretty - * dubious but it matches our historical behavior. Note that this - * value of am_superuser is used only for connection-privilege - * checks here and in CheckMyDatabase (we won't reach - * process_startup_options in a background worker). - * - * In other cases, there's been no opportunity for the current - * role to diverge from the authenticated user ID yet, so we can - * just rely on superuser() and avoid an extra catalog lookup. - */ - if (InitializingParallelWorker) - am_superuser = superuser_arg(GetAuthenticatedUserId()); - else - am_superuser = superuser(); + am_superuser = superuser(); } } else @@ -890,11 +876,11 @@ InitPostgres(const char *in_dbname, Oid dboid, } /* - * The last few connection slots are reserved for superusers. Replication - * connections are drawn from slots reserved with max_wal_senders and not - * limited by max_connections or superuser_reserved_connections. + * The last few regular connection slots are reserved for superusers. We + * do not apply this limit to background processes, since they all have + * their own pools of PGPROC slots. */ - if (!am_superuser && !am_walsender && + if (AmRegularBackendProcess() && !am_superuser && ReservedBackends > 0 && !HaveNFreeProcs(ReservedBackends)) ereport(FATAL, |