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