1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "sighandler.h"
22 
23 #include "log.h"
24 #include "fatal.h"
25 #include "sigcommon.h"
26 #include "zbxcrypto.h"
27 
28 int			sig_parent_pid = -1;
29 volatile sig_atomic_t	sig_exiting;
30 
log_fatal_signal(int sig,siginfo_t * siginfo,void * context)31 static void	log_fatal_signal(int sig, siginfo_t *siginfo, void *context)
32 {
33 	SIG_CHECK_PARAMS(sig, siginfo, context);
34 
35 	zabbix_log(LOG_LEVEL_CRIT, "Got signal [signal:%d(%s),reason:%d,refaddr:%p]. Crashing ...",
36 			sig, get_signal_name(sig),
37 			SIG_CHECKED_FIELD(siginfo, si_code),
38 			SIG_CHECKED_FIELD_TYPE(siginfo, si_addr, void *));
39 }
40 
exit_with_failure(void)41 static void	exit_with_failure(void)
42 {
43 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
44 	zbx_tls_free_on_signal();
45 #endif
46 	_exit(EXIT_FAILURE);
47 }
48 
49 /******************************************************************************
50  *                                                                            *
51  * Function: fatal_signal_handler                                             *
52  *                                                                            *
53  * Purpose: handle fatal signals: SIGILL, SIGFPE, SIGSEGV, SIGBUS             *
54  *                                                                            *
55  ******************************************************************************/
fatal_signal_handler(int sig,siginfo_t * siginfo,void * context)56 static void	fatal_signal_handler(int sig, siginfo_t *siginfo, void *context)
57 {
58 	log_fatal_signal(sig, siginfo, context);
59 	zbx_log_fatal_info(context, ZBX_FATAL_LOG_FULL_INFO);
60 
61 	exit_with_failure();
62 }
63 
64 /******************************************************************************
65  *                                                                            *
66  * Function: metric_thread_signal_handler                                     *
67  *                                                                            *
68  * Purpose: same as fatal_signal_handler() but customized for metric thread - *
69  *          does not log memory map                                           *
70  *                                                                            *
71  ******************************************************************************/
metric_thread_signal_handler(int sig,siginfo_t * siginfo,void * context)72 static void	metric_thread_signal_handler(int sig, siginfo_t *siginfo, void *context)
73 {
74 	log_fatal_signal(sig, siginfo, context);
75 	zbx_log_fatal_info(context, (ZBX_FATAL_LOG_PC_REG_SF | ZBX_FATAL_LOG_BACKTRACE));
76 
77 	exit_with_failure();
78 }
79 
80 /******************************************************************************
81  *                                                                            *
82  * Function: alarm_signal_handler                                             *
83  *                                                                            *
84  * Purpose: handle alarm signal SIGALRM                                       *
85  *                                                                            *
86  ******************************************************************************/
alarm_signal_handler(int sig,siginfo_t * siginfo,void * context)87 static void	alarm_signal_handler(int sig, siginfo_t *siginfo, void *context)
88 {
89 	SIG_CHECK_PARAMS(sig, siginfo, context);
90 
91 	zbx_alarm_flag_set();	/* set alarm flag */
92 }
93 
94 /******************************************************************************
95  *                                                                            *
96  * Function: terminate_signal_handler                                         *
97  *                                                                            *
98  * Purpose: handle terminate signals: SIGHUP, SIGINT, SIGTERM, SIGUSR2        *
99  *                                                                            *
100  ******************************************************************************/
terminate_signal_handler(int sig,siginfo_t * siginfo,void * context)101 static void	terminate_signal_handler(int sig, siginfo_t *siginfo, void *context)
102 {
103 	int zbx_log_level_temp;
104 
105 	if (!SIG_PARENT_PROCESS)
106 	{
107 		/* the parent process can either politely ask a child process to finish it's work and perform cleanup */
108 		/* by sending SIGUSR2 or terminate child process immediately without cleanup by sending SIGHUP        */
109 		if (SIGHUP == sig)
110 			exit_with_failure();
111 
112 		if (SIGUSR2 == sig)
113 			sig_exiting = 1;
114 	}
115 	else
116 	{
117 		SIG_CHECK_PARAMS(sig, siginfo, context);
118 
119 		if (0 == sig_exiting)
120 		{
121 			sig_exiting = 1;
122 
123 			/* temporary variable is used to avoid compiler warning */
124 			zbx_log_level_temp = sig_parent_pid == SIG_CHECKED_FIELD(siginfo, si_pid) ?
125 					LOG_LEVEL_DEBUG : LOG_LEVEL_WARNING;
126 			zabbix_log(zbx_log_level_temp,
127 					"Got signal [signal:%d(%s),sender_pid:%d,sender_uid:%d,"
128 					"reason:%d]. Exiting ...",
129 					sig, get_signal_name(sig),
130 					SIG_CHECKED_FIELD(siginfo, si_pid),
131 					SIG_CHECKED_FIELD(siginfo, si_uid),
132 					SIG_CHECKED_FIELD(siginfo, si_code));
133 
134 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
135 			zbx_tls_free_on_signal();
136 #endif
137 			zbx_on_exit(SUCCEED);
138 		}
139 	}
140 }
141 
142 /******************************************************************************
143  *                                                                            *
144  * Function: child_signal_handler                                             *
145  *                                                                            *
146  * Purpose: handle child signal SIGCHLD                                       *
147  *                                                                            *
148  ******************************************************************************/
child_signal_handler(int sig,siginfo_t * siginfo,void * context)149 static void	child_signal_handler(int sig, siginfo_t *siginfo, void *context)
150 {
151 	SIG_CHECK_PARAMS(sig, siginfo, context);
152 
153 	if (!SIG_PARENT_PROCESS)
154 		exit_with_failure();
155 
156 	if (0 == sig_exiting)
157 	{
158 		sig_exiting = 1;
159 		zabbix_log(LOG_LEVEL_CRIT, "One child process died (PID:%d,exitcode/signal:%d). Exiting ...",
160 				SIG_CHECKED_FIELD(siginfo, si_pid), SIG_CHECKED_FIELD(siginfo, si_status));
161 
162 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
163 		zbx_tls_free_on_signal();
164 #endif
165 		zbx_on_exit(FAIL);
166 	}
167 }
168 
169 /******************************************************************************
170  *                                                                            *
171  * Function: zbx_set_common_signal_handlers                                   *
172  *                                                                            *
173  * Purpose: set the commonly used signal handlers                             *
174  *                                                                            *
175  ******************************************************************************/
zbx_set_common_signal_handlers(void)176 void	zbx_set_common_signal_handlers(void)
177 {
178 	struct sigaction	phan;
179 
180 	sig_parent_pid = (int)getpid();
181 
182 	sigemptyset(&phan.sa_mask);
183 	phan.sa_flags = SA_SIGINFO;
184 
185 	phan.sa_sigaction = terminate_signal_handler;
186 	sigaction(SIGINT, &phan, NULL);
187 	sigaction(SIGQUIT, &phan, NULL);
188 	sigaction(SIGHUP, &phan, NULL);
189 	sigaction(SIGTERM, &phan, NULL);
190 	sigaction(SIGUSR2, &phan, NULL);
191 
192 	phan.sa_sigaction = fatal_signal_handler;
193 	sigaction(SIGILL, &phan, NULL);
194 	sigaction(SIGFPE, &phan, NULL);
195 	sigaction(SIGSEGV, &phan, NULL);
196 	sigaction(SIGBUS, &phan, NULL);
197 
198 	phan.sa_sigaction = alarm_signal_handler;
199 	sigaction(SIGALRM, &phan, NULL);
200 }
201 
202 /******************************************************************************
203  *                                                                            *
204  * Function: zbx_set_child_signal_handler                                     *
205  *                                                                            *
206  * Purpose: set the handlers for child process signals                        *
207  *                                                                            *
208  ******************************************************************************/
zbx_set_child_signal_handler(void)209 void 	zbx_set_child_signal_handler(void)
210 {
211 	struct sigaction	phan;
212 
213 	sig_parent_pid = (int)getpid();
214 
215 	sigemptyset(&phan.sa_mask);
216 	phan.sa_flags = SA_SIGINFO | SA_NOCLDSTOP;
217 
218 	phan.sa_sigaction = child_signal_handler;
219 	sigaction(SIGCHLD, &phan, NULL);
220 }
221 
222 /******************************************************************************
223  *                                                                            *
224  * Function: zbx_set_metric_thread_signal_handler                             *
225  *                                                                            *
226  * Purpose: set the handlers for child process signals                        *
227  *                                                                            *
228  ******************************************************************************/
zbx_set_metric_thread_signal_handler(void)229 void 	zbx_set_metric_thread_signal_handler(void)
230 {
231 	struct sigaction	phan;
232 
233 	sig_parent_pid = (int)getpid();
234 
235 	sigemptyset(&phan.sa_mask);
236 	phan.sa_flags = SA_SIGINFO;
237 
238 	phan.sa_sigaction = metric_thread_signal_handler;
239 	sigaction(SIGILL, &phan, NULL);
240 	sigaction(SIGFPE, &phan, NULL);
241 	sigaction(SIGSEGV, &phan, NULL);
242 	sigaction(SIGBUS, &phan, NULL);
243 }
244