xref: /PHP-7.4/Zend/zend_signal.c (revision 54248b18)
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