Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * signalfuncs.c
4 : * Functions for signaling backends
5 : *
6 : * Portions Copyright (c) 1996-2024, 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 : * 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 110 : pg_signal_backend(int pid, int sig)
50 : {
51 110 : 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 110 : 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 18 : ereport(WARNING,
72 : (errmsg("PID %d is not a PostgreSQL backend process", pid)));
73 :
74 18 : return SIGNAL_BACKEND_ERROR;
75 : }
76 :
77 : /*
78 : * Only allow superusers to signal superuser-owned backends. Any process
79 : * not advertising a role might have the importance of a superuser-owned
80 : * backend, so treat it that way.
81 : */
82 92 : if ((!OidIsValid(proc->roleId) || superuser_arg(proc->roleId)) &&
83 92 : !superuser())
84 20 : return SIGNAL_BACKEND_NOSUPERUSER;
85 :
86 : /* Users can signal backends they have role membership in. */
87 72 : if (!has_privs_of_role(GetUserId(), proc->roleId) &&
88 0 : !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
89 0 : return SIGNAL_BACKEND_NOPERMISSION;
90 :
91 : /*
92 : * Can the process we just validated above end, followed by the pid being
93 : * recycled for a new process, before reaching here? Then we'd be trying
94 : * to kill the wrong thing. Seems near impossible when sequential pid
95 : * assignment and wraparound is used. Perhaps it could happen on a system
96 : * where pid re-use is randomized. That race condition possibility seems
97 : * too unlikely to worry about.
98 : */
99 :
100 : /* If we have setsid(), signal the backend's whole process group */
101 : #ifdef HAVE_SETSID
102 72 : if (kill(-pid, sig))
103 : #else
104 : if (kill(pid, sig))
105 : #endif
106 : {
107 : /* Again, just a warning to allow loops */
108 0 : ereport(WARNING,
109 : (errmsg("could not send signal to process %d: %m", pid)));
110 0 : return SIGNAL_BACKEND_ERROR;
111 : }
112 72 : return SIGNAL_BACKEND_SUCCESS;
113 : }
114 :
115 : /*
116 : * Signal to cancel a backend process. This is allowed if you are a member of
117 : * the role whose process is being canceled.
118 : *
119 : * Note that only superusers can signal superuser-owned processes.
120 : */
121 : Datum
122 60 : pg_cancel_backend(PG_FUNCTION_ARGS)
123 : {
124 60 : int r = pg_signal_backend(PG_GETARG_INT32(0), SIGINT);
125 :
126 60 : if (r == SIGNAL_BACKEND_NOSUPERUSER)
127 0 : ereport(ERROR,
128 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
129 : errmsg("permission denied to cancel query"),
130 : errdetail("Only roles with the %s attribute may cancel queries of roles with the %s attribute.",
131 : "SUPERUSER", "SUPERUSER")));
132 :
133 60 : if (r == SIGNAL_BACKEND_NOPERMISSION)
134 0 : ereport(ERROR,
135 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
136 : errmsg("permission denied to cancel query"),
137 : errdetail("Only roles with privileges of the role whose query is being canceled or with privileges of the \"%s\" role may cancel this query.",
138 : "pg_signal_backend")));
139 :
140 60 : PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
141 : }
142 :
143 : /*
144 : * Wait until there is no backend process with the given PID and return true.
145 : * On timeout, a warning is emitted and false is returned.
146 : */
147 : static bool
148 4 : pg_wait_until_termination(int pid, int64 timeout)
149 : {
150 : /*
151 : * Wait in steps of waittime milliseconds until this function exits or
152 : * timeout.
153 : */
154 4 : int64 waittime = 100;
155 :
156 : /*
157 : * Initially remaining time is the entire timeout specified by the user.
158 : */
159 4 : int64 remainingtime = timeout;
160 :
161 : /*
162 : * Check existence of the backend. If the backend still exists, then wait
163 : * for waittime milliseconds, again check for the existence. Repeat this
164 : * until timeout or an error occurs or a pending interrupt such as query
165 : * cancel gets processed.
166 : */
167 : do
168 : {
169 8 : if (remainingtime < waittime)
170 0 : waittime = remainingtime;
171 :
172 8 : if (kill(pid, 0) == -1)
173 : {
174 4 : if (errno == ESRCH)
175 4 : return true;
176 : else
177 0 : ereport(ERROR,
178 : (errcode(ERRCODE_INTERNAL_ERROR),
179 : errmsg("could not check the existence of the backend with PID %d: %m",
180 : pid)));
181 : }
182 :
183 : /* Process interrupts, if any, before waiting */
184 4 : CHECK_FOR_INTERRUPTS();
185 :
186 4 : (void) WaitLatch(MyLatch,
187 : WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
188 : waittime,
189 : WAIT_EVENT_BACKEND_TERMINATION);
190 :
191 4 : ResetLatch(MyLatch);
192 :
193 4 : remainingtime -= waittime;
194 4 : } while (remainingtime > 0);
195 :
196 0 : ereport(WARNING,
197 : (errmsg_plural("backend with PID %d did not terminate within %lld millisecond",
198 : "backend with PID %d did not terminate within %lld milliseconds",
199 : timeout,
200 : pid, (long long int) timeout)));
201 :
202 0 : return false;
203 : }
204 :
205 : /*
206 : * Send a signal to terminate a backend process. This is allowed if you are a
207 : * member of the role whose process is being terminated. If the timeout input
208 : * argument is 0, then this function just signals the backend and returns
209 : * true. If timeout is nonzero, then it waits until no process has the given
210 : * PID; if the process ends within the timeout, true is returned, and if the
211 : * timeout is exceeded, a warning is emitted and false is returned.
212 : *
213 : * Note that only superusers can signal superuser-owned processes.
214 : */
215 : Datum
216 50 : pg_terminate_backend(PG_FUNCTION_ARGS)
217 : {
218 : int pid;
219 : int r;
220 : int timeout; /* milliseconds */
221 :
222 50 : pid = PG_GETARG_INT32(0);
223 50 : timeout = PG_GETARG_INT64(1);
224 :
225 50 : if (timeout < 0)
226 0 : ereport(ERROR,
227 : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
228 : errmsg("\"timeout\" must not be negative")));
229 :
230 50 : r = pg_signal_backend(pid, SIGTERM);
231 :
232 50 : if (r == SIGNAL_BACKEND_NOSUPERUSER)
233 20 : ereport(ERROR,
234 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
235 : errmsg("permission denied to terminate process"),
236 : errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
237 : "SUPERUSER", "SUPERUSER")));
238 :
239 30 : if (r == SIGNAL_BACKEND_NOPERMISSION)
240 0 : ereport(ERROR,
241 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
242 : errmsg("permission denied to terminate process"),
243 : errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
244 : "pg_signal_backend")));
245 :
246 : /* Wait only on success and if actually requested */
247 30 : if (r == SIGNAL_BACKEND_SUCCESS && timeout > 0)
248 4 : PG_RETURN_BOOL(pg_wait_until_termination(pid, timeout));
249 : else
250 26 : PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
251 : }
252 :
253 : /*
254 : * Signal to reload the database configuration
255 : *
256 : * Permission checking for this function is managed through the normal
257 : * GRANT system.
258 : */
259 : Datum
260 34 : pg_reload_conf(PG_FUNCTION_ARGS)
261 : {
262 34 : if (kill(PostmasterPid, SIGHUP))
263 : {
264 0 : ereport(WARNING,
265 : (errmsg("failed to send signal to postmaster: %m")));
266 0 : PG_RETURN_BOOL(false);
267 : }
268 :
269 34 : PG_RETURN_BOOL(true);
270 : }
271 :
272 :
273 : /*
274 : * Rotate log file
275 : *
276 : * Permission checking for this function is managed through the normal
277 : * GRANT system.
278 : */
279 : Datum
280 0 : pg_rotate_logfile(PG_FUNCTION_ARGS)
281 : {
282 0 : if (!Logging_collector)
283 : {
284 0 : ereport(WARNING,
285 : (errmsg("rotation not possible because log collection not active")));
286 0 : PG_RETURN_BOOL(false);
287 : }
288 :
289 0 : SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
290 0 : PG_RETURN_BOOL(true);
291 : }
|