Introduce pg_signal_autovacuum_worker.
authorNathan Bossart <[email protected]>
Tue, 9 Jul 2024 18:03:40 +0000 (13:03 -0500)
committerNathan Bossart <[email protected]>
Tue, 9 Jul 2024 18:03:40 +0000 (13:03 -0500)
Since commit 3a9b18b309, roles with privileges of pg_signal_backend
cannot signal autovacuum workers.  Many users treated the ability
to signal autovacuum workers as a feature instead of a bug, so we
are reintroducing it via a new predefined role.  Having privileges
of this new role, named pg_signal_autovacuum_worker, only permits
signaling autovacuum workers.  It does not permit signaling other
types of superuser backends.

Bumps catversion.

Author: Kirill Reshke
Reviewed-by: Anthony Leung, Michael Paquier, Andrey Borodin
Discussion: https://postgr.es/m/CALdSSPhC4GGmbnugHfB9G0%3DfAxjCSug_-rmL9oUh0LTxsyBfsg%40mail.gmail.com

doc/src/sgml/func.sgml
doc/src/sgml/user-manag.sgml
src/backend/storage/ipc/signalfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_authid.dat

index f9d7a8f9c352a45525d0aad088f0dc03e8e32617..f1ce1db6bcd95da665304f5a4da884fb626a5007 100644 (file)
@@ -28163,6 +28163,10 @@ acl      | {postgres=arwdDxtm/postgres,foo=r/postgres}
         calling role is a member of the role whose backend is being canceled or
         the calling role has privileges of <literal>pg_signal_backend</literal>,
         however only superusers can cancel superuser backends.
+        As an exception, roles with privileges of
+        <literal>pg_signal_autovacuum_worker</literal> are permitted to
+        cancel autovacuum worker processes, which are otherwise considered
+        superuser backends.
        </para></entry>
       </row>
 
@@ -28237,6 +28241,10 @@ acl      | {postgres=arwdDxtm/postgres,foo=r/postgres}
         is a member of the role whose backend is being terminated or the
         calling role has privileges of <literal>pg_signal_backend</literal>,
         however only superusers can terminate superuser backends.
+        As an exception, roles with privileges of
+        <literal>pg_signal_autovacuum_worker</literal> are permitted to
+        terminate autovacuum worker processes, which are otherwise considered
+        superuser backends.
        </para>
        <para>
         If <parameter>timeout</parameter> is not specified or zero, this
index 07a16247d76f15c2c11a4024365098b3343a6999..340cefff705925e80759e13cebe888ca22693cf7 100644 (file)
@@ -661,6 +661,11 @@ DROP ROLE doomed_role;
        <entry>pg_signal_backend</entry>
        <entry>Signal another backend to cancel a query or terminate its session.</entry>
       </row>
+      <row>
+       <entry>pg_signal_autovacuum_worker</entry>
+       <entry>Signal an autovacuum worker to cancel the current table's vacuum
+       or terminate its session.</entry>
+      </row>
       <row>
        <entry>pg_read_server_files</entry>
        <entry>Allow reading files from any location the database can access on the server with COPY and
index 88e9bf8125d11772a8785dd9f4d5b2f8157dee49..aa729a36e3921f387d5e67497d69c07cff6caf4d 100644 (file)
@@ -34,8 +34,9 @@
  * role as the backend being signaled. For "dangerous" signals, an explicit
  * check for superuser needs to be done prior to calling this function.
  *
- * Returns 0 on success, 1 on general failure, 2 on normal permission error
- * and 3 if the caller needs to be a superuser.
+ * Returns 0 on success, 1 on general failure, 2 on normal permission error,
+ * 3 if the caller needs to be a superuser, and 4 if the caller needs to have
+ * privileges of pg_signal_autovacuum_worker.
  *
  * In the event of a general failure (return code 1), a warning message will
  * be emitted. For permission errors, doing that is the responsibility of
