xref: /PHP-7.4/sapi/fpm/fpm/fpm_signals.c (revision e37bd5dc)
1 	/* (c) 2007,2008 Andrei Nigmatulin */
2 
3 #include "fpm_config.h"
4 
5 #include <signal.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <errno.h>
14 
15 #include "fpm.h"
16 #include "fpm_signals.h"
17 #include "fpm_sockets.h"
18 #include "fpm_php.h"
19 #include "zlog.h"
20 
21 static int sp[2];
22 static sigset_t block_sigset;
23 static sigset_t child_block_sigset;
24 
25 const char *fpm_signal_names[NSIG + 1] = {
26 #ifdef SIGHUP
27 	[SIGHUP] 		= "SIGHUP",
28 #endif
29 #ifdef SIGINT
30 	[SIGINT] 		= "SIGINT",
31 #endif
32 #ifdef SIGQUIT
33 	[SIGQUIT] 		= "SIGQUIT",
34 #endif
35 #ifdef SIGILL
36 	[SIGILL] 		= "SIGILL",
37 #endif
38 #ifdef SIGTRAP
39 	[SIGTRAP] 		= "SIGTRAP",
40 #endif
41 #ifdef SIGABRT
42 	[SIGABRT] 		= "SIGABRT",
43 #endif
44 #ifdef SIGEMT
45 	[SIGEMT] 		= "SIGEMT",
46 #endif
47 #ifdef SIGBUS
48 	[SIGBUS] 		= "SIGBUS",
49 #endif
50 #ifdef SIGFPE
51 	[SIGFPE] 		= "SIGFPE",
52 #endif
53 #ifdef SIGKILL
54 	[SIGKILL] 		= "SIGKILL",
55 #endif
56 #ifdef SIGUSR1
57 	[SIGUSR1] 		= "SIGUSR1",
58 #endif
59 #ifdef SIGSEGV
60 	[SIGSEGV] 		= "SIGSEGV",
61 #endif
62 #ifdef SIGUSR2
63 	[SIGUSR2] 		= "SIGUSR2",
64 #endif
65 #ifdef SIGPIPE
66 	[SIGPIPE] 		= "SIGPIPE",
67 #endif
68 #ifdef SIGALRM
69 	[SIGALRM] 		= "SIGALRM",
70 #endif
71 #ifdef SIGTERM
72 	[SIGTERM] 		= "SIGTERM",
73 #endif
74 #ifdef SIGCHLD
75 	[SIGCHLD] 		= "SIGCHLD",
76 #endif
77 #ifdef SIGCONT
78 	[SIGCONT] 		= "SIGCONT",
79 #endif
80 #ifdef SIGSTOP
81 	[SIGSTOP] 		= "SIGSTOP",
82 #endif
83 #ifdef SIGTSTP
84 	[SIGTSTP] 		= "SIGTSTP",
85 #endif
86 #ifdef SIGTTIN
87 	[SIGTTIN] 		= "SIGTTIN",
88 #endif
89 #ifdef SIGTTOU
90 	[SIGTTOU] 		= "SIGTTOU",
91 #endif
92 #ifdef SIGURG
93 	[SIGURG] 		= "SIGURG",
94 #endif
95 #ifdef SIGXCPU
96 	[SIGXCPU] 		= "SIGXCPU",
97 #endif
98 #ifdef SIGXFSZ
99 	[SIGXFSZ] 		= "SIGXFSZ",
100 #endif
101 #ifdef SIGVTALRM
102 	[SIGVTALRM] 	= "SIGVTALRM",
103 #endif
104 #ifdef SIGPROF
105 	[SIGPROF] 		= "SIGPROF",
106 #endif
107 #ifdef SIGWINCH
108 	[SIGWINCH] 		= "SIGWINCH",
109 #endif
110 #ifdef SIGINFO
111 	[SIGINFO] 		= "SIGINFO",
112 #endif
113 #ifdef SIGIO
114 	[SIGIO] 		= "SIGIO",
115 #endif
116 #ifdef SIGPWR
117 	[SIGPWR] 		= "SIGPWR",
118 #endif
119 #ifdef SIGSYS
120 	[SIGSYS] 		= "SIGSYS",
121 #endif
122 #ifdef SIGWAITING
123 	[SIGWAITING] 	= "SIGWAITING",
124 #endif
125 #ifdef SIGLWP
126 	[SIGLWP] 		= "SIGLWP",
127 #endif
128 #ifdef SIGFREEZE
129 	[SIGFREEZE] 	= "SIGFREEZE",
130 #endif
131 #ifdef SIGTHAW
132 	[SIGTHAW] 		= "SIGTHAW",
133 #endif
134 #ifdef SIGCANCEL
135 	[SIGCANCEL] 	= "SIGCANCEL",
136 #endif
137 #ifdef SIGLOST
138 	[SIGLOST] 		= "SIGLOST",
139 #endif
140 };
141 
sig_soft_quit(int signo)142 static void sig_soft_quit(int signo) /* {{{ */
143 {
144 	int saved_errno = errno;
145 
146 	/* closing fastcgi listening socket will force fcgi_accept() exit immediately */
147 	close(fpm_globals.listening_socket);
148 	if (0 > socket(AF_UNIX, SOCK_STREAM, 0)) {
149 		zlog(ZLOG_WARNING, "failed to create a new socket");
150 	}
151 	fpm_php_soft_quit();
152 	errno = saved_errno;
153 }
154 /* }}} */
155 
sig_handler(int signo)156 static void sig_handler(int signo) /* {{{ */
157 {
158 	static const char sig_chars[NSIG + 1] = {
159 		[SIGTERM] = 'T',
160 		[SIGINT]  = 'I',
161 		[SIGUSR1] = '1',
162 		[SIGUSR2] = '2',
163 		[SIGQUIT] = 'Q',
164 		[SIGCHLD] = 'C'
165 	};
166 	char s;
167 	int saved_errno;
168 
169 	if (fpm_globals.parent_pid != getpid()) {
170 		/* Avoid using of signal handlers from the master process in a worker
171 			before the child sets up its own signal handlers.
172 			Normally it is prevented by the sigprocmask() calls
173 			around fork(). This execution branch is a last resort trap
174 			that has no protection against #76601. */
175 		return;
176 	}
177 
178 	saved_errno = errno;
179 	s = sig_chars[signo];
180 	zend_quiet_write(sp[1], &s, sizeof(s));
181 	errno = saved_errno;
182 }
183 /* }}} */
184 
fpm_signals_init_main()185 int fpm_signals_init_main() /* {{{ */
186 {
187 	struct sigaction act;
188 
189 	if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) {
190 		zlog(ZLOG_SYSERROR, "failed to init signals: socketpair()");
191 		return -1;
192 	}
193 
194 	if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) {
195 		zlog(ZLOG_SYSERROR, "failed to init signals: fd_set_blocked()");
196 		return -1;
197 	}
198 
199 	if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) {
200 		zlog(ZLOG_SYSERROR, "falied to init signals: fcntl(F_SETFD, FD_CLOEXEC)");
201 		return -1;
202 	}
203 
204 	memset(&act, 0, sizeof(act));
205 	act.sa_handler = sig_handler;
206 	sigfillset(&act.sa_mask);
207 
208 	if (0 > sigaction(SIGTERM,  &act, 0) ||
209 	    0 > sigaction(SIGINT,   &act, 0) ||
210 	    0 > sigaction(SIGUSR1,  &act, 0) ||
211 	    0 > sigaction(SIGUSR2,  &act, 0) ||
212 	    0 > sigaction(SIGCHLD,  &act, 0) ||
213 	    0 > sigaction(SIGQUIT,  &act, 0)) {
214 
215 		zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()");
216 		return -1;
217 	}
218 
219 	zlog(ZLOG_DEBUG, "Unblocking all signals");
220 	if (0 > fpm_signals_unblock()) {
221 		return -1;
222 	}
223 	return 0;
224 }
225 /* }}} */
226 
fpm_signals_init_child()227 int fpm_signals_init_child() /* {{{ */
228 {
229 	struct sigaction act, act_dfl;
230 
231 	memset(&act, 0, sizeof(act));
232 	memset(&act_dfl, 0, sizeof(act_dfl));
233 
234 	act.sa_handler = &sig_soft_quit;
235 	act.sa_flags |= SA_RESTART;
236 
237 	act_dfl.sa_handler = SIG_DFL;
238 
239 	close(sp[0]);
240 	close(sp[1]);
241 
242 	if (0 > sigaction(SIGTERM,  &act_dfl,  0) ||
243 	    0 > sigaction(SIGINT,   &act_dfl,  0) ||
244 	    0 > sigaction(SIGUSR1,  &act_dfl,  0) ||
245 	    0 > sigaction(SIGUSR2,  &act_dfl,  0) ||
246 	    0 > sigaction(SIGCHLD,  &act_dfl,  0) ||
247 	    0 > sigaction(SIGQUIT,  &act,      0)) {
248 
249 		zlog(ZLOG_SYSERROR, "failed to init child signals: sigaction()");
250 		return -1;
251 	}
252 
253 	zend_signal_init();
254 
255 	if (0 > fpm_signals_unblock()) {
256 		return -1;
257 	}
258 	return 0;
259 }
260 /* }}} */
261 
fpm_signals_get_fd()262 int fpm_signals_get_fd() /* {{{ */
263 {
264 	return sp[0];
265 }
266 /* }}} */
267 
fpm_signals_init_mask()268 int fpm_signals_init_mask() /* {{{ */
269 {
270 	/* Subset of signals from fpm_signals_init_main() and fpm_got_signal()
271 		blocked to avoid unexpected death during early init
272 		or during reload just after execvp() or fork */
273 	int init_signal_array[] = { SIGUSR1, SIGUSR2, SIGCHLD };
274 	size_t size = sizeof(init_signal_array)/sizeof(init_signal_array[0]);
275 	size_t i = 0;
276 	if (0 > sigemptyset(&block_sigset) ||
277 	    0 > sigemptyset(&child_block_sigset)) {
278 		zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigemptyset()");
279 		return -1;
280 	}
281 	for (i = 0; i < size; ++i) {
282 		int sig_i = init_signal_array[i];
283 		if (0 > sigaddset(&block_sigset, sig_i) ||
284 		    0 > sigaddset(&child_block_sigset, sig_i)) {
285 			if (sig_i <= NSIG && fpm_signal_names[sig_i] != NULL) {
286 				zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigaddset(%s)",
287 						fpm_signal_names[sig_i]);
288 			} else {
289 				zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigaddset(%d)", sig_i);
290 			}
291 			return -1;
292 		}
293 	}
294 	if (0 > sigaddset(&child_block_sigset, SIGTERM) ||
295 	    0 > sigaddset(&child_block_sigset, SIGQUIT)) {
296 		zlog(ZLOG_SYSERROR, "failed to prepare child signal block mask: sigaddset()");
297 		return -1;
298 	}
299 	return 0;
300 }
301 /* }}} */
302 
fpm_signals_block()303 int fpm_signals_block() /* {{{ */
304 {
305 	if (0 > sigprocmask(SIG_BLOCK, &block_sigset, NULL)) {
306 		zlog(ZLOG_SYSERROR, "failed to block signals");
307 		return -1;
308 	}
309 	return 0;
310 }
311 /* }}} */
312 
fpm_signals_child_block()313 int fpm_signals_child_block() /* {{{ */
314 {
315 	if (0 > sigprocmask(SIG_BLOCK, &child_block_sigset, NULL)) {
316 		zlog(ZLOG_SYSERROR, "failed to block child signals");
317 		return -1;
318 	}
319 	return 0;
320 }
321 /* }}} */
322 
fpm_signals_unblock()323 int fpm_signals_unblock() /* {{{ */
324 {
325 	/* Ensure that during reload after upgrade all signals are unblocked.
326 		block_sigset could have different value before execve() */
327 	sigset_t all_signals;
328 	sigfillset(&all_signals);
329 	if (0 > sigprocmask(SIG_UNBLOCK, &all_signals, NULL)) {
330 		zlog(ZLOG_SYSERROR, "failed to unblock signals");
331 		return -1;
332 	}
333 	return 0;
334 }
335 /* }}} */
336