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