LCOV - differential code coverage report
Current view: top level - src/backend/storage/ipc - signalfuncs.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 53.6 % 69 37 1 20 11 4 22 11 16 25 1
Current Date: 2023-04-08 15:15:32 Functions: 71.4 % 7 5 2 3 1 1 2 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * signalfuncs.c
       4                 :  *    Functions for signaling backends
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *    src/backend/storage/ipc/signalfuncs.c
      12                 :  *
      13                 :  *-------------------------------------------------------------------------
      14                 :  */
      15                 : #include "postgres.h"
      16                 : 
      17                 : #include <signal.h>
      18                 : 
      19                 : #include "catalog/pg_authid.h"
      20                 : #include "miscadmin.h"
      21                 : #include "pgstat.h"
      22                 : #include "postmaster/syslogger.h"
      23                 : #include "storage/pmsignal.h"
      24                 : #include "storage/proc.h"
      25                 : #include "storage/procarray.h"
      26                 : #include "utils/acl.h"
      27                 : #include "utils/builtins.h"
      28                 : 
      29                 : 
      30                 : /*
      31                 :  * Send a signal to another backend.
      32                 :  *
      33                 :  * The signal is delivered if the user is either a superuser or the same
      34                 :  * role as the backend being signaled. For "dangerous" signals, an explicit
      35                 :  * check for superuser needs to be done prior to calling this function.
      36                 :  *
      37                 :  * Returns 0 on success, 1 on general failure, 2 on normal permission error
      38                 :  * and 3 if the caller needs to be a superuser.
      39                 :  *
      40                 :  * In the event of a general failure (return code 1), a warning message will
      41                 :  * be emitted. For permission errors, doing that is the responsibility of
      42                 :  * the caller.
      43                 :  */
      44                 : #define SIGNAL_BACKEND_SUCCESS 0
      45                 : #define SIGNAL_BACKEND_ERROR 1
      46                 : #define SIGNAL_BACKEND_NOPERMISSION 2
      47                 : #define SIGNAL_BACKEND_NOSUPERUSER 3
      48                 : static int
      49 CBC          35 : pg_signal_backend(int pid, int sig)
      50                 : {
      51              35 :     PGPROC     *proc = BackendPidGetProc(pid);
      52                 : 
      53                 :     /*
      54                 :      * BackendPidGetProc returns NULL if the pid isn't valid; but by the time
      55                 :      * we reach kill(), a process for which we get a valid proc here might
      56                 :      * have terminated on its own.  There's no way to acquire a lock on an
      57                 :      * arbitrary process to prevent that. But since so far all the callers of
      58                 :      * this mechanism involve some request for ending the process anyway, that
      59                 :      * it might end on its own first is not a problem.
      60                 :      *
      61                 :      * Note that proc will also be NULL if the pid refers to an auxiliary
      62                 :      * process or the postmaster (neither of which can be signaled via
      63                 :      * pg_signal_backend()).
      64                 :      */
      65              35 :     if (proc == NULL)
      66                 :     {
      67                 :         /*
      68                 :          * This is just a warning so a loop-through-resultset will not abort
      69                 :          * if one backend terminated on its own during the run.
      70                 :          */
      71 UBC           0 :         ereport(WARNING,
      72                 :                 (errmsg("PID %d is not a PostgreSQL backend process", pid)));
      73                 : 
      74               0 :         return SIGNAL_BACKEND_ERROR;
      75                 :     }
      76                 : 
      77                 :     /* Only allow superusers to signal superuser-owned backends. */
      78 CBC          35 :     if (superuser_arg(proc->roleId) && !superuser())
      79 UBC           0 :         return SIGNAL_BACKEND_NOSUPERUSER;
      80                 : 
      81                 :     /* Users can signal backends they have role membership in. */
      82 CBC          35 :     if (!has_privs_of_role(GetUserId(), proc->roleId) &&
      83 UBC           0 :         !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
      84               0 :         return SIGNAL_BACKEND_NOPERMISSION;
      85                 : 
      86                 :     /*
      87                 :      * Can the process we just validated above end, followed by the pid being
      88                 :      * recycled for a new process, before reaching here?  Then we'd be trying
      89                 :      * to kill the wrong thing.  Seems near impossible when sequential pid
      90                 :      * assignment and wraparound is used.  Perhaps it could happen on a system
      91                 :      * where pid re-use is randomized.  That race condition possibility seems
      92                 :      * too unlikely to worry about.
      93                 :      */
      94                 : 
      95                 :     /* If we have setsid(), signal the backend's whole process group */
      96                 : #ifdef HAVE_SETSID
      97 CBC          35 :     if (kill(-pid, sig))
      98                 : #else
      99                 :     if (kill(pid, sig))
     100                 : #endif
     101                 :     {
     102                 :         /* Again, just a warning to allow loops */
     103 UBC           0 :         ereport(WARNING,
     104                 :                 (errmsg("could not send signal to process %d: %m", pid)));
     105               0 :         return SIGNAL_BACKEND_ERROR;
     106                 :     }
     107 CBC          35 :     return SIGNAL_BACKEND_SUCCESS;
     108                 : }
     109                 : 
     110                 : /*
     111                 :  * Signal to cancel a backend process.  This is allowed if you are a member of
     112                 :  * the role whose process is being canceled.
     113                 :  *
     114                 :  * Note that only superusers can signal superuser-owned processes.
     115                 :  */
     116                 : Datum
     117              29 : pg_cancel_backend(PG_FUNCTION_ARGS)
     118                 : {
     119              29 :     int         r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
     120                 : 
     121              29 :     if (r == SIGNAL_BACKEND_NOSUPERUSER)
     122 UBC           0 :         ereport(ERROR,
     123                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     124                 :                  errmsg("permission denied to cancel query"),
     125                 :                  errdetail("Only roles with the %s attribute may cancel queries of roles with %s.",
     126                 :                            "SUPERUSER", "SUPERUSER")));
     127                 : 
     128 GIC          29 :     if (r == SIGNAL_BACKEND_NOPERMISSION)
     129 UIC           0 :         ereport(ERROR,
     130 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     131                 :                  errmsg("permission denied to cancel query"),
     132                 :                  errdetail("Only roles with privileges of the role whose query is being canceled or with privileges of the \"%s\" role may cancel this query.",
     133                 :                            "pg_signal_backend")));
     134                 : 
     135 GIC          29 :     PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
     136                 : }
     137                 : 
     138                 : /*
     139 ECB             :  * Wait until there is no backend process with the given PID and return true.
     140                 :  * On timeout, a warning is emitted and false is returned.
     141                 :  */
     142                 : static bool
     143 GIC           2 : pg_wait_until_termination(int pid, int64 timeout)
     144                 : {
     145                 :     /*
     146                 :      * Wait in steps of waittime milliseconds until this function exits or
     147 ECB             :      * timeout.
     148                 :      */
     149 GIC           2 :     int64       waittime = 100;
     150                 : 
     151                 :     /*
     152                 :      * Initially remaining time is the entire timeout specified by the user.
     153 ECB             :      */
     154 GIC           2 :     int64       remainingtime = timeout;
     155                 : 
     156                 :     /*
     157                 :      * Check existence of the backend. If the backend still exists, then wait
     158 ECB             :      * for waittime milliseconds, again check for the existence. Repeat this
     159                 :      * until timeout or an error occurs or a pending interrupt such as query
     160                 :      * cancel gets processed.
     161                 :      */
     162                 :     do
     163                 :     {
     164 GIC           6 :         if (remainingtime < waittime)
     165 UIC           0 :             waittime = remainingtime;
     166                 : 
     167 GIC           6 :         if (kill(pid, 0) == -1)
     168 ECB             :         {
     169 GBC           2 :             if (errno == ESRCH)
     170 GIC           2 :                 return true;
     171 ECB             :             else
     172 UIC           0 :                 ereport(ERROR,
     173 ECB             :                         (errcode(ERRCODE_INTERNAL_ERROR),
     174                 :                          errmsg("could not check the existence of the backend with PID %d: %m",
     175                 :                                 pid)));
     176 EUB             :         }
     177                 : 
     178                 :         /* Process interrupts, if any, before waiting */
     179 GIC           4 :         CHECK_FOR_INTERRUPTS();
     180                 : 
     181               4 :         (void) WaitLatch(MyLatch,
     182                 :                          WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
     183 ECB             :                          waittime,
     184                 :                          WAIT_EVENT_BACKEND_TERMINATION);
     185                 : 
     186 GIC           4 :         ResetLatch(MyLatch);
     187                 : 
     188               4 :         remainingtime -= waittime;
     189               4 :     } while (remainingtime > 0);
     190 ECB             : 
     191 UIC           0 :     ereport(WARNING,
     192 ECB             :             (errmsg_plural("backend with PID %d did not terminate within %lld millisecond",
     193                 :                            "backend with PID %d did not terminate within %lld milliseconds",
     194                 :                            timeout,
     195 EUB             :                            pid, (long long int) timeout)));
     196                 : 
     197 UIC           0 :     return false;
     198                 : }
     199                 : 
     200                 : /*
     201 EUB             :  * Send a signal to terminate a backend process. This is allowed if you are a
     202                 :  * member of the role whose process is being terminated. If the timeout input
     203                 :  * argument is 0, then this function just signals the backend and returns
     204                 :  * true.  If timeout is nonzero, then it waits until no process has the given
     205                 :  * PID; if the process ends within the timeout, true is returned, and if the
     206                 :  * timeout is exceeded, a warning is emitted and false is returned.
     207                 :  *
     208                 :  * Note that only superusers can signal superuser-owned processes.
     209                 :  */
     210                 : Datum
     211 GIC           6 : pg_terminate_backend(PG_FUNCTION_ARGS)
     212                 : {
     213                 :     int         pid;
     214                 :     int         r;
     215 ECB             :     int         timeout;        /* milliseconds */
     216                 : 
     217 GIC           6 :     pid = PG_GETARG_INT32(0);
     218               6 :     timeout = PG_GETARG_INT64(1);
     219                 : 
     220               6 :     if (timeout < 0)
     221 LBC           0 :         ereport(ERROR,
     222 ECB             :                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     223                 :                  errmsg("\"timeout\" must not be negative")));
     224                 : 
     225 GBC           6 :     r = pg_signal_backend(pid, SIGTERM);
     226                 : 
     227 GIC           6 :     if (r == SIGNAL_BACKEND_NOSUPERUSER)
     228 UIC           0 :         ereport(ERROR,
     229 ECB             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     230                 :                  errmsg("permission denied to terminate process"),
     231                 :                  errdetail("Only roles with the %s attribute may terminate processes of roles with %s.",
     232                 :                            "SUPERUSER", "SUPERUSER")));
     233                 : 
     234 GBC           6 :     if (r == SIGNAL_BACKEND_NOPERMISSION)
     235 UIC           0 :         ereport(ERROR,
     236                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     237                 :                  errmsg("permission denied to terminate process"),
     238                 :                  errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
     239                 :                            "pg_signal_backend")));
     240                 : 
     241                 :     /* Wait only on success and if actually requested */
     242 CBC           6 :     if (r == SIGNAL_BACKEND_SUCCESS && timeout > 0)
     243 GBC           2 :         PG_RETURN_BOOL(pg_wait_until_termination(pid, timeout));
     244                 :     else
     245 GIC           4 :         PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
     246                 : }
     247                 : 
     248                 : /*
     249                 :  * Signal to reload the database configuration
     250 ECB             :  *
     251                 :  * Permission checking for this function is managed through the normal
     252                 :  * GRANT system.
     253                 :  */
     254                 : Datum
     255 GIC          16 : pg_reload_conf(PG_FUNCTION_ARGS)
     256                 : {
     257              16 :     if (kill(PostmasterPid, SIGHUP))
     258                 :     {
     259 UIC           0 :         ereport(WARNING,
     260                 :                 (errmsg("failed to send signal to postmaster: %m")));
     261               0 :         PG_RETURN_BOOL(false);
     262                 :     }
     263 ECB             : 
     264 GIC          16 :     PG_RETURN_BOOL(true);
     265 ECB             : }
     266                 : 
     267 EUB             : 
     268                 : /*
     269                 :  * Rotate log file
     270                 :  *
     271                 :  * This function is kept to support adminpack 1.0.
     272 ECB             :  */
     273                 : Datum
     274 UIC           0 : pg_rotate_logfile(PG_FUNCTION_ARGS)
     275                 : {
     276               0 :     if (!superuser())
     277               0 :         ereport(ERROR,
     278                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     279                 :                  errmsg("must be superuser to rotate log files with adminpack 1.0"),
     280                 :         /* translator: %s is a SQL function name */
     281                 :                  errhint("Consider using %s, which is part of core, instead.",
     282 EUB             :                          "pg_logfile_rotate()")));
     283                 : 
     284 UBC           0 :     if (!Logging_collector)
     285 EUB             :     {
     286 UIC           0 :         ereport(WARNING,
     287                 :                 (errmsg("rotation not possible because log collection not active")));
     288               0 :         PG_RETURN_BOOL(false);
     289                 :     }
     290                 : 
     291               0 :     SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
     292 UBC           0 :     PG_RETURN_BOOL(true);
     293                 : }
     294 EUB             : 
     295                 : /*
     296                 :  * Rotate log file
     297                 :  *
     298                 :  * Permission checking for this function is managed through the normal
     299                 :  * GRANT system.
     300                 :  */
     301                 : Datum
     302 UIC           0 : pg_rotate_logfile_v2(PG_FUNCTION_ARGS)
     303                 : {
     304               0 :     if (!Logging_collector)
     305                 :     {
     306               0 :         ereport(WARNING,
     307                 :                 (errmsg("rotation not possible because log collection not active")));
     308               0 :         PG_RETURN_BOOL(false);
     309                 :     }
     310 EUB             : 
     311 UIC           0 :     SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
     312 UBC           0 :     PG_RETURN_BOOL(true);
     313                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a