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 #ifndef _GNU_SOURCE
29 # define _GNU_SOURCE
30 #endif
31 #include <string.h>
32
33 #include "zend.h"
34 #include "zend_globals.h"
35 #include <signal.h>
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #ifdef ZEND_SIGNALS
42
43 #include "zend_signal.h"
44
45 #ifdef ZTS
46 ZEND_API int zend_signal_globals_id;
47 ZEND_API size_t zend_signal_globals_offset;
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 zend_result zend_signal_register(int signo, void (*handler)(int, siginfo_t*, void*));
66
67 #if defined(__CYGWIN__) || defined(__PASE__)
68 /* Matches zend_execute_API.c; these platforms don't support ITIMER_PROF. */
69 #define TIMEOUT_SIG SIGALRM
70 #else
71 #define TIMEOUT_SIG SIGPROF
72 #endif
73
74 static const int zend_sigs[] = { TIMEOUT_SIG, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2 };
75
76 #define SA_FLAGS_MASK ~(SA_NODEFER | SA_RESETHAND)
77
78 /* True globals, written only at process startup */
79 static zend_signal_entry_t global_orig_handlers[NSIG];
80 static sigset_t global_sigmask;
81
82 /* {{{ zend_signal_handler_defer
83 * Blocks signals if in critical section */
zend_signal_handler_defer(int signo,siginfo_t * siginfo,void * context)84 static void zend_signal_handler_defer(int signo, siginfo_t *siginfo, void *context)
85 {
86 int errno_save = errno;
87 zend_signal_queue_t *queue, *qtmp;
88
89 #ifdef ZTS
90 /* A signal could hit after TSRM shutdown, in this case globals are already freed.
91 * Or it could be delivered to a thread that didn't execute PHP yet.
92 * In the latter case we act as if SIGG(active) is false. */
93 if (tsrm_is_shutdown() || !tsrm_is_managed_thread()) {
94 /* Forward to default handler handler */
95 zend_signal_handler(signo, siginfo, context);
96 return;
97 }
98 #endif
99
100 if (EXPECTED(SIGG(active))) {
101 if (UNEXPECTED(SIGG(depth) == 0)) { /* try to handle signal */
102 if (UNEXPECTED(SIGG(blocked))) {
103 SIGG(blocked) = 0;
104 }
105 if (EXPECTED(SIGG(running) == 0)) {
106 SIGG(running) = 1;
107 zend_signal_handler(signo, siginfo, context);
108
109 queue = SIGG(phead);
110 SIGG(phead) = NULL;
111
112 while (queue) {
113 zend_signal_handler(queue->zend_signal.signo, queue->zend_signal.siginfo, queue->zend_signal.context);
114 qtmp = queue->next;
115 queue->next = SIGG(pavail);
116 queue->zend_signal.signo = 0;
117 SIGG(pavail) = queue;
118 queue = qtmp;
119 }
120 SIGG(running) = 0;
121 }
122 } else { /* delay signal handling */
123 SIGG(blocked) = 1; /* signal is blocked */
124
125 if ((queue = SIGG(pavail))) { /* if none available it's simply forgotten */
126 SIGG(pavail) = queue->next;
127 queue->zend_signal.signo = signo;
128 queue->zend_signal.siginfo = siginfo;
129 queue->zend_signal.context = context;
130 queue->next = NULL;
131
132 if (SIGG(phead) && SIGG(ptail)) {
133 SIGG(ptail)->next = queue;
134 } else {
135 SIGG(phead) = queue;
136 }
137 SIGG(ptail) = queue;
138 }
139 #if ZEND_DEBUG
140 else { /* this may not be safe to do, but could work and be useful */
141 zend_output_debug_string(0, "zend_signal: not enough queue storage, lost signal (%d)", signo);
142 }
143 #endif
144 }
145 } else {
146 /* need to just run handler if we're inactive and getting a signal */
147 zend_signal_handler(signo, siginfo, context);
148 }
149
150 errno = errno_save;
151 } /* }}} */
152
153 /* {{{ zend_signal_handler_unblock
154 * Handle deferred signal from HANDLE_UNBLOCK_ALARMS */
zend_signal_handler_unblock(void)155 ZEND_API void zend_signal_handler_unblock(void)
156 {
157 zend_signal_queue_t *queue;
158 zend_signal_t zend_signal;
159
160 if (EXPECTED(SIGG(active))) {
161 SIGNAL_BEGIN_CRITICAL(); /* procmask to protect handler_defer as if it were called by the kernel */
162 queue = SIGG(phead);
163 SIGG(phead) = queue->next;
164 zend_signal = queue->zend_signal;
165 queue->next = SIGG(pavail);
166 queue->zend_signal.signo = 0;
167 SIGG(pavail) = queue;
168
169 zend_signal_handler_defer(zend_signal.signo, zend_signal.siginfo, zend_signal.context);
170 SIGNAL_END_CRITICAL();
171 }
172 }
173 /* }}} */
174
175 /* {{{ zend_signal_handler
176 * Call the previously registered handler for a signal
177 */
zend_signal_handler(int signo,siginfo_t * siginfo,void * context)178 static void zend_signal_handler(int signo, siginfo_t *siginfo, void *context)
179 {
180 int errno_save = errno;
181 struct sigaction sa;
182 sigset_t sigset;
183 zend_signal_entry_t p_sig;
184 #ifdef ZTS
185 if (tsrm_is_shutdown() || !tsrm_is_managed_thread()) {
186 p_sig = global_orig_handlers[signo-1];
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 void 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_ONSTACK | 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 /* }}} */
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 void 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 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 zend_result 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 if (SIGG(reset)) {
326 for (x = 0; x < sizeof(zend_sigs) / sizeof(*zend_sigs); x++) {
327 zend_signal_register(zend_sigs[x], zend_signal_handler_defer);
328 }
329 }
330
331 SIGG(active) = 1;
332 SIGG(depth) = 0;
333 } /* }}} */
334
335 /* {{{ zend_signal_deactivate */
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