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