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