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