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 } /* }}} */
334
335 /* {{{ zend_signal_deactivate
336 * */
zend_signal_deactivate(void)337 void zend_signal_deactivate(void)
338 {
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 /* did anyone steal our installed handler */
348 for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
349 sigaction(zend_sigs[x], NULL, &sa);
350 if (sa.sa_sigaction != zend_signal_handler_defer) {
351 zend_error(E_CORE_WARNING, "zend_signal: handler was replaced for signal (%d) after startup", zend_sigs[x]);
352 }
353 }
354 }
355
356 SIGNAL_BEGIN_CRITICAL();
357 SIGG(active) = 0;
358 SIGG(running) = 0;
359 SIGG(blocked) = 0;
360 SIGG(depth) = 0;
361 SIGNAL_END_CRITICAL();
362 }
363 /* }}} */
364
zend_signal_globals_ctor(zend_signal_globals_t * zend_signal_globals)365 static void zend_signal_globals_ctor(zend_signal_globals_t *zend_signal_globals) /* {{{ */
366 {
367 size_t x;
368
369 memset(zend_signal_globals, 0, sizeof(*zend_signal_globals));
370
371 for (x = 0; x < sizeof(zend_signal_globals->pstorage) / sizeof(*zend_signal_globals->pstorage); ++x) {
372 zend_signal_queue_t *queue = &zend_signal_globals->pstorage[x];
373 queue->zend_signal.signo = 0;
374 queue->next = zend_signal_globals->pavail;
375 zend_signal_globals->pavail = queue;
376 }
377 }
378 /* }}} */
379
zend_signal_init(void)380 void zend_signal_init(void) /* {{{ */
381 {
382 int signo;
383 struct sigaction sa;
384
385 /* Save previously registered signal handlers into orig_handlers */
386 memset(&global_orig_handlers, 0, sizeof(global_orig_handlers));
387 for (signo = 1; signo < NSIG; ++signo) {
388 if (sigaction(signo, NULL, &sa) == 0) {
389 global_orig_handlers[signo-1].flags = sa.sa_flags;
390 if (sa.sa_flags & SA_SIGINFO) {
391 global_orig_handlers[signo-1].handler = (void *) sa.sa_sigaction;
392 } else {
393 global_orig_handlers[signo-1].handler = (void *) sa.sa_handler;
394 }
395 }
396 }
397 }
398 /* }}} */
399
400 /* {{{ zend_signal_startup
401 * alloc zend signal globals */
zend_signal_startup(void)402 ZEND_API void zend_signal_startup(void)
403 {
404
405 #ifdef ZTS
406 ts_allocate_id(&zend_signal_globals_id, sizeof(zend_signal_globals_t), (ts_allocate_ctor) zend_signal_globals_ctor, NULL);
407 #else
408 zend_signal_globals_ctor(&zend_signal_globals);
409 #endif
410
411 /* Used to block signals during execution of signal handlers */
412 sigfillset(&global_sigmask);
413 sigdelset(&global_sigmask, SIGILL);
414 sigdelset(&global_sigmask, SIGABRT);
415 sigdelset(&global_sigmask, SIGFPE);
416 sigdelset(&global_sigmask, SIGKILL);
417 sigdelset(&global_sigmask, SIGSEGV);
418 sigdelset(&global_sigmask, SIGCONT);
419 sigdelset(&global_sigmask, SIGSTOP);
420 sigdelset(&global_sigmask, SIGTSTP);
421 sigdelset(&global_sigmask, SIGTTIN);
422 sigdelset(&global_sigmask, SIGTTOU);
423 #ifdef SIGBUS
424 sigdelset(&global_sigmask, SIGBUS);
425 #endif
426 #ifdef SIGSYS
427 sigdelset(&global_sigmask, SIGSYS);
428 #endif
429 #ifdef SIGTRAP
430 sigdelset(&global_sigmask, SIGTRAP);
431 #endif
432
433 zend_signal_init();
434 }
435 /* }}} */
436
437
438 #endif /* ZEND_SIGNALS */
439
440 /*
441 * Local variables:
442 * tab-width: 4
443 * c-basic-offset: 4
444 * indent-tabs-mode: t
445 * End:
446 * vim600: fdm=marker
447 * vim: noet sw=4 ts=4
448 */
449