Only register fr_fault signal handlers if we're not running under a debugger
[freeradius.git] / src / lib / debug.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16
17 /**
18  * @file debug.c
19  * @brief Various functions to aid in debugging
20  *
21  * @copyright 2013  The FreeRADIUS server project
22  * @copyright 2013  Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  */
24 #include <assert.h>
25 #include <freeradius-devel/libradius.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28
29 #if defined(HAVE_MALLOPT) && defined(HAVE_MALLOC_H)
30 #  include <malloc.h>
31 #endif
32
33 /*
34  *      runtime backtrace functions are not POSIX but are included in
35  *      glibc, OSX >= 10.5 and various BSDs
36  */
37 #ifdef HAVE_EXECINFO
38 #  include <execinfo.h>
39 #endif
40
41 #ifdef HAVE_SYS_PRCTL_H
42 #  include <sys/prctl.h>
43 #endif
44
45 #ifdef HAVE_SYS_PTRACE_H
46 #  include <sys/ptrace.h>
47 #  if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
48 #    define PTRACE_ATTACH PT_ATTACH
49 #  endif
50 #  if !defined(PTRACE_CONT) && defined(PT_CONTINUE)
51 #    define PTRACE_CONT PT_CONTINUE
52 #  endif
53 #  if !defined(PTRACE_DETACH) && defined(PT_DETACH)
54 #    define PTRACE_DETACH PT_DETACH
55 #  endif
56 #endif
57
58 #ifdef HAVE_SYS_RESOURCE_H
59 #  include <sys/resource.h>
60 #endif
61
62 #ifdef HAVE_PTHREAD_H
63 #  define PTHREAD_MUTEX_LOCK pthread_mutex_lock
64 #  define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
65 #else
66 #  define PTHREAD_MUTEX_LOCK(_x)
67 #  define PTHREAD_MUTEX_UNLOCK(_x)
68 #endif
69
70 #ifdef HAVE_EXECINFO
71 #  ifndef MAX_BT_FRAMES
72 #    define MAX_BT_FRAMES 128
73 #  endif
74 #  ifndef MAX_BT_CBUFF
75 #    define MAX_BT_CBUFF  1048576                       //!< Should be a power of 2
76 #  endif
77
78 #  ifdef HAVE_PTHREAD_H
79 static pthread_mutex_t fr_debug_init = PTHREAD_MUTEX_INITIALIZER;
80 #  endif
81
82 typedef struct fr_bt_info {
83         void            *obj;                           //!< Memory address of the block of allocated memory.
84         void            *frames[MAX_BT_FRAMES];         //!< Backtrace frame data
85         int             count;                          //!< Number of frames stored
86 } fr_bt_info_t;
87
88 struct fr_bt_marker {
89         void            *obj;                           //!< Pointer to the parent object, this is our needle
90                                                         //!< when we iterate over the contents of the circular buffer.
91         fr_cbuff_t      *cbuff;                         //!< Where we temporarily store the backtraces
92 };
93 #endif
94
95 static char panic_action[512];                          //!< The command to execute when panicking.
96 static fr_fault_cb_t panic_cb = NULL;                   //!< Callback to execute whilst panicking, before the
97                                                         //!< panic_action.
98 static fr_fault_log_t fr_fault_log = NULL;              //!< Function to use to process logging output.
99 static int fr_fault_log_fd = STDERR_FILENO;             //!< Where to write debug output.
100
101 static int debugger_attached = -1;                      //!< Whether were attached to by a debugger.
102
103 #ifdef HAVE_SYS_RESOURCE_H
104 static struct rlimit core_limits;
105 #endif
106
107 static TALLOC_CTX *talloc_null_ctx;
108 static TALLOC_CTX *talloc_autofree_ctx;
109
110 #define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__)
111
112 #ifdef HAVE_SYS_PTRACE_H
113 #  ifdef __linux__
114 #    define _PTRACE(_x, _y) ptrace(_x, _y, NULL, NULL)
115 #  else
116 #    define _PTRACE(_x, _y) ptrace(_x, _y, NULL, 0)
117 #  endif
118
119 /** Determine if we're running under a debugger by attempting to attach using pattach
120  *
121  * @return 0 if we're not, 1 if we are, -1 if we can't tell.
122  */
123 static int fr_debugger_attached(void)
124 {
125         int pid;
126
127         int from_child[2] = {-1, -1};
128
129         if (pipe(from_child) < 0) {
130                 fr_strerror_printf("Debugger check failed: Error opening internal pipe: %s", fr_syserror(errno));
131                 return -1;
132         }
133
134         pid = fork();
135         if (pid == -1) {
136                 fr_strerror_printf("Debugger check failed: Error forking: %s", fr_syserror(errno));
137                 return -1;
138         }
139
140         /* Child */
141         if (pid == 0) {
142                 int8_t ret = 0;
143                 int ppid = getppid();
144
145                 /* Close parent's side */
146                 close(from_child[0]);
147
148                 if (_PTRACE(PTRACE_ATTACH, ppid) == 0) {
149                         /* If we attached then we're not running under a debugger */
150                         write(from_child[1], &ret, sizeof(ret));
151
152                         /* Wait for the parent to stop and continue it */
153                         waitpid(ppid, NULL, 0);
154                         _PTRACE(PTRACE_CONT, ppid);
155
156                         /* Detach */
157                         _PTRACE(PTRACE_DETACH, ppid);
158                         exit(0);
159                 }
160
161                 ret = 1;
162                 /* Something is already attached */
163                 write(from_child[1], &ret, 1);
164
165                 exit(0);
166         /* Parent */
167         } else {
168                 int8_t ret = -1;
169
170                 /*
171                  *      The child writes a 1 if pattach failed else 0.
172                  *
173                  *      This read may be interrupted by pattach,
174                  *      which is why we need the loop.
175                  */
176                 while ((read(from_child[0], &ret, 1) < 0) && (errno == EINTR));
177
178                 /* Ret not updated */
179                 if (ret < 0) {
180                         fr_strerror_printf("Debugger check failed: Error getting status from child: %s",
181                                            fr_syserror(errno));
182                 }
183
184                 /* Close the pipes here (if we did it above, it might race with pattach) */
185                 close(from_child[1]);
186                 close(from_child[0]);
187
188                 /* Collect the status of the child */
189                 waitpid(pid, NULL, 0);
190
191                 return ret;
192         }
193 }
194 #else
195 static int fr_debugger_attached(void)
196 {
197         fr_strerror_printf("Debugger check failed: PTRACE not available");
198
199         return -1;
200 }
201 #endif
202
203 /** Break in debugger (if were running under a debugger)
204  *
205  * If the server is running under a debugger this will raise a
206  * SIGTRAP which will pause the running process.
207  *
208  * If the server is not running under debugger then this will do nothing.
209  */
210 void fr_debug_break(void)
211 {
212         if (debugger_attached == -1) {
213                 debugger_attached = fr_debugger_attached();
214         }
215
216         if (debugger_attached == 1) {
217                 fprintf(stderr, "Debugger detected, raising SIGTRAP\n");
218                 fflush(stderr);
219
220                 raise(SIGTRAP);
221         }
222 }
223
224 #ifdef HAVE_EXECINFO
225 /** Print backtrace entry for a given object
226  *
227  * @param cbuff to search in.
228  * @param obj pointer to original object
229  */
230 void backtrace_print(fr_cbuff_t *cbuff, void *obj)
231 {
232         fr_bt_info_t *p;
233         bool found = false;
234
235         while ((p = fr_cbuff_rp_next(cbuff, NULL))) {
236                 if ((p->obj == obj) || !obj) {
237                         found = true;
238
239                         fprintf(stderr, "Stacktrace for: %p\n", p->obj);
240                         backtrace_symbols_fd(p->frames, p->count, STDERR_FILENO);
241                 }
242         };
243
244         if (!found) {
245                 fprintf(stderr, "No backtrace available for %p", obj);
246         }
247 }
248
249 /** Generate a backtrace for an object
250  *
251  * If this is the first entry being inserted
252  */
253 int fr_backtrace_do(fr_bt_marker_t *marker)
254 {
255         fr_bt_info_t *bt;
256
257         if (!fr_assert(marker->obj) || !fr_assert(marker->cbuff)) return -1;
258
259         bt = talloc_zero(NULL, fr_bt_info_t);
260         if (!bt) return -1;
261
262         bt->obj = marker->obj;
263         bt->count = backtrace(bt->frames, MAX_BT_FRAMES);
264
265         fr_cbuff_rp_insert(marker->cbuff, bt);
266
267         return 0;
268 }
269
270 /** Inserts a backtrace marker into the provided context
271  *
272  * Allows for maximum laziness and will initialise a circular buffer if one has not already been created.
273  *
274  * Code augmentation should look something like:
275 @verbatim
276         // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it
277         static fr_cbuff_t *my_obj_bt;
278
279         my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) {
280                 my_obj_t *this;
281
282                 this = talloc(ctx, my_obj_t);
283
284                 // Attach backtrace marker to object
285                 backtrace_attach(&my_obj_bt, this);
286
287                 return this;
288         }
289 @endverbatim
290  *
291  * Then, later when a double free occurs:
292 @verbatim
293         (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>)
294 @endverbatim
295  *
296  * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument
297  * values, but should at least show the code path taken.
298  *
299  * @param cbuff this should be a pointer to a static *fr_cbuff.
300  * @param obj we want to generate a backtrace for.
301  */
302 fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj)
303 {
304         fr_bt_marker_t *marker;
305
306         if (*cbuff == NULL) {
307                 PTHREAD_MUTEX_LOCK(&fr_debug_init);
308                 /* Check again now we hold the mutex - eww*/
309                 if (*cbuff == NULL) *cbuff = fr_cbuff_alloc(NULL, MAX_BT_CBUFF, true);
310                 PTHREAD_MUTEX_UNLOCK(&fr_debug_init);
311         }
312
313         marker = talloc(obj, fr_bt_marker_t);
314         if (!marker) {
315                 return NULL;
316         }
317
318         marker->obj = (void *) obj;
319         marker->cbuff = *cbuff;
320
321         fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
322         /*
323          *      Generate the backtrace for memory allocation
324          */
325         fr_backtrace_do(marker);
326         talloc_set_destructor(marker, fr_backtrace_do);
327
328         return marker;
329 }
330 #else
331 void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj)
332 {
333         fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
334 }
335 fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj)
336 {
337         fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
338         abort();
339 }
340 #endif /* ifdef HAVE_EXECINFO */
341
342 static int _panic_on_free(UNUSED char *foo)
343 {
344         fr_fault(SIGUSR1);
345         return -1;      /* this should make the free fail */
346 }
347
348 /** Insert memory into the context of another talloc memory chunk which
349  * causes a panic when freed.
350  *
351  * @param ctx TALLOC_CTX to monitor for frees.
352  */
353 void fr_panic_on_free(TALLOC_CTX *ctx)
354 {
355         char *ptr;
356
357         ptr = talloc(ctx, char);
358         talloc_set_destructor(ptr, _panic_on_free);
359 }
360
361 /** Set the dumpable flag, also controls whether processes can PATTACH
362  *
363  * @param dumpable whether we should allow core dumping
364  */
365 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
366 static int fr_set_dumpable_flag(bool dumpable)
367 {
368         if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) {
369                 fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s",
370                                    fr_syserror(errno));
371                 return -1;
372         }
373
374         return 0;
375 }
376 #else
377 static int fr_set_dumpable_flag(UNUSED bool dumpable)
378 {
379         fr_strerror_printf("Changing value of PR_DUMPABLE not supported on this system");
380         return -2;
381 }
382 #endif
383
384 /** Get the processes dumpable flag
385  *
386  */
387 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_DUMPABLE)
388 static int fr_get_dumpable_flag(void)
389 {
390         int ret;
391
392         ret = prctl(PR_GET_DUMPABLE);
393         if (ret < 0) {
394                 fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
395                 return -1;
396         }
397
398         /*
399          *  Linux is crazy and prctl sometimes returns 2 for disabled
400          */
401         if (ret != 1) return 0;
402         return 1;
403 }
404 #else
405 static int fr_get_dumpable_flag(void)
406 {
407         fr_strerror_printf("Getting value of PR_DUMPABLE not supported on this system");
408         return -2;
409 }
410 #endif
411
412
413 /** Get the current maximum for core files
414  *
415  * Do this before anything else so as to ensure it's properly initialized.
416  */
417 int fr_set_dumpable_init(void)
418 {
419 #ifdef HAVE_SYS_RESOURCE_H
420         if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
421                 fr_strerror_printf("Failed to get current core limit:  %s", fr_syserror(errno));
422                 return -1;
423         }
424 #endif
425         return 0;
426 }
427
428 /** Enable or disable core dumps
429  *
430  * @param allow_core_dumps whether to enable or disable core dumps.
431  */
432 int fr_set_dumpable(bool allow_core_dumps)
433 {
434         /*
435          *      If configured, turn core dumps off.
436          */
437         if (!allow_core_dumps) {
438 #ifdef HAVE_SYS_RESOURCE_H
439                 struct rlimit no_core;
440
441                 no_core.rlim_cur = 0;
442                 no_core.rlim_max = 0;
443
444                 if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
445                         fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));
446
447                         return -1;
448                 }
449 #endif
450                 return 0;
451         }
452
453         if (fr_set_dumpable_flag(true) < 0) return -1;
454
455         /*
456          *      Reset the core dump limits to their original value.
457          */
458 #ifdef HAVE_SYS_RESOURCE_H
459         if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
460                 fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));
461
462                 return -1;
463         }
464 #endif
465         return 0;
466 }
467
468 /** Check to see if panic_action file is world writeable
469  *
470  * @return 0 if file is OK, else -1.
471  */
472 static int fr_fault_check_permissions(void)
473 {
474         char const *p, *q;
475         size_t len;
476         char filename[256];
477         struct stat statbuf;
478
479         /*
480          *      Try and guess which part of the command is the binary, and check to see if
481          *      it's world writeable, to try and save the admin from their own stupidity.
482          *
483          *      @fixme we should do this properly and take into account single and double
484          *      quotes.
485          */
486         if ((q = strchr(panic_action, ' '))) {
487                 /*
488                  *      need to use a static buffer, because mallocing memory in a signal handler
489                  *      is a bad idea and can result in deadlock.
490                  */
491                 len = snprintf(filename, sizeof(filename), "%.*s", (int)(q - panic_action), panic_action);
492                 if (is_truncated(len, sizeof(filename))) {
493                         fr_strerror_printf("Failed writing panic_action to temporary buffer (truncated)");
494                         return -1;
495                 }
496                 p = filename;
497         } else {
498                 p = panic_action;
499         }
500
501         if (stat(p, &statbuf) == 0) {
502 #ifdef S_IWOTH
503                 if ((statbuf.st_mode & S_IWOTH) != 0) {
504                         fr_strerror_printf("panic_action file \"%s\" is globally writable", p);
505                         return -1;
506                 }
507 #endif
508         }
509
510         return 0;
511 }
512
513 /** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
514  *
515  * @param sig caught
516  */
517 void fr_fault(int sig)
518 {
519         char cmd[sizeof(panic_action) + 20];
520         char *out = cmd;
521         size_t left = sizeof(cmd), ret;
522
523         char const *p = panic_action;
524         char const *q;
525
526         int code;
527
528         /*
529          *      Makes the backtraces slightly cleaner
530          */
531         memset(cmd, 0, sizeof(cmd));
532
533         FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
534
535         /*
536          *      Check for administrator sanity.
537          */
538         if (fr_fault_check_permissions() < 0) {
539                 FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror());
540                 goto finish;
541         }
542
543         /*
544          *      Run the callback if one was registered
545          */
546         if (panic_cb && (panic_cb(sig) < 0)) goto finish;
547
548         /*
549          *      Produce a simple backtrace - They've very basic but at least give us an
550          *      idea of the area of the code we hit the issue in.
551          *
552          *      See below in fr_fault_setup() and
553          *      https://sourceware.org/bugzilla/show_bug.cgi?id=16159
554          *      for why we only print backtraces in debug builds if we're using GLIBC.
555          */
556 #if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
557         {
558                 size_t frame_count, i;
559                 void *stack[MAX_BT_FRAMES];
560                 char **strings;
561
562                 frame_count = backtrace(stack, MAX_BT_FRAMES);
563
564                 FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
565
566                 /*
567                  *      Only use backtrace_symbols() if we don't have a logging fd.
568                  *      If the server has experienced memory corruption, there's
569                  *      a high probability that calling backtrace_symbols() which
570                  *      mallocs more memory, will fail.
571                  */
572                 if (fr_fault_log_fd < 0) {
573                         strings = backtrace_symbols(stack, frame_count);
574                         for (i = 0; i < frame_count; i++) {
575                                 FR_FAULT_LOG("%s", strings[i]);
576                         }
577                         free(strings);
578                 } else {
579                         backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
580                 }
581         }
582 #endif
583
584         /* No panic action set... */
585         if (panic_action[0] == '\0') {
586                 FR_FAULT_LOG("No panic action set");
587                 goto finish;
588         }
589
590         /* Substitute %p for the current PID (useful for attaching a debugger) */
591         while ((q = strstr(p, "%p"))) {
592                 out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid());
593                 if (left <= ret) {
594                 oob:
595                         FR_FAULT_LOG("Panic action too long");
596                         fr_exit_now(1);
597                 }
598                 left -= ret;
599                 p = q + 2;
600         }
601         if (strlen(p) >= left) goto oob;
602         strlcpy(out, p, left);
603
604         FR_FAULT_LOG("Calling: %s", cmd);
605
606         {
607                 bool disable = false;
608
609                 /*
610                  *      Here we temporarily enable the dumpable flag so if GBD or LLDB
611                  *      is called in the panic_action, they can pattach to the running
612                  *      process.
613                  */
614                 if (fr_get_dumpable_flag() == 0) {
615                         if ((fr_set_dumpable_flag(true) < 0) || !fr_get_dumpable_flag()) {
616                                 FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror());
617                         } else {
618                                 disable = true;
619                         }
620                         FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1");
621                 }
622
623                 code = system(cmd);
624
625                 /*
626                  *      We only want to error out here, if dumpable was originally disabled
627                  *      and we managed to change the value to enabled, but failed
628                  *      setting it back to disabled.
629                  */
630                 if (disable) {
631                         FR_FAULT_LOG("Resetting PR_DUMPABLE to 0");
632                         if (fr_set_dumpable_flag(false) < 0) {
633                                 FR_FAULT_LOG("Failed reseting dumpable flag to off: %s", fr_strerror());
634                                 FR_FAULT_LOG("Exiting due to insecure process state");
635                                 fr_exit_now(1);
636                         }
637                 }
638         }
639
640         FR_FAULT_LOG("Panic action exited with %i", code);
641
642 finish:
643 #ifdef SIGUSR1
644         if (sig == SIGUSR1) {
645                 return;
646         }
647 #endif
648         fr_exit_now(1);
649 }
650
651 #ifdef SIGABRT
652 /** Work around debuggers which can't backtrace past the signal handler
653  *
654  * At least this provides us some information when we get talloc errors.
655  */
656 static void _fr_talloc_fault(char const *reason)
657 {
658         fr_fault_log("talloc abort: %s\n", reason);
659         fr_fault(SIGABRT);
660 }
661 #endif
662
663 /** Wrapper to pass talloc log output to our fr_fault_log function
664  *
665  */
666 static void _fr_talloc_log(char const *msg)
667 {
668         fr_fault_log("%s\n", msg);
669 }
670
671 /** Generate a talloc memory report for a context and print to stderr/stdout
672  *
673  * @param ctx to generate a report for, may be NULL in which case the root context is used.
674  */
675 int fr_log_talloc_report(TALLOC_CTX *ctx)
676 {
677         FILE *log;
678         int i = 0;
679         int fd;
680
681         fd = dup(fr_fault_log_fd);
682         if (fd < 0) {
683                 fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno));
684                 return -1;
685         }
686         log = fdopen(fd, "w");
687         if (!log) {
688                 close(fd);
689                 fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno));
690                 return -1;
691         }
692
693         if (!ctx) {
694                 fprintf(log, "Current state of talloced memory:\n");
695                 talloc_report_full(talloc_null_ctx, log);
696         } else {
697                 fprintf(log, "Talloc chunk lineage:\n");
698                 fprintf(log, "%p (%s)", ctx, talloc_get_name(ctx));
699                 while ((ctx = talloc_parent(ctx))) fprintf(log, " < %p (%s)", ctx, talloc_get_name(ctx));
700                 fprintf(log, "\n");
701
702                 do {
703                         fprintf(log, "Talloc context level %i:\n", i++);
704                         talloc_report_full(ctx, log);
705                 } while ((ctx = talloc_parent(ctx)) &&
706                          (talloc_parent(ctx) != talloc_autofree_ctx) && /* Stop before we hit the autofree ctx */
707                          (talloc_parent(ctx) != talloc_null_ctx));      /* Stop before we hit NULL ctx */
708         }
709
710         fclose(log);
711
712         return 0;
713 }
714
715 /** Signal handler to print out a talloc memory report
716  *
717  * @param sig caught
718  */
719 static void _fr_fault_mem_report(int sig)
720 {
721         FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
722
723         if (fr_log_talloc_report(NULL) < 0) fr_perror("memreport");
724 }
725
726 static int _fr_disable_null_tracking(UNUSED bool *p)
727 {
728         talloc_disable_null_tracking();
729         return 0;
730 }
731
732 /** Registers signal handlers to execute panic_action on fatal signal
733  *
734  * May be called multiple time to change the panic_action/program.
735  *
736  * @param cmd to execute on fault. If present %p will be substituted
737  *        for the parent PID before the command is executed, and %e
738  *        will be substituted for the currently running program.
739  * @param program Name of program currently executing (argv[0]).
740  * @return 0 on success -1 on failure.
741  */
742 int fr_fault_setup(char const *cmd, char const *program)
743 {
744         static bool setup = false;
745
746         char *out = panic_action;
747         size_t left = sizeof(panic_action), ret;
748
749         char const *p = cmd;
750         char const *q;
751
752         if (cmd) {
753                 /* Substitute %e for the current program */
754                 while ((q = strstr(p, "%e"))) {
755                         out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
756                         if (left <= ret) {
757                         oob:
758                                 fr_strerror_printf("Panic action too long");
759                                 return -1;
760                         }
761                         left -= ret;
762                         p = q + 2;
763                 }
764                 if (strlen(p) >= left) goto oob;
765                 strlcpy(out, p, left);
766         } else {
767                 *panic_action = '\0';
768         }
769
770         /*
771          *      Check for administrator sanity.
772          */
773         if (fr_fault_check_permissions() < 0) return -1;
774
775         /* Unsure what the side effects of changing the signal handler mid execution might be */
776         if (!setup) {
777                 debugger_attached = fr_debugger_attached();
778
779                 /*
780                  *  These signals can't be properly dealt with in the debugger
781                  *  if we set our own signal handlers
782                  */
783                 if (debugger_attached == 0) {
784 #ifdef SIGSEGV
785                         if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
786 #endif
787 #ifdef SIGBUS
788                         if (fr_set_signal(SIGBUS, fr_fault) < 0) return -1;
789 #endif
790 #ifdef SIGFPE
791                         if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
792 #endif
793
794 #ifdef SIGABRT
795                         if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
796
797                         /*
798                          *  Use this instead of abort so we get a
799                          *  full backtrace with broken versions of LLDB
800                          */
801                         talloc_set_abort_fn(_fr_talloc_fault);
802 #endif
803                 }
804 #ifdef SIGUSR1
805                 if (fr_set_signal(SIGUSR1, fr_fault) < 0) return -1;
806 #endif
807
808 #ifdef SIGUSR2
809                 if (fr_set_signal(SIGUSR2, _fr_fault_mem_report) < 0) return -1;
810 #endif
811
812                 /*
813                  *  Setup the default logger
814                  */
815                 if (!fr_fault_log) fr_fault_set_log_fn(NULL);
816                 talloc_set_log_fn(_fr_talloc_log);
817
818                 /*
819                  *  Needed for memory reports
820                  */
821                 {
822                         TALLOC_CTX *tmp;
823                         bool *marker;
824
825                         tmp = talloc(NULL, bool);
826                         talloc_null_ctx = talloc_parent(tmp);
827                         talloc_free(tmp);
828
829                         /*
830                          *  Disable null tracking on exit, else valgrind complains
831                          */
832                         talloc_autofree_ctx = talloc_autofree_context();
833                         marker = talloc(talloc_autofree_ctx, bool);
834                         talloc_set_destructor(marker, _fr_disable_null_tracking);
835                 }
836
837 #if defined(HAVE_MALLOPT) && !defined(NDEBUG)
838                 /*
839                  *  If were using glibc malloc > 2.4 this scribbles over
840                  *  uninitialised and freed memory, to make memory issues easier
841                  *  to track down.
842                  */
843                 if (!getenv("TALLOC_FREE_FILL")) mallopt(M_PERTURB, 0x42);
844                 mallopt(M_CHECK_ACTION, 3);
845 #endif
846
847 #if defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
848                /*
849                 *  We need to pre-load lgcc_s, else we can get into a deadlock
850                 *  in fr_fault, as backtrace() attempts to dlopen it.
851                 *
852                 *  Apparently there's a performance impact of loading lgcc_s,
853                 *  so only do it if this is a debug build.
854                 *
855                 *  See: https://sourceware.org/bugzilla/show_bug.cgi?id=16159
856                 */
857                 {
858                         void *stack[10];
859
860                         backtrace(stack, 10);
861                 }
862 #endif
863         }
864         setup = true;
865
866         return 0;
867 }
868
869 /** Set a callback to be called before fr_fault()
870  *
871  * @param func to execute. If callback returns < 0
872  *      fr_fault will exit before running panic_action code.
873  */
874 void fr_fault_set_cb(fr_fault_cb_t func)
875 {
876         panic_cb = func;
877 };
878
879 /** Default logger, logs output to stderr
880  *
881  */
882 static void CC_HINT(format (printf, 1, 2)) _fr_fault_log(char const *msg, ...)
883 {
884         va_list ap;
885
886         va_start(ap, msg);
887         vfprintf(stderr, msg, ap);
888         va_end(ap);
889 }
890
891
892 /** Set a file descriptor to log panic_action output to.
893  *
894  * @param func to call to output log messages.
895  */
896 void fr_fault_set_log_fn(fr_fault_log_t func)
897 {
898         fr_fault_log = func ? func : _fr_fault_log;
899 }
900
901 /** Set a file descriptor to log memory reports to.
902  *
903  * @param fd to write output to.
904  */
905 void fr_fault_set_log_fd(int fd)
906 {
907         fr_fault_log_fd = fd;
908 }
909
910
911 #ifdef WITH_VERIFY_PTR
912
913 /*
914  *      Verify a VALUE_PAIR
915  */
916 inline void fr_verify_vp(char const *file, int line, VALUE_PAIR const *vp)
917 {
918         if (!vp) {
919                 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR pointer was NULL", file, line);
920                 fr_assert(0);
921                 fr_exit_now(0);
922         }
923
924         (void) talloc_get_type_abort(vp, VALUE_PAIR);
925
926         if (vp->data.ptr) switch (vp->da->type) {
927         case PW_TYPE_OCTETS:
928         case PW_TYPE_TLV:
929         {
930                 size_t len;
931                 TALLOC_CTX *parent;
932
933                 if (!talloc_get_type(vp->data.ptr, uint8_t)) {
934                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
935                                      "uint8_t but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
936                         (void) talloc_get_type_abort(vp->data.ptr, uint8_t);
937                 }
938
939                 len = talloc_array_length(vp->vp_octets);
940                 if (vp->length > len) {
941                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
942                                      "uint8_t data buffer length %zu\n", file, line, vp->da->name, vp->length, len);
943                         fr_assert(0);
944                         fr_exit_now(1);
945                 }
946
947                 parent = talloc_parent(vp->data.ptr);
948                 if (parent != vp) {
949                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
950                                      "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
951                                      file, line, vp->da->name,
952                                      vp, parent, parent ? talloc_get_name(parent) : "NULL");
953                         fr_assert(0);
954                         fr_exit_now(1);
955                 }
956         }
957                 break;
958
959         case PW_TYPE_STRING:
960         {
961                 size_t len;
962                 TALLOC_CTX *parent;
963
964                 if (!talloc_get_type(vp->data.ptr, char)) {
965                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
966                                      "char but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
967                         (void) talloc_get_type_abort(vp->data.ptr, char);
968                 }
969
970                 len = (talloc_array_length(vp->vp_strvalue) - 1);
971                 if (vp->length > len) {
972                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
973                                      "char buffer length %zu\n", file, line, vp->da->name, vp->length, len);
974                         fr_assert(0);
975                         fr_exit_now(1);
976                 }
977
978                 if (vp->vp_strvalue[vp->length] != '\0') {
979                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer not \\0 "
980                                      "terminated\n", file, line, vp->da->name);
981                         fr_assert(0);
982                         fr_exit_now(1);
983                 }
984
985                 parent = talloc_parent(vp->data.ptr);
986                 if (parent != vp) {
987                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" uint8_t buffer is not "
988                                      "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
989                                      file, line, vp->da->name,
990                                      vp, parent, parent ? talloc_get_name(parent) : "NULL");
991                         fr_assert(0);
992                         fr_exit_now(1);
993                 }
994         }
995                 break;
996
997         default:
998                 break;
999         }
1000 }
1001
1002 /*
1003  *      Verify a pair list
1004  */
1005 void fr_verify_list(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps)
1006 {
1007         vp_cursor_t cursor;
1008         VALUE_PAIR *vp;
1009         TALLOC_CTX *parent;
1010
1011         for (vp = fr_cursor_init(&cursor, &vps);
1012              vp;
1013              vp = fr_cursor_next(&cursor)) {
1014                 VERIFY_VP(vp);
1015
1016                 parent = talloc_parent(vp);
1017                 if (expected && (parent != expected)) {
1018                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: Expected VALUE_PAIR \"%s\" to be parented "
1019                                      "by %p (%s), instead parented by %p (%s)\n",
1020                                      file, line, vp->da->name,
1021                                      expected, talloc_get_name(expected),
1022                                      parent, parent ? talloc_get_name(parent) : "NULL");
1023
1024                         fr_log_talloc_report(expected);
1025                         if (parent) fr_log_talloc_report(parent);
1026
1027                         assert(0);
1028                 }
1029
1030         }
1031 }
1032 #endif
1033
1034 bool fr_assert_cond(char const *file, int line, char const *expr, bool cond)
1035 {
1036         if (!cond) {
1037                 FR_FAULT_LOG("SOFT ASSERT FAILED %s[%u]: %s", file, line, expr);
1038 #if !defined(NDEBUG) && defined(SIGUSR1)
1039                 fr_fault(SIGUSR1);
1040 #endif
1041                 return false;
1042         }
1043
1044         return cond;
1045 }
1046
1047 /** Exit possibly printing a message about why we're exiting.
1048  *
1049  * Use the fr_exit(status) macro instead of calling this function
1050  * directly.
1051  *
1052  * @param file where fr_exit() was called.
1053  * @param line where fr_exit() was called.
1054  * @param status we're exiting with.
1055  */
1056 void NEVER_RETURNS _fr_exit(char const *file, int line, int status)
1057 {
1058 #ifndef NDEBUG
1059         char const *error = fr_strerror();
1060
1061         if (error && (status != 0)) {
1062                 FR_FAULT_LOG("EXIT(%i) CALLED %s[%u].  Last error was: %s", status, file, line, error);
1063         } else {
1064                 FR_FAULT_LOG("EXIT(%i) CALLED %s[%u]", status, file, line);
1065         }
1066 #endif
1067         fr_debug_break();       /* If running under GDB we'll break here */
1068
1069         exit(status);
1070 }
1071
1072 /** Exit possibly printing a message about why we're exiting.
1073  *
1074  * Use the fr_exit_now(status) macro instead of calling this function
1075  * directly.
1076  *
1077  * @param file where fr_exit_now() was called.
1078  * @param line where fr_exit_now() was called.
1079  * @param status we're exiting with.
1080  */
1081 void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status)
1082 {
1083 #ifndef NDEBUG
1084         char const *error = fr_strerror();
1085
1086         if (error && (status != 0)) {
1087                 FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u].  Last error was: %s", status, file, line, error);
1088         } else {
1089                 FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u]", status, file, line);
1090         }
1091 #endif
1092         fr_debug_break();       /* If running under GDB we'll break here */
1093
1094         _exit(status);
1095 }