Ban role pg_signal_backend from more superuser backend types.
authorNoah Misch <[email protected]>
Mon, 6 Nov 2023 14:14:13 +0000 (06:14 -0800)
committerNoah Misch <[email protected]>
Mon, 6 Nov 2023 14:14:13 +0000 (06:14 -0800)
Documentation says it cannot signal "a backend owned by a superuser".
On the contrary, it could signal background workers, including the
logical replication launcher.  It could signal autovacuum workers and
the autovacuum launcher.  Block all that.  Signaling autovacuum workers
and those two launchers doesn't stall progress beyond what one could
achieve other ways.  If a cluster uses a non-core extension with a
background worker that does not auto-restart, this could create a denial
of service with respect to that background worker.  A background worker
with bugs in its code for responding to terminations or cancellations
could experience those bugs at a time the pg_signal_backend member
chooses.  Back- to v11 (all supported versions).

Reviewed by Jelte Fennema-Nio.  Reported by Hemanth Sandrana and
Mahendrakar Srinivasarao.

Security: CVE-2023-5870

src/backend/storage/ipc/signalfuncs.c
src/test/regress/expected/privileges.out
src/test/regress/sql/privileges.sql

index 94ae553b9461857c939b6c6de4316838760da1a5..b595c2d69123370c9650e2688cf79ba4be6555cc 100644 (file)
@@ -74,8 +74,13 @@ pg_signal_backend(int pid, int sig)
                return SIGNAL_BACKEND_ERROR;
        }
 
-       /* Only allow superusers to signal superuser-owned backends. */
-       if (superuser_arg(proc->roleId) && !superuser())
+       /*
+        * Only allow superusers to signal superuser-owned backends.  Any process
+        * not advertising a role might have the importance of a superuser-owned
+        * backend, so treat it that way.
+        */
+       if ((!OidIsValid(proc->roleId) || superuser_arg(proc->roleId)) &&
+               !superuser())
                return SIGNAL_BACKEND_NOSUPERUSER;
 
        /* Users can signal backends they have role membership in. */
index c1e610e62f3b175f006fc6bcdae7d0abe0fb59e5..fbb0489a4ffaf918047f4edc5770bdbe7b41f13d 100644 (file)
@@ -2083,6 +2083,24 @@ SELECT * FROM pg_largeobject LIMIT 0;
 SET SESSION AUTHORIZATION regress_priv_user1;
 SELECT * FROM pg_largeobject LIMIT 0;                  -- to be denied
 ERROR:  permission denied for table pg_largeobject
+-- pg_signal_backend can't signal superusers
+RESET SESSION AUTHORIZATION;
+BEGIN;
+CREATE OR REPLACE FUNCTION terminate_nothrow(pid int) RETURNS bool
+       LANGUAGE plpgsql SECURITY DEFINER SET client_min_messages = error AS $$
+BEGIN
+       RETURN pg_terminate_backend($1);
+EXCEPTION WHEN OTHERS THEN
+       RETURN false;
+END$$;
+ALTER FUNCTION terminate_nothrow OWNER TO pg_signal_backend;
+SELECT backend_type FROM pg_stat_activity
+WHERE CASE WHEN COALESCE(usesysid, 10) = 10 THEN terminate_nothrow(pid) END;
+ backend_type 
+--------------
+(0 rows)
+
+ROLLBACK;
 -- test pg_database_owner
 RESET SESSION AUTHORIZATION;
 GRANT pg_database_owner TO regress_priv_user1;
index bf0035d96d253907310d09199dd7416c7a55e4c9..3f68cafcd1ea1607b11b8e4f7bb2715b11649ffd 100644 (file)
@@ -1349,6 +1349,21 @@ SELECT * FROM pg_largeobject LIMIT 0;
 SET SESSION AUTHORIZATION regress_priv_user1;
 SELECT * FROM pg_largeobject LIMIT 0;                  -- to be denied
 
+-- pg_signal_backend can't signal superusers
+RESET SESSION AUTHORIZATION;
+BEGIN;
+CREATE OR REPLACE FUNCTION terminate_nothrow(pid int) RETURNS bool
+       LANGUAGE plpgsql SECURITY DEFINER SET client_min_messages = error AS $$
+BEGIN
+       RETURN pg_terminate_backend($1);
+EXCEPTION WHEN OTHERS THEN
+       RETURN false;
+END$$;
+ALTER FUNCTION terminate_nothrow OWNER TO pg_signal_backend;
+SELECT backend_type FROM pg_stat_activity
+WHERE CASE WHEN COALESCE(usesysid, 10) = 10 THEN terminate_nothrow(pid) END;
+ROLLBACK;
+
 -- test pg_database_owner
 RESET SESSION AUTHORIZATION;
 GRANT pg_database_owner TO regress_priv_user1;