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