xref: /PHP-7.3/Zend/zend_signal.c (revision 38f1288b)
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