@@ -45,6 +46,7 @@
 #define SIGNAL_BACKEND_ERROR 1
 #define SIGNAL_BACKEND_NOPERMISSION 2
 #define SIGNAL_BACKEND_NOSUPERUSER 3
+#define SIGNAL_BACKEND_NOAUTOVAC 4
 static int
 pg_signal_backend(int pid, int sig)
 {
@@ -77,15 +79,27 @@ pg_signal_backend(int pid, int sig)
    /*
     * 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.
+    * backend, so treat it that way.  As an exception, we allow roles with
+    * privileges of pg_signal_autovacuum_worker to signal autovacuum workers
+    * (which do not advertise a role).
+    *
+    * Otherwise, users can signal backends for roles they have privileges of.
     */
-   if ((!OidIsValid(proc->roleId) || superuser_arg(proc->roleId)) &&
-       !superuser())
-       return SIGNAL_BACKEND_NOSUPERUSER;
+   if (!OidIsValid(proc->roleId) || superuser_arg(proc->roleId))
+   {
+       ProcNumber  procNumber = GetNumberFromPGProc(proc);
+       PgBackendStatus *procStatus = pgstat_get_beentry_by_proc_number(procNumber);
 
-   /* Users can signal backends they have role membership in. */
-   if (!has_privs_of_role(GetUserId(), proc->roleId) &&
-       !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
+       if (procStatus && procStatus->st_backendType == B_AUTOVAC_WORKER)
+       {
+           if (!has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_AUTOVACUUM_WORKER))
+               return SIGNAL_BACKEND_NOAUTOVAC;
+       }
+       else if (!superuser())
+           return SIGNAL_BACKEND_NOSUPERUSER;
+   }
+   else if (!has_privs_of_role(GetUserId(), proc->roleId) &&
+            !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
        return SIGNAL_BACKEND_NOPERMISSION;
 
    /*
@@ -130,6 +144,13 @@ pg_cancel_backend(PG_FUNCTION_ARGS)
                 errdetail("Only roles with the %s attribute may cancel queries of roles with the %s attribute.",
                           "SUPERUSER", "SUPERUSER")));
 
+   if (r == SIGNAL_BACKEND_NOAUTOVAC)
+       ereport(ERROR,
+               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                errmsg("permission denied to cancel query"),
+                errdetail("Only roles with privileges of the \"%s\" role may cancel autovacuum workers.",
+                          "pg_signal_autovacuum_worker")));
+
    if (r == SIGNAL_BACKEND_NOPERMISSION)
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -236,6 +257,13 @@ pg_terminate_backend(PG_FUNCTION_ARGS)
                 errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
                           "SUPERUSER", "SUPERUSER")));
 
+   if (r == SIGNAL_BACKEND_NOAUTOVAC)
+       ereport(ERROR,
+               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                errmsg("permission denied to terminate process"),
+                errdetail("Only roles with privileges of the \"%s\" role may terminate autovacuum workers.",
+                          "pg_signal_autovacuum_worker")));
+
    if (r == SIGNAL_BACKEND_NOPERMISSION)
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
index 4bf79d462acc23aeb5696978896a8c13c60b05dc..06f43c496f39107cc9128d51a01b7b72c0f8bbf2 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202407082
+#define CATALOG_VERSION_NO 202407091
 
 #endif
index bf00815c14e4758f456aecf515539e5330dfcdf0..0129f67eaaa2790809d160380fed8faa7ca758ef 100644 (file)
   rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
   rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
   rolpassword => '_null_', rolvaliduntil => '_null_' },
+{ oid => '8916', oid_symbol => 'ROLE_PG_SIGNAL_AUTOVACUUM_WORKER',
+  rolname => 'pg_signal_autovacuum_worker', rolsuper => 'f', rolinherit => 't',
+  rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
+  rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
+  rolpassword => '_null_', rolvaliduntil => '_null_' },
 
 ]