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 | 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 |
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 |
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 |
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 |
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 |
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 | |