Skip to content

Commit e03c66d

Browse files
reshkenmisch
andauthored
Backport: Ban role pg_signal_backend from more superuser backend types. (#1504)
Cherry-picked from https://git.postgresql.org/cgit/postgresql.git/commit/?id=3a9b18b3095366cd0c4305441d426d04572d88c1 Apache Cloudberry changes reviewed by Andrey Borodin and Max Yang. 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-patch to v11 (all supported versions). Reviewed by Jelte Fennema-Nio. Reported by Hemanth Sandrana and Mahendrakar Srinivasarao. Security: CVE-2023-5870 Co-authored-by: Noah Misch <noah@leadboat.com>
1 parent a16ad2b commit e03c66d

3 files changed

Lines changed: 41 additions & 29 deletions

File tree

src/backend/storage/ipc/signalfuncs.c

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ static int
5252
pg_signal_backend(int pid, int sig, char *msg)
5353
{
5454
PGPROC *proc = BackendPidGetProc(pid);
55-
LocalPgBackendStatus *local_beentry;
5655

5756
/*
5857
* BackendPidGetProc returns NULL if the pid isn't valid; but by the time
@@ -73,34 +72,14 @@ pg_signal_backend(int pid, int sig, char *msg)
7372
return SIGNAL_BACKEND_ERROR;
7473
}
7574

76-
local_beentry = pgstat_fetch_stat_local_beentry_by_pid(pid);
77-
78-
/* Only allow superusers to signal superuser-owned backends. */
79-
if (superuser_arg(proc->roleId) && !superuser())
80-
{
81-
Oid role;
82-
char * appname;
83-
84-
if (local_beentry == NULL) {
85-
return SIGNAL_BACKEND_NOSUPERUSER;
86-
}
87-
88-
role = get_role_oid("mdb_admin", true /*if nodoby created mdb_admin role in this database*/);
89-
appname = local_beentry->backendStatus.st_appname;
90-
91-
// only allow mdb_admin to kill su queries
92-
if (!is_member_of_role(GetUserId(), role)) {
93-
return SIGNAL_BACKEND_NOSUPERUSER;
94-
}
95-
96-
if (local_beentry->backendStatus.st_backendType == B_AUTOVAC_WORKER) {
97-
// ok
98-
} else if (appname != NULL && strcmp(appname, "MDB") == 0) {
99-
// ok
100-
} else {
101-
return SIGNAL_BACKEND_NOSUPERUSER;
102-
}
103-
}
75+
/*
76+
* Only allow superusers to signal superuser-owned backends. Any process
77+
* not advertising a role might have the importance of a superuser-owned
78+
* backend, so treat it that way.
79+
*/
80+
if ((!OidIsValid(proc->roleId) || superuser_arg(proc->roleId)) &&
81+
!superuser())
82+
return SIGNAL_BACKEND_NOSUPERUSER;
10483

10584
/* Users can signal backends they have role membership in. */
10685
if (!has_privs_of_role(GetUserId(), proc->roleId) &&

src/test/regress/expected/privileges.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,24 @@ TABLE information_schema.enabled_roles;
19861986

19871987
INSERT INTO datdba_only DEFAULT VALUES;
19881988
ERROR: permission denied for table datdba_only
1989+
ROLLBACK;
1990+
-- pg_signal_backend can't signal superusers
1991+
RESET SESSION AUTHORIZATION;
1992+
BEGIN;
1993+
CREATE OR REPLACE FUNCTION terminate_nothrow(pid int) RETURNS bool
1994+
LANGUAGE plpgsql SECURITY DEFINER SET client_min_messages = error AS $$
1995+
BEGIN
1996+
RETURN pg_terminate_backend($1);
1997+
EXCEPTION WHEN OTHERS THEN
1998+
RETURN false;
1999+
END$$;
2000+
ALTER FUNCTION terminate_nothrow OWNER TO pg_signal_backend;
2001+
SELECT backend_type FROM pg_stat_activity
2002+
WHERE CASE WHEN COALESCE(usesysid, 10) = 10 THEN terminate_nothrow(pid) END;
2003+
backend_type
2004+
--------------
2005+
(0 rows)
2006+
19892007
ROLLBACK;
19902008
-- test default ACLs
19912009
\c -

src/test/regress/sql/privileges.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,21 @@ TABLE information_schema.enabled_roles;
12081208
INSERT INTO datdba_only DEFAULT VALUES;
12091209
ROLLBACK;
12101210

1211+
-- pg_signal_backend can't signal superusers
1212+
RESET SESSION AUTHORIZATION;
1213+
BEGIN;
1214+
CREATE OR REPLACE FUNCTION terminate_nothrow(pid int) RETURNS bool
1215+
LANGUAGE plpgsql SECURITY DEFINER SET client_min_messages = error AS $$
1216+
BEGIN
1217+
RETURN pg_terminate_backend($1);
1218+
EXCEPTION WHEN OTHERS THEN
1219+
RETURN false;
1220+
END$$;
1221+
ALTER FUNCTION terminate_nothrow OWNER TO pg_signal_backend;
1222+
SELECT backend_type FROM pg_stat_activity
1223+
WHERE CASE WHEN COALESCE(usesysid, 10) = 10 THEN terminate_nothrow(pid) END;
1224+
ROLLBACK;
1225+
12111226
-- test default ACLs
12121227
\c -
12131228

0 commit comments

Comments
 (0)