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 | 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 #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_excute_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 if (tsrm_is_shutdown()) {
90 /* Forward to default handler handler */
91 zend_signal_handler(signo, siginfo, context);
92 return;
93 }
94 #endif
95
96 if (EXPECTED(SIGG(active))) {
97 if (UNEXPECTED(SIGG(depth) == 0)) { /* try to handle signal */
98 if (UNEXPECTED(SIGG(blocked))) {
99 SIGG(blocked) = 0;
100 }
101 if (EXPECTED(SIGG(running) == 0)) {
102 SIGG(running) = 1;
103 zend_signal_handler(signo, siginfo, context);
104
105 queue = SIGG(phead);
106 SIGG(phead) = NULL;
107
108 while (queue) {
109 zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context);
110 qtmp = queue->next;
111 queue->next = SIGG(pavail);
112 queue->zend_signal.signo = 0;
113 SIGG(pavail) = queue;
114 queue = qtmp;
115 }
116 SIGG(running) = 0;
117 }
118 } else { /* delay signal handling */
119 SIGG(blocked) = 1; /* signal is blocked */
120
121 if ((queue = SIGG(pavail))) { /* if none available it's simply forgotton */
122 SIGG(pavail) = queue->next;
123 queue->zend_signal.signo = signo;
124 queue->zend_signal.siginfo = siginfo;
125 queue->zend_signal.context = context;
126 queue->next = NULL;
127
128 if (SIGG(phead) && SIGG(ptail)) {
129 SIGG(ptail)->next = queue;
130 } else {
131 SIGG(phead) = queue;
132 }
133 SIGG(ptail) = queue;
134 }
135 #if ZEND_DEBUG
136 else { /* this may not be safe to do, but could work and be useful */
137 zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo);
138 }
139 #endif
140 }
141 } else {
142 /* need to just run handler if we're inactive and getting a signal */
143 zend_signal_handler(signo, siginfo, context);
144 }
145
146 errno = errno_save;
147 } /* }}} */
148
149 /* {{{ zend_signal_handler_unblock
150 * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */
zend_signal_handler_unblock(void)151 ZEND_API void zend_signal_handler_unblock(void)
152 {
153 zend_signal_queue_t *queue;
154 zend_signal_t zend_signal;
155
156 if (EXPECTED(SIGG(active))) {
157 SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */
158 queue = SIGG(phead);
159 SIGG(phead) = queue->next;
160 zend_signal = queue->zend_signal;
161 queue->next = SIGG(pavail);
162 queue->zend_signal.signo = 0;
163 SIGG(pavail) = queue;
164
165 zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context);
166 SIGNAL_END_CRITICAL();
167 }
168 }
169 /* }}} */
170
171 /* {{{ zend_signal_handler
172 * Call the previously registered handler for a signal
173 */
zend_signal_handler(int signo,siginfo_t * siginfo,void * context)174 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context)
175 {
176 int errno_save = errno;
177 struct sigaction sa;
178 sigset_t sigset;
179 zend_signal_entry_t p_sig;
180 #ifdef ZTS
181 if (tsrm_is_shutdown()) {
182 p_sig.flags = 0;
183 p_sig.handler = SIG_DFL;
184 } else
185 #endif
186 p_sig = SIGG(handlers)[signo-1];
187
188 if (p_sig.handler == SIG_DFL) { /* raise default handler */
189 if (sigaction(signo, NULL, &sa) == 0) {
190 sa.sa_handler = SIG_DFL;
191 sigemptyset(&sa.sa_mask);
192
193 sigemptyset(&sigset);
194 sigaddset(&sigset, signo);
195
196 if (sigaction(signo, &sa, NULL) == 0) {
197 /* throw away any blocked signals */
198 zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
199 #ifdef ZTS
200 # define RAISE_ERROR "raise() failed\n"
201 if (raise(signo) != 0) {
202 /* On some systems raise() fails with errno 3: No such process */
203 kill(getpid(), signo);
204 }
205 #else
206 kill(getpid(), signo);
207 #endif
208 }
209 }
210 } else if (p_sig.handler != SIG_IGN) {
211 if (p_sig.flags & SA_SIGINFO) {
212 if (p_sig.flags & SA_RESETHAND) {
213 SIGG(handlers)[signo-1].flags = 0;
214 SIGG(handlers)[signo-1].handler = SIG_DFL;
215 }
216 (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context);
217 } else {
218 (*(void (*)(int))p_sig.handler)(signo);
219 }
220 }
221
222 errno = errno_save;
223 } /* }}} */
224
225 /* {{{ zend_sigaction
226 * Register a signal handler that will be deferred in critical sections */
zend_sigaction(int signo,const struct sigaction * act,struct sigaction * oldact)227 ZEND_API int zend_sigaction(int signo, const struct sigaction *act, struct sigaction *oldact)
228 {
229 struct sigaction sa;
230 sigset_t sigset;
231
232 if (oldact != NULL) {
233 oldact->sa_flags = SIGG(handlers)[signo-1].flags;
234 oldact->sa_handler = (void *) SIGG(handlers)[signo-1].handler;
235 oldact->sa_mask = global_sigmask;
236 }
237 if (act != NULL) {
238 SIGG(handlers)[signo-1].flags = act->sa_flags;
239 if (act->sa_flags & SA_SIGINFO) {
240 SIGG(handlers)[signo-1].handler = (void *) act->sa_sigaction;
241 } else {
242 SIGG(handlers)[signo-1].handler = (void *) act->sa_handler;
243 }
244
245 memset(&sa, 0, sizeof(sa));
246 if (SIGG(handlers)[signo-1].handler == (void *) SIG_IGN) {
247 sa.sa_sigaction = (void *) SIG_IGN;
248 } else {
249 sa.sa_flags = SA_SIGINFO | (act->sa_flags & SA_FLAGS_MASK);
250 sa.sa_sigaction = zend_signal_handler_defer;
251 sa.sa_mask = global_sigmask;
252 }
253
254 if (sigaction(signo, &sa, NULL) < 0) {
255 zend_error_noreturn(E_ERROR, "Error installing signal handler for %d", signo);
256 }
257
258 /* unsure this signal is not blocked */
259 sigemptyset(&sigset);
260 sigaddset(&sigset, signo);
261 zend_sigprocmask(SIG_UNBLOCK, &sigset, NULL);
262 }
263
264 return SUCCESS;
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 int 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 return 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 int 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
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 zend_signal_globals->reset = 1;
380
381 for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) {
382 zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x];
383 queue->zend_signal.signo = 0;
384 queue->next = zend_signal_globals->pavail;
385 zend_signal_globals->pavail = queue;
386 }
387 }
388 /* }}} */
389
zend_signal_init(void)390 void zend_signal_init(void) /* {{{ */
391 {
392 int signo;
393 struct sigaction sa;
394
395 /* Save previously registered signal handlers into orig_handlers */
396 memset(&global_orig_handlers, 0, sizeof(global_orig_handlers));
397 for (signo = 1; signo < NSIG; ++signo) {
398 if (sigaction(signo, NULL, &sa) == 0) {
399 global_orig_handlers[signo-1].flags = sa.sa_flags;
400 if (sa.sa_flags & SA_SIGINFO) {
401 global_orig_handlers[signo-1].handler = (void *) sa.sa_sigaction;
402 } else {
403 global_orig_handlers[signo-1].handler = (void *) sa.sa_handler;
404 }
405 }
406 }
407 }
408 /* }}} */
409
410 /* {{{ zend_signal_startup
411 * alloc zend signal globals */
zend_signal_startup(void)412 ZEND_API void zend_signal_startup(void)
413 {
414
415 #ifdef ZTS
416 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);
417 #else
418 zend_signal_globals_ctor(&zend_signal_globals);
419 #endif
420
421 /* Used to block signals during execution of signal handlers */
422 sigfillset(&global_sigmask);
423 sigdelset(&global_sigmask, SIGILL);
424 sigdelset(&global_sigmask, SIGABRT);
425 sigdelset(&global_sigmask, SIGFPE);
426 sigdelset(&global_sigmask, SIGKILL);
427 sigdelset(&global_sigmask, SIGSEGV);
428 sigdelset(&global_sigmask, SIGCONT);
429 sigdelset(&global_sigmask, SIGSTOP);
430 sigdelset(&global_sigmask, SIGTSTP);
431 sigdelset(&global_sigmask, SIGTTIN);
432 sigdelset(&global_sigmask, SIGTTOU);
433 #ifdef SIGBUS
434 sigdelset(&global_sigmask, SIGBUS);
435 #endif
436 #ifdef SIGSYS
437 sigdelset(&global_sigmask, SIGSYS);
438 #endif
439 #ifdef SIGTRAP
440 sigdelset(&global_sigmask, SIGTRAP);
441 #endif
442
443 zend_signal_init();
444 }
445 /* }}} */
446
447
448 #endif /* ZEND_SIGNALS */
449