1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup ### #######
36  *  @ingroup yadifad
37  *  @brief
38  *
39  * @{
40  */
41 /*------------------------------------------------------------------------------
42  *
43  * USE INCLUDES */
44 
45 #include "dnscore/dnscore-config.h"
46 
47 #ifndef WIN32
48 
49 #define _GNU_SOURCE 1
50 
51 #include <dnscore/thread.h>
52 
53 #include <unistd.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 
58 #if defined(__linux__) || defined(__gnu_hurd__)
59 #define _GNU_SOURCE 1
60 #include <execinfo.h>
61 #include <sys/mman.h>
62 #include <ucontext.h>
63 #elif defined(__sun)
64 #include <ucontext.h>
65 #endif
66 
67 #include "dnscore/logger.h"
68 #include "dnscore/format.h"
69 #include "dnscore/fdtools.h"
70 #include "dnscore/timems.h"
71 #include "dnscore/thread.h"
72 #include "dnscore/thread_pool.h"
73 #include "dnscore/process.h"
74 #include "dnscore/signals.h"
75 
76 #define SIGNAL_MAX 32
77 #define SIGNAL_HANDLER_CHAIN 0
78 #define SIGNAL_DONT_QUEUE_TWICE 1   // avoids hammering the signal handling thread
79 
80 #if SIGNAL_DONT_QUEUE_TWICE
81 
82 #if HAVE_STDATOMIC_H
83 #include <stdatomic.h>
84 #else
85 
86 #if __GNUC__
87     #if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9))
88     #pragma message("stdatomic.h not found: this is expected given the version of gcc: please use gcc >= 4.9 or clang >=?")
89     #else
90     #pragma message("stdatomic.h not found: this is not expected as your gcc has a version >= 4.9")
91     #endif
92 #else
93     #pragma message("stdatomic.h not found: please a compiler that supports it (e.g.: gcc >= 4.9")
94 #endif
95 
96 #if HAS_SYNC_BUILTINS
97 
98 #pragma message("stdatomic.h not found: using __sync builtins instead")
99 
100 #define ATOMIC_FLAG_INIT 0
101 
102 typedef int atomic_flag;
103 
atomic_flag_test_and_set(atomic_flag * v)104 static bool atomic_flag_test_and_set(atomic_flag* v)
105 {
106     bool old = __sync_fetch_and_or(v, (atomic_flag)1);
107     return old;
108 }
109 
atomic_flag_clear(atomic_flag * v)110 static void atomic_flag_clear(atomic_flag* v)
111 {
112     __sync_fetch_and_and(v, (atomic_flag)0);
113 }
114 
115 #else
116 
117 #pragma message("stdatomic.h not found: found no proper way to handle this")
118 
119 #define ATOMIC_FLAG_INIT 0
120 
121 typedef volatile int atomic_flag;
122 
atomic_flag_test_and_set(atomic_flag * v)123 static bool atomic_flag_test_and_set(atomic_flag* v)
124 {
125     bool old = *v;
126     *v = 1;
127     return old;
128 }
129 
atomic_flag_clear(atomic_flag * v)130 static void atomic_flag_clear(atomic_flag* v)
131 {
132     *v = 0;
133 }
134 
135 #endif
136 
137 
138 #endif // HAS_STDATOMIC_H
139 
140 #endif // SIGNAL_DONT_QUEUE_TWICE
141 
142 #if DEBUG
143 #if defined(__linux__)
144 #include <sys/types.h>
145 
146 // testing for !((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 30))) is irrelevant as there is no name collision.
147 
148 #include <asm/unistd.h>
signal_gettid()149 static inline long int signal_gettid()
150 {
151     return (long int)syscall(__NR_gettid);
152 }
153 #else
signal_gettid()154 static inline long int signal_gettid()
155 {
156     return (long int)~0;
157 }
158 #endif
159 #endif
160 
161 #define MODULE_MSG_HANDLE g_system_logger
162 #define MAXTRACE 128
163 
164 // Let this to 0
165 // This prevents the coredump from occurring.
166 // Let's configure this using runtime flags.
167 #define SIGNAL_HOOK_COREDUMP 1
168 
169 static const char* signal_dump_path = "/tmp";
170 
171 static thread_t signal_thread = 0;
172 static mutex_t signal_mutex = MUTEX_INITIALIZER;
173 
174 static volatile int signal_handler_read_fd = -1;
175 static volatile int signal_handler_write_fd = -1;
176 
177 static bool sigsegv_trytrace = TRUE;
178 static bool sigsegv_tryloggerflush = TRUE;
179 
180 #if DEBUG
181 static void
signal_handler_cb_debug(u8 signum)182 signal_handler_cb_debug(u8 signum)
183 {
184     log_info("signal: %i received", (int)signum);
185 }
186 
187 #define SIGNAL_HANDLER_NULL signal_handler_cb_debug
188 
189 #else
190 
191 #define SIGNAL_HANDLER_NULL NULL
192 
193 #endif
194 
195 // signal can be lost, a full pipe will not block and lose even more.
196 // shutdown is thus given an override so that it cannot be lost after
197 // the signal handler gets it.
198 
199 static volatile bool signal_shutdown_received = FALSE;
200 
201 struct signal_handler_entry
202 {
203     signal_handler_cb handler;
204 #if SIGNAL_HANDLER_CHAIN
205     struct signal_handler_entry *next;
206 #endif
207 #if SIGNAL_DONT_QUEUE_TWICE
208     atomic_flag queued;
209 #endif
210 };
211 
212 typedef struct signal_handler_entry signal_handler_entry;
213 
214 #if SIGNAL_HANDLER_CHAIN
215 #if SIGNAL_DONT_QUEUE_TWICE
216 #define SIGNAL_HANDLER_ENTRY {SIGNAL_HANDLER_NULL, NULL, ATOMIC_FLAG_INIT}
217 #else
218 #define SIGNAL_HANDLER_ENTRY {SIGNAL_HANDLER_NULL, NULL}
219 #endif
220 #else
221 #if SIGNAL_DONT_QUEUE_TWICE
222 #define SIGNAL_HANDLER_ENTRY {SIGNAL_HANDLER_NULL, ATOMIC_FLAG_INIT}
223 #else
224 #define SIGNAL_HANDLER_ENTRY {SIGNAL_HANDLER_NULL}
225 #endif
226 #endif
227 
228 static signal_handler_entry signal_handlers[SIGNAL_MAX] =
229 {
230     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
231     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
232     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
233     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
234     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
235     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
236     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY,
237     SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY, SIGNAL_HANDLER_ENTRY
238 };
239 
240 static u8 signal_ignored_at_shutdown[SIGNAL_MAX] =
241 {
242     SIGHUP, SIGUSR1, SIGINT, SIGTERM,
243     SIGPIPE,0,0,0,
244     0,0,0,0,
245     0,0,0,0,
246     0,0,0,0,
247     0,0,0,0,
248     0,0,0,0,
249     0,0,0,0,
250 };
251 
252 static void
signal_ignore_for_shutdown()253 signal_ignore_for_shutdown()
254 {
255     int errno_value = errno;
256     for(int i = 0; i < SIGNAL_MAX; ++i)
257     {
258         int s;
259         if((s = signal_ignored_at_shutdown[i]) == 0) break;
260         signal(s, SIG_IGN);
261     }
262     errno = errno_value;
263 }
264 
265 static void
signal_send_to_thread(int signo)266 signal_send_to_thread(int signo)
267 {
268 #if SIGNAL_DONT_QUEUE_TWICE
269     assert(((signo >= 0) && (signo < SIGNAL_MAX)) || (signo == MAX_U8));
270 
271 #if !defined(GCC_VERSION) || (GCC_VERSION > 40700)
272     bool old_flag = (signo < SIGNAL_MAX)?atomic_flag_test_and_set(&signal_handlers[signo].queued):FALSE;
273 #else
274     bool old_flag;
275     if(signo < SIGNAL_MAX)
276     {
277 	atomic_flag* flag = &signal_handlers[signo].queued;
278         old_flag = atomic_flag_test_and_set(flag);
279     }
280     else
281     {
282         old_flag = FALSE;
283     }
284 #endif
285 
286     if(!old_flag)
287     {
288 #endif
289         int errno_value = errno;
290         int ret;
291         u8 signum = (u8)signo; // MUST be one byte long
292         while((ret = write(signal_handler_write_fd, &signum, sizeof(signum))) != sizeof(signum))
293         {
294             if(ret < 0)
295             {
296                 ret = errno;
297 #if EAGAIN != EWOULDBLOCK
298                 if((ret == EINTR) || (ret == EAGAIN) || (ret == EWOULDBLOCK))
299                 {
300                     continue;
301                 }
302 #else
303                 if((ret == EINTR) || (ret == EAGAIN))
304                 {
305                     continue;
306                 }
307 #endif
308             }
309             else if(ret == 0)
310             {
311                 continue;
312             }
313 
314             // failed unexpectedly
315 
316             if(signo < SIGNAL_MAX)
317             {
318                 atomic_flag_clear(&signal_handlers[signo].queued);
319             }
320 
321             break;
322         }
323 
324         errno = errno_value;
325 #if SIGNAL_DONT_QUEUE_TWICE
326     }
327 #endif
328 }
329 
330 /*
331  * signals are not supposed to be interrupted by other signals
332  * still, it happened once, the pthread_create of another signal : deadlock
333  * so, here is another check (mutexes are of course forbidden)
334  */
335 
336 // tool to avoid external function calls during the signal
337 
338 static int
signal_strcat(char * dest,const char * src)339 signal_strcat(char *dest, const char* src)
340 {
341     char *p = dest;
342 
343     while(*p != '\0')
344     {
345         p++;
346     }
347 
348     while(*src != '\0')
349     {
350         *p++ = *src++;
351     }
352 
353     *p = '\0';
354 
355     return p - dest;
356 }
357 
358 // tool to avoid external function calls during the signal
359 
360 static int
signal_int2str(char * dest,int src)361 signal_int2str(char *dest, int src)
362 {
363     char *p = dest;
364     int tmp = src;
365     do
366     {
367         p++;
368         tmp /= 10;
369     }
370     while(tmp > 0);
371 
372     *p = '\0';
373 
374     do
375     {
376         char c = '0' + (char)(src % 10);
377         src /= 10;
378 
379         --p;
380 
381         *p = c;
382     }
383     while(src > 0);
384 
385     while(p > dest)
386     {
387         --p;
388 
389         *p = ' ';
390     }
391 
392     return p - dest;
393 }
394 
395 static const char __HEXA__[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
396 
397 static int
signal_longlong2hexstr(char * dest,u64 src)398 signal_longlong2hexstr(char *dest, u64 src)
399 {
400     int shift = 60;
401     do
402     {
403         *dest++ = __HEXA__[(src >> shift) & 15];
404         shift -= 4;
405     }
406     while(shift >= 0);
407     *dest = '\0';
408     return 16;
409 }
410 
411 static int
signal_int2hexstr(char * dest,u32 src)412 signal_int2hexstr(char *dest, u32 src)
413 {
414     int shift = 28;
415     do
416     {
417         *dest++ = __HEXA__[(src >> shift) & 15];
418         shift -= 4;
419     }
420     while(shift >= 0);
421     *dest = '\0';
422     return 8;
423 }
424 
425 static int
signal_char2hexstr(char * dest,u8 src)426 signal_char2hexstr(char *dest, u8 src)
427 {
428     int shift = 4;
429     do
430     {
431         *dest++ = __HEXA__[(src >> shift) & 15];
432         shift -= 4;
433     }
434     while(shift >= 0);
435     *dest = '\0';
436     return 2;
437 }
438 
439 // tool to avoid external function calls during the signal
440 
441 static int
signal_ptr2str(char * dest,const void * srcp)442 signal_ptr2str(char *dest, const void* srcp)
443 {
444 #if __SIZEOF_POINTER__ == 8
445     return signal_longlong2hexstr(dest,(u64)srcp);
446 #elif __SIZEOF_POINTER__ == 4
447     return signal_int2hexstr(dest,(u32)srcp);
448 #else
449 #error "unsupported pointer size"
450 #endif
451 }
452 
453 //
454 
455 static void
signal_handler_thread_stop()456 signal_handler_thread_stop()
457 {
458     log_info("signal: thread stopping");
459 
460     mutex_lock(&signal_mutex);
461     if(signal_handler_read_fd >= 0)
462     {
463         signal_send_to_thread(MAX_U8);
464     }
465     mutex_unlock(&signal_mutex);
466 }
467 
468 static noreturn void*
signal_handler_thread(void * parms)469 signal_handler_thread(void* parms)
470 {
471     (void)parms;
472 
473 #if DEBUG
474     log_debug7("thread started: self=%p, tid=%i", thread_self(), signal_gettid());
475 #endif
476 
477     thread_set_name("signal", 0, 0);
478 
479 #if DNSCORE_HAS_LOG_THREAD_TAG
480     static char signal_thread_tag[9] = "signal";
481     logger_handle_set_thread_tag(signal_thread_tag);
482 #endif
483 
484     log_info("signal: thread started");
485 
486     while(signal_handler_read_fd >= 0)
487     {
488         u8 signum;
489         ya_result return_code;
490 
491 #if DEBUG
492         log_debug7("signal: waiting for next signal");
493 #endif
494 
495         if(FAIL(return_code = readfully(signal_handler_read_fd, &signum, sizeof(signum))))
496         {
497             log_err("signal: error reading the next signal: %r", return_code);
498             break;
499         }
500 
501 #if DEBUG
502         log_debug7("signal: handling signal %i", signum);
503 #endif
504 
505         if(signum < SIGNAL_MAX)
506         {
507 #if SIGNAL_DONT_QUEUE_TWICE
508             atomic_flag_clear(&signal_handlers[signum].queued);
509 #endif
510             if(signal_shutdown_received)
511             {
512 #if DEBUG
513                 if(signum != SIGINT && signum != SIGTERM)
514                 {
515                     log_debug7("signal: check that, handling a SIGINT instead");
516                 }
517 #endif
518                 signum = SIGINT;
519             }
520 #if SIGNAL_HANDLER_CHAIN
521             signal_handler_entry* = &signal_handlers[signum];
522             if(signal_handler_entry->handler != NULL)
523             {
524                 do
525                 {
526                     signal_handler_entry->handler(signum);
527                     signal_handler_entry = signal_handler_entry->next;
528                 }
529                 while(signal_handler_entry != NULL);
530             }
531 #else
532             switch(signum)
533             {
534                 case SIGABRT:
535                 case SIGBUS:
536                 case SIGFPE:
537                 case SIGILL:
538                 case SIGSEGV:
539                     break;
540                 case SIGINT:
541                 case SIGTERM:
542                     logger_sink_noblock();
543                     break;
544                 default:
545                     logger_sink_noblock();
546                     break;
547             }
548 
549             if(signal_handlers[signum].handler != NULL) // NULL is right
550             {
551                 signal_handlers[signum].handler(signum);
552             }
553 #endif
554         }
555         else if(signum == MAX_U8)
556         {
557             //signal_handler_thread_stop();
558             break;
559         }
560     }
561 
562     log_info("signal: thread stopping");
563 
564     /*
565     mutex_lock(&signal_mutex);
566     signal_thread = 0;
567     mutex_unlock(&signal_mutex);
568     */
569 #if DNSCORE_HAS_LOG_THREAD_TAG
570     logger_flush();
571     logger_handle_clear_thread_tag();
572 #endif
573 
574     log_info("signal: thread stopped");
575 
576     logger_flush();
577 
578     thread_exit(NULL);
579 
580     // unreachable
581 #if GCC_VERSION < 40600
582     return NULL;
583 #endif
584 }
585 
586 void
signal_handler_stop()587 signal_handler_stop()
588 {
589     signal_handler_thread_stop();
590 
591     /**
592      * The signal thread CANNOT be joined here,
593      * as if a signal handler callback calls it then it will ovbiously be a deadlock.
594      */
595 }
596 
597 /** \brief handle the signals received
598  *
599  *  @param[in] signo
600  *
601  *  @note The signal handler CANNOT use the loggers or it has to use its own channels + handle. (ie: not the ones of the logger)
602  *        The reason being mutexes are not reentrant.  So if a signal occurs while the log mutex is on
603  *        the signal will deadlock as soon as it tries to log.
604  *
605  *  return NONE
606  */
607 
608 static void
signal_handler(int signo,siginfo_t * info,void * context)609 signal_handler(int signo, siginfo_t* info, void* context)
610 {
611     // formatln("signal_handler, pid=%i, tid=%p, signal=%i", getpid(), thread_self(), signo);
612 
613     switch(signo)
614     {
615         case SIGINT: // special cases
616         case SIGTERM:
617         {
618             /*
619              * We are shutting down : ignore other "command" signals
620              * Also, in order to avoid handling an hammering of signals,
621              * (and risking missing the shutdown if the pipe is already full)
622              * we set a volatile that will be sync "soon" (no mutexes here please)
623              */
624 
625             signal_ignore_for_shutdown();
626             signal_shutdown_received = TRUE;
627 
628             signal_send_to_thread(signo);
629             break;
630         }
631 
632 #if SIGNAL_HOOK_COREDUMP
633         case SIGABRT:
634         case SIGBUS:
635         case SIGFPE:
636         case SIGILL:
637         case SIGSEGV:
638         {
639             // reactivate the default handler
640 
641             int errno_value = errno;
642 
643             signal(signo, SIG_DFL);
644 
645             if(sigsegv_trytrace)
646             {
647                 char filepath[PATH_MAX];
648                 char number[32];
649 
650                 sigsegv_trytrace = FALSE;
651 
652                 for(int source = 0; source <= 1; source++)
653                 {
654                     char *eol = (source == 0)?"\n":"";
655                     int fd = -1; /// @note edf: set to -1 to shut-up false positive "uninitialised"
656                     int len;
657 
658                     filepath[0] = '\0';
659                     signal_strcat(filepath, signal_dump_path);
660                     signal_strcat(filepath, "/");
661                     signal_strcat(filepath, "sig-");
662                     signal_int2str(number, signo);
663                     signal_strcat(filepath, number);
664                     signal_strcat(filepath, "-");
665                     signal_int2str(number, getpid_ex());
666                     signal_strcat(filepath, number);
667 
668                     if(source == 0)
669                     {
670                         fd = open_create_ex(filepath, O_WRONLY|O_CREAT|O_APPEND|O_CLOEXEC, 0644);
671 
672                         if(fd < 0)
673                         {
674                             continue;
675                         }
676                     }
677                     else
678                     {
679                         if(!logger_is_running())
680                         {
681                             continue;
682                         }
683                     }
684 
685                     len = signal_strcat(filepath, eol);
686 
687                     if(source == 0)
688                     {
689                         writefully(fd, filepath, len);
690                         fsync(fd);
691                     }
692                     else
693                     {
694                         log_err(filepath);
695                     }
696 
697 #if defined(__GLIBC__) || defined(__gnu_hurd__)
698                     void* buffer[MAXTRACE];
699                     char** strings;
700                     int n = backtrace(buffer, MAXTRACE);
701                     int i;
702                     time_t now = time(NULL);
703 
704                     filepath[0] = '\0';
705                     signal_strcat(filepath, "got signal ");
706                     signal_int2str(number, signo);
707                     signal_strcat(filepath, number);
708                     signal_strcat(filepath, " at time=");
709                     signal_int2str(number, now);
710                     signal_strcat(filepath, number);
711                     signal_strcat(filepath, " for address ");
712 
713                     signal_ptr2str(number, info->si_addr);
714                     signal_strcat(filepath, number);
715                     len = signal_strcat(filepath, eol);
716 
717                     if(source == 0)
718                     {
719                         writefully(fd, filepath, len);
720                         fsync(fd);
721                     }
722                     else
723                     {
724                         log_err(filepath);
725                     }
726 
727 #if __linux__
728                     ucontext_t* ucontext = (ucontext_t*)context;
729 
730                     /*
731                      * cpu registers dump, if supported
732                      * this helps a lot if there is no core dump available
733                      */
734 
735 #ifdef __x86_64__
736                     // specific x86_64 information
737 
738                     struct text_idx
739                     {
740                         const char* name;
741                         int index;
742                     };
743 
744                     static struct text_idx text_idx[18] =
745                     {
746                         {"rax", REG_RAX},
747                         {"rcx", REG_RCX},
748                         {"rdx", REG_RDX},
749                         {"rbx", REG_RBX},
750                         {"rsi", REG_RSI},
751                         {"rdi", REG_RDI},
752                         {"rsp", REG_RSP},
753                         {"rbp", REG_RBP},
754                         {"r8 ", REG_R8},
755                         {"r9 ", REG_R9},
756                         {"r10", REG_R10},
757                         {"r11", REG_R11},
758                         {"r12", REG_R12},
759                         {"r13", REG_R13},
760                         {"r14", REG_R14},
761                         {"r15", REG_R15},
762                         {"rip", REG_RIP},
763                         {"efl", REG_EFL}
764                     };
765 
766                     for(int i = 0; i < 18; ++i)
767                     {
768                         filepath[0] = '\0';
769                         signal_strcat(filepath, text_idx[i].name);
770                         signal_strcat(filepath, "=");
771                         signal_longlong2hexstr(number, ucontext->uc_mcontext.gregs[text_idx[i].index]);
772                         signal_strcat(filepath, number);
773                         len = signal_strcat(filepath, eol);
774 
775                         if(source == 0)
776                         {
777                             writefully(fd, filepath, len);
778                             fsync(fd);
779                         }
780                         else
781                         {
782                             log_err(filepath);
783                         }
784                     }
785 #elif defined(__i386__)
786                     struct text_idx
787                     {
788                         const char* name;
789                         int index;
790                     };
791 
792                     static struct text_idx text_idx[10] =
793                     {
794                         {"eax", REG_EAX},
795                         {"ecx", REG_ECX},
796                         {"edx", REG_EDX},
797                         {"ebx", REG_EBX},
798                         {"esi", REG_ESI},
799                         {"edi", REG_EDI},
800                         {"esp", REG_ESP},
801                         {"ebp", REG_EBP},
802                         {"rip", REG_EIP},
803                         {"efl", REG_EFL}
804                     };
805 
806                     for(int i = 0; i < 10; ++i)
807                     {
808                         filepath[0] = '\0';
809                         signal_strcat(filepath, text_idx[i].name);
810                         signal_strcat(filepath, "=");
811                         signal_int2hexstr(number, ucontext->uc_mcontext.gregs[text_idx[i].index]);
812                         signal_strcat(filepath, number);
813                         len = signal_strcat(filepath, eol);
814 
815                         if(source == 0)
816                         {
817                             writefully(fd, filepath, len);
818                             fsync(fd);
819                         }
820                         else
821                         {
822                             log_err(filepath);
823                         }
824                     }
825 #else // not x86_64 nor i386
826                     // cpu registers dump not supported
827 #endif
828 
829 #endif // linux
830                     strings = backtrace_symbols(buffer, n);
831 
832                     if(strings != NULL)
833                     {
834                         for(i = 0; i < n; i++)
835                         {
836                             filepath[0] = '\0';
837                             signal_strcat(filepath, "\t[");
838                             signal_int2str(number, i);
839                             signal_strcat(filepath, number);
840                             signal_strcat(filepath, "]: ");
841                             signal_strcat(filepath, strings[i]);
842                             len = signal_strcat(filepath, eol);
843 
844                             if(source == 0)
845                             {
846                                 writefully(fd, filepath, len);
847                                 fsync(fd);
848                             }
849                             else
850                             {
851                                 log_err(filepath);
852                             }
853                         }
854                     }
855                     else
856                     {
857                         filepath[0] = '\0';
858                         signal_strcat(filepath, "no backtrace available: ");
859                         signal_int2str(number, errno);
860                         signal_strcat(filepath, number);
861                         len = signal_strcat(filepath, eol);
862 
863                         if(source == 0)
864                         {
865                             writefully(fd, filepath, len);
866                             fsync(fd);
867                         }
868                         else
869                         {
870                             log_err(filepath);
871                         }
872                     }
873 
874                     filepath[0] = '\0';
875                     signal_strcat(filepath, "pid: ");
876                     signal_int2str(number, getpid_ex());
877                     signal_strcat(filepath, number);
878                     signal_strcat(filepath, " ");
879                     signal_strcat(filepath, "thread id: ");
880 
881                     thread_t self = thread_self();
882 
883                     if(sizeof(self) >= sizeof(u64))
884                     {
885                         signal_longlong2hexstr(number,(u64)self);
886                     }
887                     else
888                     {
889                         signal_int2hexstr(number,(u32)self);
890                     }
891 
892                     signal_strcat(filepath, number);
893                     len = signal_strcat(filepath, eol);
894 
895                     if(source == 0)
896                     {
897                         writefully(fd, filepath, len);
898                         fsync(fd); // fd IS initialised : (source == 0) => fd set
899                     }
900                     else
901                     {
902                         log_err(filepath);
903                     }
904 
905 #if __linux__ && (defined(__x86_64__) || defined(__i386__)) && (_BSD_SOURCE || _SVID_SOURCE || _DEFAULT_SOURCE)
906                     // dump more information about the memory address of the error
907 #define PAGESIZE 4096
908 #define LINESIZE 32
909                     const u8 *addr = (u8*)info->si_addr;
910                     for(;;)
911                     {
912                         u8 *page_addr = (u8*)(((intptr)addr) & ~(PAGESIZE - 1));
913                         unsigned char vec[1];
914 
915                         if(mincore(page_addr, PAGESIZE, vec) == 0)
916                         {
917                             // memory is resident
918 
919                             for(const u8* p = page_addr; p < &page_addr[PAGESIZE]; p += 32)
920                             {
921                                 filepath[0] = '\0';
922                                 signal_ptr2str(number, p);
923                                 signal_strcat(filepath, number);
924                                 signal_strcat(filepath, " | ");
925                                 for(int i = 0; i < LINESIZE; ++i)
926                                 {
927                                     signal_char2hexstr(number, p[i]);
928                                     signal_strcat(filepath, number);
929                                     signal_strcat(filepath, " ");
930                                 }
931                                 len = signal_strcat(filepath, "| ");
932                                 for(int i = 0; i < LINESIZE; ++i)
933                                 {
934                                     u8 c = p[i];
935                                     if(c < 32 || c >= 127)
936                                     {
937                                         c = '.';
938                                     }
939                                     filepath[len + i] = c;
940                                 }
941                                 len += LINESIZE;
942 
943                                 if(source == 0)
944                                 {
945                                     writefully(fd, filepath, len);
946                                     fsync(fd); // fd IS initialised : (source == 0) => fd set
947                                 }
948                                 else
949                                 {
950                                     log_err(filepath);
951                                 }
952                             }
953 
954                             // dump enough memory to make sense
955 
956                             if(&page_addr[PAGESIZE] >= &addr[32])
957                             {
958                                 break;
959                             }
960                         }
961                         else
962                         {
963                             int err = errno;
964 
965                             if(err == ENOMEM)
966                             {
967                                 // memory is not mapped
968                                 filepath[0] = '\0';
969                                 signal_strcat(filepath, "page at ");
970                                 signal_ptr2str(number, page_addr);
971                                 signal_strcat(filepath, number);
972                                 len = signal_strcat(filepath, " is not mapped.");
973                             }
974                             else
975                             {
976                                 //
977                                 filepath[0] = '\0';
978                                 signal_strcat(filepath, "could not get information for page at ");
979                                 signal_ptr2str(number, page_addr);
980                                 signal_strcat(filepath, number);
981                                 signal_strcat(filepath, " : errno = ");
982                                 signal_int2str(number, err);
983                                 len = signal_strcat(filepath, number);
984                             }
985 
986                             if(source == 0)
987                             {
988                                 writefully(fd, filepath, len);
989                                 fsync(fd); // fd IS initialised : (source == 0) => fd set
990                             }
991                             else
992                             {
993                                 log_err(filepath);
994                             }
995 
996                             break;
997                         }
998                     }
999 
1000 #endif // linux && mincore supported
1001 
1002 #elif defined(__sun)
1003                     filepath[0] = '\0';
1004                     signal_strcat(filepath, "got signal ");
1005                     signal_int2str(number, signo);
1006                     signal_strcat(filepath, number);
1007 
1008                     signal_strcat(filepath, eol);
1009                     if(source == 0) // 0 -> output to file, else to the logger if it's on
1010                     {
1011                         writefully(fd, filepath, len);
1012                         printstack(fd);
1013                         fsync(fd);
1014                     }
1015                     else
1016                     {
1017                         signal_strcat(filepath, "stack trace dumped in ");
1018                         signal_strcat(filepath, signal_dump_path);
1019                         signal_strcat(filepath, "/");
1020                         signal_strcat(filepath, "sig-");
1021                         signal_int2str(number, signo);
1022                         signal_strcat(filepath, number);
1023                         signal_strcat(filepath, "-");
1024                         signal_int2str(number, getpid_ex());
1025                         signal_strcat(filepath, number);
1026 
1027                         log_err(filepath);
1028                     }
1029 #else
1030                     filepath[0] = '\0';
1031                     signal_strcat(filepath, "got signal ");
1032                     signal_int2str(number, signo);
1033                     signal_strcat(filepath, number);
1034                     len = signal_strcat(filepath, "\nno backtrace available\n");
1035 
1036                     if(source == 0)
1037                     {
1038                         writefully(fd, filepath, len);
1039                         fsync(fd);
1040                     }
1041                     else
1042                     {
1043                         log_err(filepath);
1044                     }
1045 #endif
1046                     if(source == 0)
1047                     {
1048                         close_ex(fd);
1049                     }
1050 
1051                 } // for both sources
1052 
1053                     /**
1054                      * Do NOT free(strings) :
1055                      * If the memory is corrupted, this is one more chance to crash
1056                      *
1057                      */
1058             } // if sigsegv_trytrace
1059 
1060             /* There COULD be some relevant information in the logger */
1061             /* try to flush it */
1062 
1063             if(sigsegv_tryloggerflush)
1064             {
1065                 sigsegv_tryloggerflush = FALSE;
1066                 logger_flush();
1067                 log_err("CRITICAL ERROR");
1068                 logger_flush();
1069             }
1070 
1071             debug_malloc_hook_tracked_dump();
1072             flushout();
1073 
1074             errno = errno_value;
1075 
1076             break;
1077         }
1078 #endif
1079 
1080         default:
1081         {
1082             if(signal_handlers[signo].handler != NULL) // NULL is right, don't use SIGNAL_HANDLER_NULL
1083             {
1084                 signal_send_to_thread(signo);
1085             }
1086             break;
1087         }
1088     }
1089 }
1090 
1091 /** \brief initialize the signals
1092  *
1093  *  @param NONE
1094  *
1095  *  @return NONE
1096  *
1097  */
1098 int
signal_handler_init()1099 signal_handler_init()
1100 {
1101     int fds[2];
1102 
1103     log_debug("signal_handler_init()");
1104 
1105     if((signal_handler_read_fd >= 0) || (signal_handler_write_fd >= 0))
1106     {
1107         log_debug("signal_handler_init() : already initialised");
1108 
1109         return INVALID_STATE_ERROR; // invalid status
1110     }
1111 
1112     if(pipe(fds) < 0)
1113     {
1114         int pipe_err = ERRNO_ERROR;
1115 
1116         log_debug("signal_handler_init(): %r", pipe_err);
1117 
1118         return pipe_err;
1119     }
1120 
1121     signal_handler_read_fd = fds[0];
1122     signal_handler_write_fd = fds[1];
1123 
1124     int write_fd_flags = fcntl(signal_handler_write_fd, F_GETFL, 0);
1125     write_fd_flags |= O_NONBLOCK;
1126     if(fcntl(signal_handler_write_fd, F_SETFL, write_fd_flags) < 0)
1127     {
1128         int fcntl_err = ERRNO_ERROR;
1129 
1130         log_debug("signal_handler_init(): %r", fcntl_err);
1131 
1132         return fcntl_err;
1133     }
1134 
1135     int thread_errcode;
1136 
1137     if((thread_errcode = thread_create(&signal_thread, signal_handler_thread, NULL)) != 0)
1138     {
1139         close_ex(signal_handler_read_fd);
1140         close_ex(signal_handler_write_fd);
1141 
1142         signal_handler_read_fd = -1;
1143         signal_handler_write_fd = -1;
1144 
1145         log_debug("signal_handler_init(): %r", thread_errcode);
1146 
1147         return thread_errcode;
1148     }
1149 
1150     static const u8 handled_signals[] =
1151     {
1152         SIGHUP,		/* Hangup (POSIX).  */
1153         SIGINT,		/* Interrupt (ANSI).  */
1154         SIGQUIT,	/* Quit (POSIX).  */
1155         SIGIOT,		/* IOT trap (4.2 BSD).  */
1156         SIGUSR1,	/* User-defined signal 1 (POSIX).  */
1157 #if SIGNAL_HOOK_COREDUMP
1158         SIGABRT,	/* Abort (ANSI).  */
1159         SIGILL,		/* Illegal instruction (ANSI).  */	    /* ERROR/EXIT */
1160         SIGBUS,		/* BUS error (4.2 BSD).  */
1161         SIGFPE,		/* Floating-point exception (ANSI).  */	    /* ERROR/EXIT */
1162         SIGSEGV,	/* Segmentation violation (ANSI).  */	    /* ERROR/EXIT */
1163 #endif
1164         SIGUSR2,	/* User-defined signal 2 (POSIX).  */
1165         SIGALRM,	/* Alarm clock (POSIX).  */
1166         SIGTERM,	/* Termination (ANSI).  */
1167     /*	SIGSTKFLT,*/	/* Stack fault.  */
1168         SIGCHLD,	/* Child status has changed (POSIX).  */
1169         SIGCONT,	/* Continue (POSIX).  */
1170         SIGTSTP,	/* Keyboard stop (POSIX).  */
1171         SIGTTIN,	/* Background read from tty (POSIX).  */
1172         SIGTTOU,	/* Background write to tty (POSIX).  */
1173         SIGURG,		/* Urgent condition on socket (4.2 BSD).  */
1174         SIGXCPU,	/* CPU limit exceeded (4.2 BSD).  */
1175         SIGXFSZ,	/* File size limit exceeded (4.2 BSD).  */
1176         0
1177     };
1178 
1179     static const u8 ignored_signals[] =
1180     {
1181         SIGPIPE,	/* Broken pipe (POSIX).  */
1182         0
1183     };
1184 
1185     struct sigaction action;
1186     struct sigaction error_action;
1187     int signal_idx;
1188 
1189     ZEROMEMORY(&action, sizeof(action));
1190     action.sa_sigaction = signal_handler;
1191 #ifdef SA_NOCLDWAIT
1192     action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP | SA_NOCLDWAIT;
1193 #else /// @note 20151119 edf -- quick fix for Debian Hurd i386, and any other system missing SA_NOCLDWAIT
1194     action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP;
1195 #endif
1196 
1197     ZEROMEMORY(&error_action, sizeof(error_action));
1198     error_action.sa_sigaction = signal_handler;
1199 #ifdef SA_NOCLDWAIT
1200     error_action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESETHAND;
1201 #else /// @note 20151119 edf -- quick fix for Debian Hurd i386, and any other system missing SA_NOCLDWAIT
1202     error_action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP | SA_RESETHAND;
1203 #endif
1204 
1205     for(signal_idx = 0; handled_signals[signal_idx] != 0; signal_idx++)
1206     {
1207         switch(signal_idx)
1208         {
1209             case SIGBUS:
1210             case SIGFPE:
1211             case SIGILL:
1212             case SIGSEGV:
1213             case SIGABRT:
1214             {
1215                 sigemptyset(&error_action.sa_mask);    /* can interrupt the interrupt */
1216                 break;
1217             }
1218             default:
1219             {
1220                 sigfillset(&action.sa_mask);    /* don't interrupt the interrupt */
1221                 break;
1222             }
1223         }
1224         sigaction(handled_signals[signal_idx], &action, NULL);
1225     }
1226 
1227     action.sa_handler = SIG_IGN;
1228 
1229     for(signal_idx = 0; ignored_signals[signal_idx] != 0; ++signal_idx)
1230     {
1231         sigaction(ignored_signals[signal_idx], &action, NULL);
1232     }
1233 
1234     log_debug("signal_handler_init() done");
1235 
1236     return SUCCESS;
1237 }
1238 
1239 signal_handler_cb
signal_handler_get(u8 signum)1240 signal_handler_get(u8 signum)
1241 {
1242     if(signum < SIGNAL_MAX)
1243     {
1244         return signal_handlers[signum].handler;
1245     }
1246     else
1247     {
1248         return NULL;
1249     }
1250 }
1251 
1252 void
signal_handler_set(u8 signum,signal_handler_cb handler)1253 signal_handler_set(u8 signum, signal_handler_cb handler)
1254 {
1255     if(handler != NULL)
1256     {
1257         struct sigaction action;
1258         struct sigaction error_action;
1259 
1260         ZEROMEMORY(&action, sizeof(action));
1261         action.sa_sigaction = signal_handler;
1262     #ifdef SA_NOCLDWAIT
1263         action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP | SA_NOCLDWAIT;
1264     #else /// @note 20151119 edf -- quick fix for Debian Hurd i386, and any other system missing SA_NOCLDWAIT
1265         action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP;
1266     #endif
1267 
1268         ZEROMEMORY(&error_action, sizeof(error_action));
1269         error_action.sa_sigaction = signal_handler;
1270     #ifdef SA_NOCLDWAIT
1271         error_action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESETHAND;
1272     #else /// @note 20151119 edf -- quick fix for Debian Hurd i386, and any other system missing SA_NOCLDWAIT
1273         error_action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP | SA_RESETHAND;
1274     #endif
1275         sigfillset(&action.sa_mask);    /* don't interrupt the interrupt */
1276 
1277         signal_handlers[signum].handler = handler;
1278 
1279         sigaction(signum, &action, NULL);
1280     }
1281     else
1282     {
1283         signal(signum, SIG_DFL);
1284 
1285         signal_handlers[signum].handler = NULL;
1286     }
1287 }
1288 
1289 void
signal_handler_finalize()1290 signal_handler_finalize()
1291 {
1292     log_debug("signal_handler_finalize()");
1293 
1294     if(signal_handler_write_fd >= 0)
1295     {
1296         for(int signum = 0; signum < SIGNAL_MAX; ++signum)
1297         {
1298             if(signal_handlers[signum].handler != NULL) // NULL is right
1299             {
1300                 signal_handler_set(signum, NULL);
1301             }
1302         }
1303 
1304         log_debug1("signal: pipe not closed yet");
1305 
1306         mutex_lock(&signal_mutex);
1307         thread_t signal_thread_local = signal_thread;
1308         mutex_unlock(&signal_mutex);
1309 
1310         if(signal_handler_read_fd >= 0)
1311         {
1312             u8 stop_value = MAX_U8;
1313 
1314             if(signal_thread_local != 0)
1315             {
1316                 log_debug1("signal: handler is still running");
1317 
1318                 writefully(signal_handler_write_fd, &stop_value, sizeof(stop_value));
1319                 thread_join(signal_thread_local, NULL);
1320                 mutex_lock(&signal_mutex);
1321                 signal_thread = 0;
1322                 mutex_unlock(&signal_mutex);
1323 
1324                 log_debug1("signal: handler has stopped");
1325             }
1326             else
1327             {
1328                 log_debug1("signal: handler is not running anymore");
1329             }
1330 
1331             int signal_handler_read_fd_local = signal_handler_read_fd;
1332 
1333             if(signal_handler_read_fd_local >= 0)
1334             {
1335                 close_ex(signal_handler_read_fd_local);
1336                 mutex_lock(&signal_mutex);
1337                 signal_handler_read_fd = -1;
1338                 mutex_unlock(&signal_mutex);
1339             }
1340         }
1341         else
1342         {
1343             if(signal_thread_local != 0)
1344             {
1345                 log_debug1("signal: waiting for the handler to stop");
1346 
1347                 thread_join(signal_thread_local, NULL);
1348                 mutex_lock(&signal_mutex);
1349                 signal_thread = 0;
1350                 mutex_unlock(&signal_mutex);
1351             }
1352 
1353             log_debug1("signal: handler has stopped");
1354         }
1355 
1356         close_ex(signal_handler_write_fd);
1357         signal_handler_write_fd = -1;
1358     }
1359     else
1360     {
1361         if(signal_handler_read_fd >= 0)
1362         {
1363             log_err("signal: invalid pipe status r:%i>=0 && w:%i>=0",
1364                     signal_handler_read_fd,
1365                     signal_handler_write_fd);
1366         }
1367 
1368         if(signal_thread != 0)
1369         {
1370             log_err("signal: handler is unexpectedly still running");
1371         }
1372     }
1373 
1374     log_debug("signal_handler_finalize() done");
1375 }
1376 
1377 #else // WIN32
1378 
1379 #include "dnscore/signals.h"
1380 
1381 int
signal_handler_init()1382 signal_handler_init()
1383 {
1384 }
1385 
1386 signal_handler_cb
signal_handler_get(u8 signum)1387 signal_handler_get(u8 signum)
1388 {
1389 }
1390 
1391 void
signal_handler_set(u8 signum,signal_handler_cb handler)1392 signal_handler_set(u8 signum, signal_handler_cb handler)
1393 {
1394 }
1395 
1396 void
signal_handler_finalize()1397 signal_handler_finalize()
1398 {
1399 }
1400 
1401 #endif
1402 
1403 /** @} */
1404