1 /*-------------------------------------------------------------------------
2  *
3  * signalfuncs.c
4  *	  Functions for signaling backends
5  *
6  * Portions Copyright (c) 1996-2020, 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
pg_signal_backend(int pid,int sig)48 pg_signal_backend(int pid, int sig)
49 {
50 	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 	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 		ereport(WARNING,
67 				(errmsg("PID %d is not a PostgreSQL server process", pid)));
68 		return SIGNAL_BACKEND_ERROR;
69 	}
70 
71 	/* Only allow superusers to signal superuser-owned backends. */
72 	if (superuser_arg(proc->roleId) && !superuser())
73 		return SIGNAL_BACKEND_NOSUPERUSER;
74 
75 	/* Users can signal backends they have role membership in. */
76 	if (!has_privs_of_role(GetUserId(), proc->roleId) &&
77 		!has_privs_of_role(GetUserId(), DEFAULT_ROLE_SIGNAL_BACKENDID))
78 		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 	if (kill(-pid, sig))
92 #else
93 	if (kill(pid, sig))
94 #endif
95 	{
96 		/* Again, just a warning to allow loops */
97 		ereport(WARNING,
98 				(errmsg("could not send signal to process %d: %m", pid)));
99 		return SIGNAL_BACKEND_ERROR;
100 	}
101 	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
pg_cancel_backend(PG_FUNCTION_ARGS)111 pg_cancel_backend(PG_FUNCTION_ARGS)
112 {
113 	int			r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
114 
115 	if (r == SIGNAL_BACKEND_NOSUPERUSER)
116 		ereport(ERROR,
117 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
118 				 errmsg("must be a superuser to cancel superuser query")));
119 
120 	if (r == SIGNAL_BACKEND_NOPERMISSION)
121 		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 	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
pg_terminate_backend(PG_FUNCTION_ARGS)135 pg_terminate_backend(PG_FUNCTION_ARGS)
136 {
137 	int			r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);
138 
139 	if (r == SIGNAL_BACKEND_NOSUPERUSER)
140 		ereport(ERROR,
141 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
142 				 errmsg("must be a superuser to terminate superuser process")));
143 
144 	if (r == SIGNAL_BACKEND_NOPERMISSION)
145 		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 	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
pg_reload_conf(PG_FUNCTION_ARGS)159 pg_reload_conf(PG_FUNCTION_ARGS)
160 {
161 	if (kill(PostmasterPid, SIGHUP))
162 	{
163 		ereport(WARNING,
164 				(errmsg("failed to send signal to postmaster: %m")));
165 		PG_RETURN_BOOL(false);
166 	}
167 
168 	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
pg_rotate_logfile(PG_FUNCTION_ARGS)178 pg_rotate_logfile(PG_FUNCTION_ARGS)
179 {
180 	if (!superuser())
181 		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 	if (!Logging_collector)
189 	{
190 		ereport(WARNING,
191 				(errmsg("rotation not possible because log collection not active")));
192 		PG_RETURN_BOOL(false);
193 	}
194 
195 	SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
196 	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
pg_rotate_logfile_v2(PG_FUNCTION_ARGS)206 pg_rotate_logfile_v2(PG_FUNCTION_ARGS)
207 {
208 	if (!Logging_collector)
209 	{
210 		ereport(WARNING,
211 				(errmsg("rotation not possible because log collection not active")));
212 		PG_RETURN_BOOL(false);
213 	}
214 
215 	SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
216 	PG_RETURN_BOOL(true);
217 }
218