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