LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - signalfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 3 47 6.4 %
Date: 2019-09-22 07:07:17 Functions: 1 6 16.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * signalfuncs.c
       4             :  *    Functions for signalling backends
       5             :  *
       6             :  * Portions Copyright (c) 1996-2019, 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 "postmaster/syslogger.h"
      22             : #include "storage/pmsignal.h"
      23             : #include "storage/proc.h"
      24             : #include "storage/procarray.h"
      25             : #include "utils/acl.h"
      26             : #include "utils/builtins.h"
      27             : 
      28             : 
      29             : /*
      30             :  * Send a signal to another backend.
      31             :  *
      32             :  * The signal is delivered if the user is either a superuser or the same
      33             :  * role as the backend being signaled. For "dangerous" signals, an explicit
      34             :  * check for superuser needs to be done prior to calling this function.
      35             :  *
      36             :  * Returns 0 on success, 1 on general failure, 2 on normal permission error
      37             :  * and 3 if the caller needs to be a superuser.
      38             :  *
      39             :  * In the event of a general failure (return code 1), a warning message will
      40             :  * be emitted. For permission errors, doing that is the responsibility of
      41             :  * the caller.
      42             :  */
      43             : #define SIGNAL_BACKEND_SUCCESS 0
      44             : #define SIGNAL_BACKEND_ERROR 1
      45             : #define SIGNAL_BACKEND_NOPERMISSION 2
      46             : #define SIGNAL_BACKEND_NOSUPERUSER 3
      47             : static int
      48           0 : pg_signal_backend(int pid, int sig)
      49             : {
      50           0 :     PGPROC     *proc = BackendPidGetProc(pid);
      51             : 
      52             :     /*
      53             :      * BackendPidGetProc returns NULL if the pid isn't valid; but by the time
      54             :      * we reach kill(), a process for which we get a valid proc here might
      55             :      * have terminated on its own.  There's no way to acquire a lock on an
      56             :      * arbitrary process to prevent that. But since so far all the callers of
      57             :      * this mechanism involve some request for ending the process anyway, that
      58             :      * it might end on its own first is not a problem.
      59             :      */
      60           0 :     if (proc == NULL)
      61             :     {
      62             :         /*
      63             :          * This is just a warning so a loop-through-resultset will not abort
      64             :          * if one backend terminated on its own during the run.
      65             :          */
      66           0 :         ereport(WARNING,
      67             :                 (errmsg("PID %d is not a PostgreSQL server process", pid)));
      68           0 :         return SIGNAL_BACKEND_ERROR;
      69             :     }
      70             : 
      71             :     /* Only allow superusers to signal superuser-owned backends. */
      72           0 :     if (superuser_arg(proc->roleId) && !superuser())
      73           0 :         return SIGNAL_BACKEND_NOSUPERUSER;
      74             : 
      75             :     /* Users can signal backends they have role membership in. */
      76           0 :     if (!has_privs_of_role(GetUserId(), proc->roleId) &&
      77           0 :         !has_privs_of_role(GetUserId(), DEFAULT_ROLE_SIGNAL_BACKENDID))
      78           0 :         return SIGNAL_BACKEND_NOPERMISSION;
      79             : 
      80             :     /*
      81             :      * Can the process we just validated above end, followed by the pid being
      82             :      * recycled for a new process, before reaching here?  Then we'd be trying
      83             :      * to kill the wrong thing.  Seems near impossible when sequential pid
      84             :      * assignment and wraparound is used.  Perhaps it could happen on a system
      85             :      * where pid re-use is randomized.  That race condition possibility seems
      86             :      * too unlikely to worry about.
      87             :      */
      88             : 
      89             :     /* If we have setsid(), signal the backend's whole process group */
      90             : #ifdef HAVE_SETSID
      91           0 :     if (kill(-pid, sig))
      92             : #else
      93             :     if (kill(pid, sig))
      94             : #endif
      95             :     {
      96             :         /* Again, just a warning to allow loops */
      97           0 :         ereport(WARNING,
      98             :                 (errmsg("could not send signal to process %d: %m", pid)));
      99           0 :         return SIGNAL_BACKEND_ERROR;
     100             :     }
     101           0 :     return SIGNAL_BACKEND_SUCCESS;
     102             : }
     103             : 
     104             : /*
     105             :  * Signal to cancel a backend process.  This is allowed if you are a member of
     106             :  * the role whose process is being canceled.
     107             :  *
     108             :  * Note that only superusers can signal superuser-owned processes.
     109             :  */
     110             : Datum
     111           0 : pg_cancel_backend(PG_FUNCTION_ARGS)
     112             : {
     113           0 :     int         r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
     114             : 
     115           0 :     if (r == SIGNAL_BACKEND_NOSUPERUSER)
     116           0 :         ereport(ERROR,
     117             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     118             :                  (errmsg("must be a superuser to cancel superuser query"))));
     119             : 
     120           0 :     if (r == SIGNAL_BACKEND_NOPERMISSION)
     121           0 :         ereport(ERROR,
     122             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     123             :                  (errmsg("must be a member of the role whose query is being canceled or member of pg_signal_backend"))));
     124             : 
     125           0 :     PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
     126             : }
     127             : 
     128             : /*
     129             :  * Signal to terminate a backend process.  This is allowed if you are a member
     130             :  * of the role whose process is being terminated.
     131             :  *
     132             :  * Note that only superusers can signal superuser-owned processes.
     133             :  */
     134             : Datum
     135           0 : pg_terminate_backend(PG_FUNCTION_ARGS)
     136             : {
     137           0 :     int         r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);
     138             : 
     139           0 :     if (r == SIGNAL_BACKEND_NOSUPERUSER)
     140           0 :         ereport(ERROR,
     141             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     142             :                  (errmsg("must be a superuser to terminate superuser process"))));
     143             : 
     144           0 :     if (r == SIGNAL_BACKEND_NOPERMISSION)
     145           0 :         ereport(ERROR,
     146             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     147             :                  (errmsg("must be a member of the role whose process is being terminated or member of pg_signal_backend"))));
     148             : 
     149           0 :     PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
     150             : }
     151             : 
     152             : /*
     153             :  * Signal to reload the database configuration
     154             :  *
     155             :  * Permission checking for this function is managed through the normal
     156             :  * GRANT system.
     157             :  */
     158             : Datum
     159          10 : pg_reload_conf(PG_FUNCTION_ARGS)
     160             : {
     161          10 :     if (kill(PostmasterPid, SIGHUP))
     162             :     {
     163           0 :         ereport(WARNING,
     164             :                 (errmsg("failed to send signal to postmaster: %m")));
     165           0 :         PG_RETURN_BOOL(false);
     166             :     }
     167             : 
     168          10 :     PG_RETURN_BOOL(true);
     169             : }
     170             : 
     171             : 
     172             : /*
     173             :  * Rotate log file
     174             :  *
     175             :  * This function is kept to support adminpack 1.0.
     176             :  */
     177             : Datum
     178           0 : pg_rotate_logfile(PG_FUNCTION_ARGS)
     179             : {
     180           0 :     if (!superuser())
     181           0 :         ereport(ERROR,
     182             :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     183             :                  (errmsg("must be superuser to rotate log files with adminpack 1.0"),
     184             :         /* translator: %s is a SQL function name */
     185             :                   errhint("Consider using %s, which is part of core, instead.",
     186             :                           "pg_logfile_rotate()"))));
     187             : 
     188           0 :     if (!Logging_collector)
     189             :     {
     190           0 :         ereport(WARNING,
     191             :                 (errmsg("rotation not possible because log collection not active")));
     192           0 :         PG_RETURN_BOOL(false);
     193             :     }
     194             : 
     195           0 :     SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
     196           0 :     PG_RETURN_BOOL(true);
     197             : }
     198             : 
     199             : /*
     200             :  * Rotate log file
     201             :  *
     202             :  * Permission checking for this function is managed through the normal
     203             :  * GRANT system.
     204             :  */
     205             : Datum
     206           0 : pg_rotate_logfile_v2(PG_FUNCTION_ARGS)
     207             : {
     208           0 :     if (!Logging_collector)
     209             :     {
     210           0 :         ereport(WARNING,
     211             :                 (errmsg("rotation not possible because log collection not active")));
     212           0 :         PG_RETURN_BOOL(false);
     213             :     }
     214             : 
     215           0 :     SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
     216           0 :     PG_RETURN_BOOL(true);
     217             : }

Generated by: LCOV version 1.13