1 /*
2 +----------------------------------------------------------------------+
3 | Zend Signal Handling |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | https://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Lucas Nealan <lucas@php.net> |
16 | Arnaud Le Blanc <lbarnaud@php.net> |
17 +----------------------------------------------------------------------+
18
19 This software was contributed to PHP by Facebook Inc. in 2008.
20
21 Future revisions and derivatives of this source code must acknowledge
22 Facebook Inc. as the original contributor of this module by leaving
23 this note intact in the source code.
24
25 All other licensing and usage conditions are those of the PHP Group.
26 */
27
28 #define _GNU_SOURCE
29 #include <string.h>
30
31 #include "zend.h"
32 #include "zend_globals.h"
33 #include <signal.h>
34
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 #ifdef ZEND_SIGNALS
40
41 #include "zend_signal.h"
42
43 #ifdef ZTS
44 ZEND_API int zend_signal_globals_id;
45 ZEND_API size_t zend_signal_globals_offset;
46 #else
47 ZEND_API zend_signal_globals_t zend_signal_globals;
48 #endif /* not ZTS */
49
50 #define SIGNAL_BEGIN_CRITICAL() \
51 sigset_t oldmask; \
52 zend_sigprocmask(SIG_BLOCK, &global_sigmask, &oldmask);
53 #define SIGNAL_END_CRITICAL() \
54 zend_sigprocmask(SIG_SETMASK, &oldmask, NULL);
55
56 #ifdef ZTS
57 # define zend_sigprocmask(signo, set, oldset) tsrm_sigmask((signo), (set), (oldset))
58 #else
59 # define zend_sigprocmask(signo, set, oldset) sigprocmask((signo), (set), (oldset))
60 #endif
61
62 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context);
63 static int zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*));
64
65 #if defined(__CYGWIN__) || defined(__PASE__)
66 /* Matches zend_execute_API.c; these platforms don't support ITIMER_PROF. */
67 #define TIMEOUT_SIG SIGALRM
68 #else
69 #define TIMEOUT_SIG SIGPROF
70 #endif
71
72 static int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 };
73
74 #define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND)
75
76 /* True globals, written only at process startup */
77 static zend_signal_entry_t global_orig_handlers[NSIG];
78 static sigset_t global_sigmask;
79
80 /* {{{ zend_signal_handler_defer
81 * Blocks signals if in critical section */
zend_signal_handler_defer(int signo,siginfo_t * siginfo,void * context)82 void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context)
83 {
84 int errno_save = errno;
85 zend_signal_queue_t *queue, *qtmp;
86
87 #ifdef ZTS
88 /* A signal could hit after TSRM shutdown, in this case globals are already freed.
89 * Or it could be delivered to a thread that didn't execute PHP yet.
90 * In the latter case we act as if SIGG(active) is false. */
91 if (tsrm_is_shutdown() || !tsrm_get_ls_cache()) {
92 /* Forward to default handler handler */
93 zend_signal_handler(signo, siginfo, context);
94 return;
95 }
96 #endif
97
98 if (EXPECTED(SIGG(active))) {
99 if (UNEXPECTED(SIGG(depth) == 0)) { /* try to handle signal */
100 if (UNEXPECTED(SIGG(blocked))) {
101 SIGG(blocked) = 0;
102 }
103 if (EXPECTED(SIGG(running) == 0)) {
104 SIGG(running) = 1;
105 zend_signal_handler(signo, siginfo, context);
106
107 queue = SIGG(phead);
108 SIGG(phead) = NULL;
109
110 while (queue) {
111 zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context);
112 qtmp = queue->next;
113 queue->next = SIGG(pavail);
114 queue->zend_signal.signo = 0;
115 SIGG(pavail) = queue;
116 queue = qtmp;
117 }
118 SIGG(running) = 0;
119 }
120 } else { /* delay signal handling */
121 SIGG(blocked) = 1; /* signal is blocked */
122
123 if ((queue = SIGG(pavail))) { /* if none available it's simply forgotten */
124 SIGG(pavail) = queue->next;
125 queue->zend_signal.signo = signo;
126 queue->zend_signal.siginfo = siginfo;
127 queue->zend_signal.context = context;
128 queue->next = NULL;
129
130 if (SIGG(phead) && SIGG(ptail)) {
131 SIGG(ptail)->next = queue;
132 } else {
133 SIGG(phead) = queue;
134 }
135 SIGG(ptail) = queue;
136 }
137 #if ZEND_DEBUG
138 else { /* this may not be safe to do, but could work and be useful */
139 zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo);
140 }
141 #endif
142 }
143 } else {
144 /* need to just run handler if we're inactive and getting a signal */
145 zend_signal_handler(signo, siginfo, context);
146 }
147
148 errno = errno_save;
149 } /* }}} */
150
151 /* {{{ zend_signal_handler_unblock
152 * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */
zend_signal_handler_unblock(void)153 ZEND_API void zend_signal_handler_unblock(void)
154 {
155 zend_signal_queue_t *queue;
156 zend_signal_t zend_signal;
157
158 if (EXPECTED(SIGG(active))) {
159 SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */
160 queue = SIGG(phead);
161 SIGG(phead) = queue->next;
162 zend_signal = queue->zend_signal;
163 queue->next = SIGG(pavail);
164 queue->zend_signal.signo = 0;
165 SIGG(pavail) = queue;
166
167 zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context);
168 SIGNAL_END_CRITICAL();
169 }
170 }
171 /* }}} */
172
173 /* {{{ zend_signal_handler
174 * Call the previously registered handler for a signal
175 */
zend_signal_handler(int signo,siginfo_t * siginfo,void * context)176 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context)
177 {
178 int errno_save = errno;
179 struct sigaction sa;
180 sigset_t sigset;
181 zend_signal_entry_t p_sig;
182 #ifdef ZTS
183 if (tsrm_is_shutdown() || !tsrm_get_ls_cache()) {
184 p_sig.flags = 0;
185 p_sig.handler = SIG_DFL;
186 } else
187 #endif
188 p_sig = SIGG(handlers)[signo-1];
189
190 if (p_sig.handler == SIG_DFL) { /* raise default handler */
191 if (sigaction(signo, NULL, &sa) == 0) {
192 sa.sa_handler = SIG_DFL;
193 sigemptyset(&sa.sa_mask);
194
195 sigemptyset(&sigset);
196 sigaddset(&sigset, signo);
197
198 if (sigaction(signo, &sa, NULL) == 0) {
199 /* throw away any blocked signals */
200 zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
201 #ifdef ZTS
202 # define RAISE_ERROR "raise() failed\n"
203 if (raise(signo) != 0) {
204 /* On some systems raise() fails with errno 3: No such process */
205 kill(getpid(), signo);
206 }
207 #else
208 kill(getpid(), signo);
209 #endif
210 }
211 }
212 } else if (p_sig.handler != SIG_IGN) {
213 if (p_sig.flags & SA_SIGINFO) {
214 if (p_sig.flags & SA_RESETHAND) {
215 SIGG(handlers)[signo-1].flags = 0;
216 SIGG(handlers)[signo-1].handler = SIG_DFL;
217 }
218 (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context);
219 } else {
220 (*(void (*)(int))p_sig.handler)(signo);
221 }
222 }
223
224 errno = errno_save;
225 } /* }}} */
226
227 /* {{{ zend_sigaction
228 * Register a signal handler that will be deferred in critical sections */
zend_sigaction(int signo,const struct sigaction * act,struct sigaction * oldact)229 ZEND_API void zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact)
230 {
231 struct sigaction sa;
232 sigset_t sigset;
233
234 if (oldact != NULL) {
235 oldact->sa_flags = SIGG(handlers)[signo-1].flags;
236 oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler;
237 oldact->sa_mask = global_sigmask;
238 }
239 if (act != NULL) {
240 SIGG(handlers)[signo-1].flags = act->sa_flags;
241 if (act->sa_flags & SA_SIGINFO) {
242 SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction;
243 } else {
244 SIGG(handlers)[signo-1].handler = (void *) act->sa_handler;
245 }
246
247 memset(&sa, 0, sizeof(sa));
248 if (SIGG(handlers)[signo-1].handler == (void *) SIG_IGN) {
249 sa.sa_sigaction = (void *) SIG_IGN;
250 } else {
251 sa.sa_flags = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK);
252 sa.sa_sigaction = zend_signal_handler_defer;
253 sa.sa_mask = global_sigmask;
254 }
255
256 if (sigaction(signo, &sa, NULL) < 0) {
257 zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo);
258 }
259
260 /* unsure this signal is not blocked */
261 sigemptyset(&sigset);
262 sigaddset(&sigset, signo);
263 zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
264 }
265 }
266 /* }}} */
267
268 /* {{{ zend_signal
269 * Register a signal handler that will be deferred in critical sections */
zend_signal(int signo,void (* handler)(int))270 ZEND_API void zend_signal(int signo, void (*handler)(int))
271 {
272 struct sigaction sa;
273
274 memset(&sa, 0, sizeof(sa));
275 sa.sa_flags = 0;
276 sa.sa_handler = handler;
277 sa.sa_mask = global_sigmask;
278
279 zend_sigaction(signo, &sa, NULL);
280 }
281 /* }}} */
282
283 /* {{{ zend_signal_register
284 * Set a handler for a signal we want to defer.
285 * Previously set handler must have been saved before.
286 */
zend_signal_register(int signo,void (* handler)(int,siginfo_t *,void *))287 static zend_result zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*))
288 {
289 struct sigaction sa;
290
291 if (sigaction(signo, NULL, &sa) == 0) {
292 if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction == handler) {
293 return FAILURE;
294 }
295
296 SIGG(handlers)[signo-1].flags = sa.sa_flags;
297 if (sa.sa_flags & SA_SIGINFO) {
298 SIGG(handlers)[signo-1].handler = (void *)sa.sa_sigaction;
299 } else {
300 SIGG(handlers)[signo-1].handler = (void *)sa.sa_handler;
301 }
302
303 sa.sa_flags = SA_SIGINFO; /* we'll use a siginfo handler */
304 sa.sa_sigaction = handler;
305 sa.sa_mask = global_sigmask;
306
307 if (sigaction(signo, &sa, NULL) < 0) {
308 zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo);
309 }
310
311 return SUCCESS;
312 }
313 return FAILURE;
314 } /* }}} */
315
316 /* {{{ zend_signal_activate
317 * Install our signal handlers, per request */
zend_signal_activate(void)318 void zend_signal_activate(void)
319 {
320 size_t x;
321
322 memcpy(&SIGG(handlers), &global_orig_handlers, sizeof(global_orig_handlers));
323
324 if (SIGG(reset)) {
325 for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
326 zend_signal_register(zend_sigs[x], zend_signal_handler_defer);
327 }
328 }
329
330 SIGG(active) = 1;
331 SIGG(depth) = 0;
332 } /* }}} */
333
334 /* {{{ zend_signal_deactivate */
zend_signal_deactivate(void)335 void zend_signal_deactivate(void)
336 {
337 if (SIGG(check)) {
338 size_t x;
339 struct sigaction sa;
340
341 if (SIGG(depth) != 0) {
342 zend_error(E_CORE_WARNING, "zend_signal: shutdown with non-zero blocking depth (%d)", SIGG(depth));
343 }
344
345 /* did anyone steal our installed handler */
346 for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
347 sigaction(zend_sigs[x], NULL, &sa);
348 if (sa.sa_sigaction != zend_signal_handler_defer &&
349 sa.sa_sigaction != (void *) SIG_IGN) {
350 zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]);
351 }
352 }
353 }
354
355 /* After active=0 is set, signal handlers will be called directly and other
356 * state that is reset below will not be accessed. */
357 *((volatile int *) &SIGG(active)) = 0;
358
359 SIGG(running) = 0;
360 SIGG(blocked) = 0;
361 SIGG(depth) = 0;
362
363 /* If there are any queued signals because of a missed unblock, drop them. */
364 if (SIGG(phead) && SIGG(ptail)) {
365 SIGG(ptail)->next = SIGG(pavail);
366 SIGG(pavail) = SIGG(phead);
367 SIGG(phead) = NULL;
368 SIGG(ptail) = NULL;
369 }
370 }
371 /* }}} */
372
zend_signal_globals_ctor(zend_signal_globals_t * zend_signal_globals)373 static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals) /* {{{ */
374 {
375 size_t x;
376
377 memset(zend_signal_globals, 0, sizeof(*zend_signal_globals));
378 zend_signal_globals->reset = 1;
379
380 for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) {
381 zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x];
382 queue->zend_signal.signo = 0;
383 queue->next = zend_signal_globals->pavail;
384 zend_signal_globals->pavail = queue;
385 }
386 }
387 /* }}} */
388
zend_signal_init(void)389 void zend_signal_init(void) /* {{{ */
390 {
391 int signo;
392 struct sigaction sa;
393
394 /* Save previously registered signal handlers into orig_handlers */
395 memset(&global_orig_handlers, 0, sizeof(global_orig_handlers));
396 for (signo = 1; signo < NSIG; ++signo) {
397 if (sigaction(signo, NULL, &sa) == 0) {
398 global_orig_handlers[signo-1].flags = sa.sa_flags;
399 if (sa.sa_flags & SA_SIGINFO) {
400 global_orig_handlers[signo-1].handler = (void *) sa.sa_sigaction;
401 } else {
402 global_orig_handlers[signo-1].handler = (void *) sa.sa_handler;
403 }
404 }
405 }
406 }
407 /* }}} */
408
409 /* {{{ zend_signal_startup
410 * alloc zend signal globals */
zend_signal_startup(void)411 ZEND_API void zend_signal_startup(void)
412 {
413
414 #ifdef ZTS
415 ts_allocate_fast_id(&zend_signal_globals_id, &zend_signal_globals_offset, sizeof(zend_signal_globals_t), (ts_allocate_ctor) zend_signal_globals_ctor, NULL);
416 #else
417 zend_signal_globals_ctor(&zend_signal_globals);
418 #endif
419
420 /* Used to block signals during execution of signal handlers */
421 sigfillset(&global_sigmask);
422 sigdelset(&global_sigmask, SIGILL);
423 sigdelset(&global_sigmask, SIGABRT);
424 sigdelset(&global_sigmask, SIGFPE);
425 sigdelset(&global_sigmask, SIGKILL);
426 sigdelset(&global_sigmask, SIGSEGV);
427 sigdelset(&global_sigmask, SIGCONT);
428 sigdelset(&global_sigmask, SIGSTOP);
429 sigdelset(&global_sigmask, SIGTSTP);
430 sigdelset(&global_sigmask, SIGTTIN);
431 sigdelset(&global_sigmask, SIGTTOU);
432 #ifdef SIGBUS
433 sigdelset(&global_sigmask, SIGBUS);
434 #endif
435 #ifdef SIGSYS
436 sigdelset(&global_sigmask, SIGSYS);
437 #endif
438 #ifdef SIGTRAP
439 sigdelset(&global_sigmask, SIGTRAP);
440 #endif
441
442 zend_signal_init();
443 }
444 /* }}} */
445
446
447 #endif /* ZEND_SIGNALS */
448