The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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/** Functions to help with debugging
18 *
19 * @file src/lib/util/debug.c
20 *
21 * @copyright 2013 The FreeRADIUS server project
22 * @copyright 2013 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
24#include <freeradius-devel/util/debug.h>
25#include <freeradius-devel/util/hash.h>
26#include <freeradius-devel/util/strerror.h>
27#include <freeradius-devel/util/syserror.h>
28
29#include <pthread.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <sys/stat.h>
33#include <sys/wait.h>
34
35#if defined(HAVE_MALLOPT) && defined(HAVE_MALLOC_H)
36# include <malloc.h>
37#endif
38
39/*
40 * runtime backtrace functions are not POSIX but are included in
41 * glibc, OSX >= 10.5 and various BSDs
42 */
43#ifdef HAVE_EXECINFO
44# include <execinfo.h>
45#endif
46
47#ifdef HAVE_SYS_PRCTL_H
48# include <sys/prctl.h>
49#endif
50
51#ifdef HAVE_SYS_PROCCTL_H
52# include <sys/procctl.h>
53#endif
54
55#ifdef HAVE_SYS_PTRACE_H
56# include <sys/ptrace.h>
57# if !defined(PT_ATTACH) && defined(PTRACE_ATTACH)
58# define PT_ATTACH PTRACE_ATTACH
59# endif
60# if !defined(PT_DETACH) && defined(PTRACE_DETACH)
61# define PT_DETACH PTRACE_DETACH
62# endif
63#endif
64
65#ifdef HAVE_SYS_RESOURCE_H
66# include <sys/resource.h>
67#endif
68
69#ifdef __APPLE__
70#include <sys/sysctl.h>
71#endif
72
73#ifdef HAVE_EXECINFO
74# ifndef MAX_BT_FRAMES
75# define MAX_BT_FRAMES 128
76# endif
77# ifndef MAX_BT_CBUFF
78# define MAX_BT_CBUFF 1048576 //!< Should be a power of 2
79# endif
80
81static pthread_mutex_t fr_debug_init = PTHREAD_MUTEX_INITIALIZER;
82
83typedef struct {
84 void *obj; //!< Memory address of the block of allocated memory.
85 void *frames[MAX_BT_FRAMES]; //!< Backtrace frame data
86 int count; //!< Number of frames stored
87} fr_bt_info_t;
88
89struct fr_bt_marker {
90 void *obj; //!< Pointer to the parent object, this is our needle
91 //!< when we iterate over the contents of the circular buffer.
92 fr_fring_t *fring; //!< Where we temporarily store the backtraces
93};
94#endif
95
96static char panic_action[512]; //!< The command to execute when panicking.
97static fr_fault_cb_t panic_cb = NULL; //!< Callback to execute whilst panicking, before the
98 //!< panic_action.
99
100static bool dump_core; //!< Whether we should drop a core on fatal signals.
101
102static int fr_fault_log_fd = STDERR_FILENO; //!< Where to write debug output.
103
104fr_debug_state_t fr_debug_state = DEBUGGER_STATE_UNKNOWN; //!< Whether we're attached to by a debugger.
105
106#ifdef HAVE_SYS_RESOURCE_H
107static struct rlimit init_core_limit;
108#endif
109
110static TALLOC_CTX *talloc_autofree_ctx;
111
112/*
113 * On BSD systems, ptrace(PT_DETACH) uses a third argument for
114 * resume address, with the magic value (void *)1 to resume where
115 * process stopped. Specifying NULL there leads to a crash because
116 * process resumes at address 0.
117 */
118#if defined(HAVE_SYS_PTRACE_H)
119# ifdef __linux__
120# define _PTRACE(_x, _y) ptrace(_x, _y, NULL, NULL)
121# define _PTRACE_DETACH(_x) ptrace(PT_DETACH, _x, NULL, NULL)
122# elif !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(HAVE_SYS_PROCCTL_H)
123# define _PTRACE(_x, _y) ptrace(_x, _y, NULL, 0)
124# define _PTRACE_DETACH(_x) ptrace(PT_DETACH, _x, (void *)1, 0)
125#endif
126
127# ifdef HAVE_CAPABILITY_H
128# include <sys/capability.h>
129# endif
130#endif
131
132#ifdef HAVE_SANITIZER_LSAN_INTERFACE_H
133# include <sanitizer/lsan_interface.h>
134#endif
135
136#ifdef HAVE_SANITIZER_LSAN_INTERFACE_H
137static int lsan_test_pipe[2] = {-1, -1};
138static int lsan_test_pid = -1;
139static int lsan_state = INT_MAX;
140static bool lsan_disable = false; //!< Explicitly disable LSAN
141
142/*
143 * Some versions of lsan_interface.h are broken and don't declare
144 * the prototypes of the functions properly, omitting the zero argument
145 * specifier (void), so we need to disable the warning.
146 *
147 * Observed with clang 5.
148 */
149DIAG_OFF(missing-prototypes)
150/** Callback for LSAN - do not rename
151 *
152 */
153char const CC_HINT(used) *__lsan_default_suppressions(void)
154{
155 return
156 "leak:CRYPTO_THREAD_lock_new\n" /* OpenSSL init leak - reported by heaptrack */
157#if defined(__APPLE__)
158 "leak:*gmtsub*\n"
159 "leak:ImageLoaderMachO::doImageInit\n"
160 "leak:_st_tzset_basic\n"
161 "leak:attachCategories\n"
162 "leak:fork\n"
163 "leak:getaddrinfo\n"
164 "leak:getpwuid_r\n"
165 "leak:libSystem_atfork_child\n"
166 "leak:libsystem_notify\n"
167 "leak:load_images\n"
168 "leak:newlocale\n"
169 /* Perl >= 5.32.0 - Upstream bug, tracked by https://github.com/Perl/perl5/issues/18108 */
170 "leak:perl_construct\n"
171 "leak:realizeClassWithoutSwift\n"
172 "leak:tzset\n"
173 "leak:tzsetwall_basic\n"
174#elif defined(__linux__)
175 "leak:*getpwnam_r*\n" /* libc startup leak - reported by heaptrack */
176 "leak:_dl_init\n" /* dl startup leak - reported by heaptrack */
177 "leak:initgroups\n" /* libc startup leak - reported by heaptrack */
178 "leak:kqueue\n"
179#endif
180 ;
181}
182
183/** Callback for LSAN - do not rename
184 *
185 * Turn off suppressions by default as it interferes with interpreting
186 * output from some of the test utilities.
187 */
188char const CC_HINT(used) *__lsan_default_options(void)
189{
190 return "print_suppressions=0";
191}
192
193/** Callback for LSAN - do not rename
194 *
195 */
196int CC_HINT(used) __lsan_is_turned_off(void)
197{
198 uint8_t ret = 1;
199
200 /* Disable LSAN explicitly - Used for tests involving fork() */
201 if (lsan_disable) return 1;
202
203 /* Parent */
204 if (lsan_test_pid != 0) return 0;
205
206 /* Child */
207 if (write(lsan_test_pipe[1], &ret, sizeof(ret)) < 0) {
208 fprintf(stderr, "Writing LSAN status failed: %s", fr_syserror(errno));
209 }
210 close(lsan_test_pipe[1]);
211 return 0;
212}
213DIAG_ON(missing-prototypes)
214
215/** Determine if we're running under LSAN (Leak Sanitizer)
216 *
217 * @return
218 * - 0 if we're not.
219 * - 1 if we are.
220 * - -1 if we can't tell because of an error.
221 * - -2 if we can't tell because we were compiled with support for the LSAN interface.
222 */
223int fr_get_lsan_state(void)
224{
225 uint8_t ret = 0;
226
227 if (lsan_state != INT_MAX) return lsan_state;/* Use cached result */
228
229 if (pipe(lsan_test_pipe) < 0) {
230 fr_strerror_printf("Failed opening internal pipe: %s", fr_syserror(errno));
231 return -1;
232 }
233
234 lsan_test_pid = fork();
235 if (lsan_test_pid == -1) {
236 fr_strerror_printf("Error forking: %s", fr_syserror(errno));
237 return -1;
238 }
239
240 /* Child */
241 if (lsan_test_pid == 0) {
242 close(lsan_test_pipe[0]); /* Close parent's side */
243 exit(EXIT_SUCCESS); /* Results in LSAN calling __lsan_is_turned_off via onexit handler */
244 }
245
246 /* Parent */
247 close(lsan_test_pipe[1]); /* Close child's side */
248
249 while ((read(lsan_test_pipe[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
250
251 close(lsan_test_pipe[0]); /* Close our side (so we don't leak FDs) */
252
253 /* Collect child */
254 waitpid(lsan_test_pid, NULL, 0);
255
256 lsan_state = ret; /* Cache test results */
257
258 return ret;
259}
260#else
262{
263 fr_strerror_const("Not built with support for LSAN interface");
264 return -2;
265}
266#endif
267
268#if defined(HAVE_SYS_PROCCTL_H)
269int fr_get_debug_state(void)
270{
271 int status;
272
273 if (procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status) == -1) {
274 fr_strerror_printf("Cannot get dumpable flag: procctl(PROC_TRACE_STATUS) failed: %s", fr_syserror(errno));
276 }
277
278 /*
279 * As FreeBSD docs say about "PROC_TRACE_STATUS":
280 *
281 * Returns the current tracing status for the specified process in the
282 * integer variable pointed to by data. If tracing is disabled, data
283 * is set to -1. If tracing is enabled, but no debugger is attached by
284 * the ptrace(2) syscall, data is set to 0. If a debugger is attached,
285 * data is set to the pid of the debugger process.
286 */
287 if (status <= 0) return DEBUGGER_STATE_NOT_ATTACHED;
288
290}
291#elif defined(__APPLE__)
292/** The ptrace_attach() method no longer works as of macOS 11.4 (we always get eperm)
293 *
294 * Apple published this helpful article here which provides the
295 * magical invocation: https://developer.apple.com/library/archive/qa/qa1361/_index.html
296 *
297 * @return
298 * - 0 if we're not.
299 * - 1 if we are.
300 * - -1
301 */
302int fr_get_debug_state(void)
303{
304 int ret;
305 int mib[4];
306 struct kinfo_proc info;
307 size_t size;
308
309 /*
310 * Initialize the flags so that, if sysctl fails for some
311 * reason, we get a predictable result.
312 */
313 info.kp_proc.p_flag = 0;
314
315 /*
316 * Initialize mib, which tells sysctl the info we want, in this case
317 * we're looking for information about a specific process ID.
318 */
319 mib[0] = CTL_KERN;
320 mib[1] = KERN_PROC;
321 mib[2] = KERN_PROC_PID;
322 mib[3] = getpid();
323
324 /* Call sysctl */
325 size = sizeof(info);
326 ret = sysctl(mib, NUM_ELEMENTS(mib), &info, &size, NULL, 0);
327 if (ret != 0) return -1;
328
329 /* We're being debugged if the P_TRACED flag is set */
330 return ((info.kp_proc.p_flag & P_TRACED) != 0);
331}
332#elif defined(HAVE_SYS_PTRACE_H) && !defined(__EMSCRIPTEN__)
333/** Determine if we're running under a debugger by attempting to attach using pattach
334 *
335 * @return
336 * - 0 if we're not.
337 * - 1 if we are.
338 * - -1 if we can't tell because of an error.
339 * - -2 if we can't tell because we don't have the CAP_SYS_PTRACE capability.
340 */
341int fr_get_debug_state(void)
342{
343 int pid;
344
345 int from_child[2] = {-1, -1};
346
347#ifdef HAVE_CAPABILITY_H
348 cap_flag_value_t state;
349 cap_t caps;
350
351 /*
352 * If we're running under linux, we first need to check if we have
353 * permission to to ptrace. We do that using the capabilities
354 * functions.
355 */
356 caps = cap_get_proc();
357 if (!caps) {
358 fr_strerror_printf("Failed getting process capabilities: %s", fr_syserror(errno));
360 }
361
362 if (cap_get_flag(caps, CAP_SYS_PTRACE, CAP_PERMITTED, &state) < 0) {
363 fr_strerror_printf("Failed getting CAP_SYS_PTRACE permitted state: %s",
364 fr_syserror(errno));
365 cap_free(caps);
367 }
368
369 if ((state == CAP_SET) && (cap_get_flag(caps, CAP_SYS_PTRACE, CAP_EFFECTIVE, &state) < 0)) {
370 fr_strerror_printf("Failed getting CAP_SYS_PTRACE effective state: %s",
371 fr_syserror(errno));
372 cap_free(caps);
374 }
375
376 /*
377 * We don't have permission to ptrace, so this test will always fail.
378 */
379 if (state == CAP_CLEAR) {
380 fr_strerror_printf("ptrace capability not set. If debugger detection is required run as root or: "
381 "setcap cap_sys_ptrace+ep <path_to_binary>");
382 cap_free(caps);
384 }
385 cap_free(caps);
386#endif
387
388 if (pipe(from_child) < 0) {
389 fr_strerror_printf("Error opening internal pipe: %s", fr_syserror(errno));
391 }
392
393 pid = fork();
394 if (pid == -1) {
395 fr_strerror_printf("Error forking: %s", fr_syserror(errno));
397 }
398
399 /* Child */
400 if (pid == 0) {
401 int8_t ret = DEBUGGER_STATE_NOT_ATTACHED;
402 int ppid = getppid();
403 int flags;
404
405 /*
406 * Disable the leak checker for this forked process
407 * so we don't get spurious leaks reported.
408 */
409#ifdef HAVE_SANITIZER_LSAN_INTERFACE_H
410 lsan_disable = true;
411#endif
412
413DIAG_OFF(deprecated-declarations)
414 flags = PT_ATTACH;
415DIAG_ON(deprecated-declarations)
416
417 /* Close parent's side */
418 close(from_child[0]);
419
420 /*
421 * FreeBSD is extremely picky about the order of operations here
422 * we need to attach, wait *then* write whilst the parent is still
423 * suspended, then detach, continuing the process.
424 *
425 * If we don't do it in that order the read in the parent triggers
426 * a SIGKILL.
427 */
428 errno = 0;
429 _PTRACE(flags, ppid);
430 if (errno == 0) {
431 /* Wait for the parent to stop */
432 waitpid(ppid, NULL, 0);
433
434 /* Tell the parent what happened */
435 send_status:
436 if (write(from_child[1], &ret, sizeof(ret)) < 0) {
437 fprintf(stderr, "Writing ptrace status to parent failed: %s\n", fr_syserror(errno));
438 }
439
440 /* Detach */
441 _PTRACE_DETACH(ppid);
442
443
444 /*
445 * We call _exit() instead of exit(). This means that we skip the atexit() handlers,
446 * which don't need to run in a temporary child process. Skipping them means that we
447 * avoid dirtying those pages to "clean things up", which is then immediately followed by
448 * exiting.
449 *
450 * Skipping the atexit() handlers also means that we're not worried about memory leaks
451 * because things "aren't cleaned up correctly". We're not exiting cleanly here (and
452 * don't care to exit cleanly). So just exiting with no cleanups is fine.
453 */
454 _exit(0); /* don't run the atexit() handlers. */
455 /*
456 * man ptrace says the following:
457 *
458 * EPERM The specified process cannot be traced. This could be
459 * because the tracer has insufficient privileges (the
460 * required capability is CAP_SYS_PTRACE); unprivileged
461 * processes cannot trace processes that they cannot send
462 * signals to or those running set-user-ID/set-group-ID
463 * programs, for obvious reasons. Alternatively, the process
464 * may already be being traced, or (before Linux 2.6.26) be
465 * init(1) (PID 1).
466 *
467 * In any case, we are very unlikely to be able to attach to
468 * the process from the panic action.
469 *
470 * We checked for CAP_SYS_PTRACE previously, so know that
471 * we _should_ haven been ablle to attach, so if we can't, it's
472 * likely that we're already being traced.
473 */
474 } else if (errno == EPERM) {
476 goto send_status;
477 }
478
479 /*
480 * Unexpected error, we don't know whether we're already running
481 * under a debugger or not...
482 */
484 fprintf(stderr, "Debugger check failed to attach to parent with unexpected error: %s\n", fr_syserror(errno));
485 goto send_status;
486 /* Parent */
487 } else {
488 int8_t ret = DEBUGGER_STATE_UNKNOWN;
489
490 /*
491 * The child writes errno (reason) if pattach failed else 0.
492 *
493 * This read may be interrupted by pattach,
494 * which is why we need the loop.
495 */
496 while ((read(from_child[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
497
498 /* Close the pipes here (if we did it above, it might race with pattach) */
499 close(from_child[1]);
500 close(from_child[0]);
501
502 /* Collect the status of the child */
503 waitpid(pid, NULL, 0);
504
505 return ret;
506 }
507}
508#else
510{
511 fr_strerror_const("PTRACE not available");
512
514}
515#endif
516
517/** Should be run before using setuid or setgid to get useful results
518 *
519 * @note sets the fr_debug_state global.
520 */
522{
524
525#ifndef NDEBUG
526 /*
527 * There are many reasons why this might happen with
528 * a vanilla install, so we don't want to spam users
529 * with messages they won't understand and may not
530 * want to resolve.
531 */
532 if (fr_debug_state < 0) fprintf(stderr, "Getting debug state failed: %s\n", fr_strerror());
533#endif
534}
535
536/** Return current value of debug_state
537 *
538 * @param state to translate into a humanly readable value.
539 * @return humanly readable version of debug state.
540 */
542{
543 switch (state) {
545 return "Debug state unknown (ptrace functionality not available)";
546
548 return "Debug state unknown (cap_sys_ptrace capability not set)";
549
551 return "Debug state unknown";
552
554 return "Found debugger attached";
555
557 return "Debugger not attached";
558 }
559
560 return "<INVALID>";
561}
562
563/** Break in debugger (if were running under a debugger)
564 *
565 * If the server is running under a debugger this will raise a
566 * SIGTRAP which will pause the running process.
567 *
568 * If the server is not running under debugger then this will do nothing.
569 */
570void fr_debug_break(bool always)
571{
572 if (always) raise(SIGTRAP);
573
576 fprintf(stderr, "Debugger detected, raising SIGTRAP\n");
577 fflush(stderr);
578
579 raise(SIGTRAP);
580 }
581}
582
583#ifdef HAVE_EXECINFO
584/** Print backtrace entry for a given object
585 *
586 * @param fring to search in.
587 * @param obj pointer to original object
588 */
589void backtrace_print(fr_fring_t *fring, void *obj)
590{
591 fr_bt_info_t *p;
592 bool found = false;
593
594 while ((p = fr_fring_next(fring))) {
595 if ((p->obj == obj) || !obj) {
596 found = true;
597
598 fprintf(stderr, "Stacktrace for: %p\n", p->obj);
599 backtrace_symbols_fd(p->frames, p->count, STDERR_FILENO);
600 }
601 }
602
603 if (!found) {
604 fprintf(stderr, "No backtrace available for %p", obj);
605 }
606}
607
608/** Generate a backtrace for an object
609 *
610 * If this is the first entry being inserted
611 */
613{
614 fr_bt_info_t *bt;
615
616 if (!fr_cond_assert(marker->obj) || !fr_cond_assert(marker->fring)) return -1;
617
618 bt = talloc_zero(NULL, fr_bt_info_t);
619 if (!bt) return -1;
620
621 bt->obj = marker->obj;
622 bt->count = backtrace(bt->frames, MAX_BT_FRAMES);
623
624 fr_fring_overwrite(marker->fring, bt);
625
626 return 0;
627}
628
629/** Inserts a backtrace marker into the provided context
630 *
631 * Allows for maximum laziness and will initialise a circular buffer if one has not already been created.
632 *
633 * Code augmentation should look something like:
634@verbatim
635 // Create a static fringer pointer, the first call to backtrace_attach will initialise it
636 static fr_fring_t *my_obj_bt;
637
638 my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) {
639 my_obj_t *this;
640
641 this = talloc(ctx, my_obj_t);
642
643 // Attach backtrace marker to object
644 backtrace_attach(&my_obj_bt, this);
645
646 return this;
647 }
648@endverbatim
649 *
650 * Then, later when a double free occurs:
651@verbatim
652 (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>)
653@endverbatim
654 *
655 * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument
656 * values, but should at least show the code path taken.
657 *
658 * @param fring this should be a pointer to a static *fr_fring_buffer.
659 * @param obj we want to generate a backtrace for.
660 */
661fr_bt_marker_t *fr_backtrace_attach(fr_fring_t **fring, TALLOC_CTX *obj)
662{
663 fr_bt_marker_t *marker;
664
665 if (*fring == NULL) {
666 pthread_mutex_lock(&fr_debug_init);
667 /* Check again now we hold the mutex - eww*/
668 if (*fring == NULL) *fring = fr_fring_alloc(NULL, MAX_BT_CBUFF, true);
669 pthread_mutex_unlock(&fr_debug_init);
670 }
671
672 marker = talloc(obj, fr_bt_marker_t);
673 if (!marker) {
674 return NULL;
675 }
676
677 marker->obj = (void *) obj;
678 marker->fring = *fring;
679
680 fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
681 /*
682 * Generate the backtrace for memory allocation
683 */
684 fr_backtrace_do(marker);
685 talloc_set_destructor(marker, fr_backtrace_do);
686
687 return marker;
688}
689#else
691{
692 fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
693}
695{
696 fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
697 abort();
698}
699#endif /* ifdef HAVE_EXECINFO */
700
701static int _panic_on_free(UNUSED char *foo)
702{
703 fr_fault(SIGABRT);
704 return -1; /* this should make the free fail */
705}
706
707/** Insert memory into the context of another talloc memory chunk which
708 * causes a panic when freed.
709 *
710 * @param ctx TALLOC_CTX to monitor for frees.
711 */
712void fr_panic_on_free(TALLOC_CTX *ctx)
713{
714 char *ptr;
715
716 ptr = talloc(ctx, char);
717 talloc_set_destructor(ptr, _panic_on_free);
718}
719
720/** Set the dumpable flag, also controls whether processes can PATTACH
721 *
722 * @param dumpable whether we should allow core dumping
723 */
724#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) && !defined(__EMSCRIPTEN__)
725static int fr_set_pr_dumpable_flag(bool dumpable)
726{
727 if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) {
728 fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s",
729 fr_syserror(errno));
730 return -1;
731 }
732
733 return 0;
734}
735#elif defined(HAVE_SYS_PROCCTL_H)
736static int fr_set_pr_dumpable_flag(bool dumpable)
737{
738 int mode = dumpable ? PROC_TRACE_CTL_ENABLE : PROC_TRACE_CTL_DISABLE;
739
740 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &mode) == -1) {
741 fr_strerror_printf("Cannot re-enable core dumps: procctl(PROC_TRACE_CTL) failed: %s",
742 fr_syserror(errno));
743 return -1;
744 }
745
746 return 0;
747}
748#else
749static int fr_set_pr_dumpable_flag(UNUSED bool dumpable)
750{
751 fr_strerror_const("Changing value of PR_DUMPABLE not supported on this system");
752 return -2;
753}
754#endif
755
756/** Get the processes dumpable flag
757 *
758 */
759#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_DUMPABLE) && !defined(__EMSCRIPTEN__)
760static int fr_get_pr_dumpable_flag(void)
761{
762 int ret;
763
764 ret = prctl(PR_GET_DUMPABLE);
765 if (ret < 0) {
766 fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
767 return -1;
768 }
769
770 /*
771 * Linux is crazy and prctl sometimes returns 2 for disabled
772 */
773 if (ret != 1) return 0;
774 return 1;
775}
776#elif defined(HAVE_SYS_PROCCTL_H)
777static int fr_get_pr_dumpable_flag(void)
778{
779 int status;
780
781 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &status) == -1) {
782 fr_strerror_printf("Cannot get dumpable flag: procctl(PROC_TRACE_CTL) failed: %s", fr_syserror(errno));
783 return -1;
784 }
785
786 /*
787 * There are a few different kinds of disabled, but only
788 * one ENABLE.
789 */
790 if (status != PROC_TRACE_CTL_ENABLE) return 0;
791
792 return 1;
793}
794#else
796{
797 fr_strerror_const("Getting value of PR_DUMPABLE not supported on this system");
798 return -2;
799}
800#endif
801
802
803/** Get the current maximum for core files
804 *
805 * Do this before anything else so as to ensure it's properly initialized.
806 */
808{
809#ifdef HAVE_SYS_RESOURCE_H
810 if (getrlimit(RLIMIT_CORE, &init_core_limit) < 0) {
811 fr_strerror_printf("Failed to get current core limit: %s", fr_syserror(errno));
812 return -1;
813 }
814#endif
815 return 0;
816}
817
818/** Enable or disable core dumps
819 *
820 * @param allow_core_dumps whether to enable or disable core dumps.
821 */
822int fr_set_dumpable(bool allow_core_dumps)
823{
824 dump_core = allow_core_dumps;
825
826#ifdef HAVE_SYS_RESOURCE_H
827 {
828 struct rlimit current;
829
830 /*
831 * Reset the core limits (or disable them)
832 */
833 if (getrlimit(RLIMIT_CORE, &current) < 0) {
834 fr_strerror_printf("Failed to get current core limit: %s", fr_syserror(errno));
835 return -1;
836 }
837
838 if (allow_core_dumps) {
839 if ((current.rlim_cur != init_core_limit.rlim_cur) ||
840 (current.rlim_max != init_core_limit.rlim_max)) {
841 if (setrlimit(RLIMIT_CORE, &init_core_limit) < 0) {
842 fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));
843
844 return -1;
845 }
846 }
847 /*
848 * We've been told to disable core dumping,
849 * rlim_cur is not set to zero.
850 *
851 * Set rlim_cur to zero, but leave rlim_max
852 * set to whatever the current value is.
853 *
854 * This is because, later, we may need to
855 * re-enable core dumps to allow the debugger
856 * to attach *sigh*.
857 */
858 } else if (current.rlim_cur != 0) {
859 struct rlimit no_core;
860
861 no_core.rlim_cur = 0;
862 no_core.rlim_max = current.rlim_max;
863
864 if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
865 fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));
866
867 return -1;
868 }
869 }
870 }
871#endif
872 /*
873 * Macro needed so we don't emit spurious errors
874 */
875#if defined(HAVE_SYS_PROCCTL_H) || (defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE))
876 if (fr_set_pr_dumpable_flag(allow_core_dumps) < 0) return -1;
877#endif
878
879 return 0;
880}
881
882/** Reset dumpable state to previously configured value
883 *
884 * Needed after suid up/down
885 *
886 * @return
887 * - 0 on success.
888 * - -1 on failure.
889 */
891{
893}
894
895/** Check to see if panic_action file is world writable
896 *
897 * @return
898 * - 0 if file is OK.
899 * - -1 if the file is world writable.
900 */
902{
903 char const *p, *q;
904 size_t len;
905 char filename[256];
906 struct stat statbuf;
907
908 /*
909 * Try and guess which part of the command is the binary, and check to see if
910 * it's world writable, to try and save the admin from their own stupidity.
911 *
912 * @fixme we should do this properly and take into account single and double
913 * quotes.
914 */
915 if ((q = strchr(panic_action, ' '))) {
916 /*
917 * need to use a static buffer, because allocing memory in a signal handler
918 * is a bad idea and can result in deadlock.
919 */
920 len = snprintf(filename, sizeof(filename), "%.*s", (int)(q - panic_action), panic_action);
921 if (is_truncated(len, sizeof(filename))) {
922 fr_strerror_const("Failed writing panic_action to temporary buffer (truncated)");
923 return -1;
924 }
925 p = filename;
926 } else {
927 p = panic_action;
928 }
929
930 if (stat(p, &statbuf) == 0) {
931#ifdef S_IWOTH
932 if ((statbuf.st_mode & S_IWOTH) != 0) {
933 fr_strerror_printf("panic_action file \"%s\" is globally writable", p);
934 return -1;
935 }
936#endif
937 }
938
939 return 0;
940}
941
942/** Split out so it can be sprinkled throughout the server and called via a debugger
943 *
944 */
946{
947
948 /*
949 * Produce a simple backtrace - They're very basic but at least give us an
950 * idea of the area of the code we hit the issue in.
951 *
952 * See below in fr_fault_setup() and
953 * https://sourceware.org/bugzilla/show_bug.cgi?id=16159
954 * for why we only print backtraces in debug builds if we're using GLIBC.
955 */
956#if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
957 if (fr_fault_log_fd >= 0) {
958 size_t frame_count;
959 void *stack[MAX_BT_FRAMES];
960
961 frame_count = backtrace(stack, MAX_BT_FRAMES);
962
963 FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
964
965 backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
966 }
967#endif
968 return;
969}
970
971/** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
972 *
973 * @param sig caught
974 */
976{
977 char cmd[sizeof(panic_action) + 20];
978 char *out = cmd;
979 size_t left = sizeof(cmd), ret;
980
981 char const *p = panic_action;
982 char const *q;
983
984 int code;
985
986 /*
987 * If a debugger is attached, we don't want to run the panic action,
988 * as it may interfere with the operation of the debugger.
989 * If something calls us directly we just raise the signal and let
990 * the debugger handle it how it wants.
991 */
993 FR_FAULT_LOG("RAISING SIGNAL: %s", strsignal(sig));
994 raise(sig);
995 }
996
997 /*
998 * Makes the backtraces slightly cleaner
999 */
1000 memset(cmd, 0, sizeof(cmd));
1001
1002 FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
1003
1004 /*
1005 * Run the callback if one was registered
1006 */
1007 if (panic_cb && (panic_cb(sig) < 0)) goto finish;
1008
1010
1011 /* No panic action set... */
1012 if (panic_action[0] == '\0') {
1013 FR_FAULT_LOG("No panic action set");
1014 goto finish;
1015 }
1016
1017 /*
1018 * Check for administrator sanity.
1019 */
1020 if (fr_fault_check_permissions() < 0) {
1021 FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror());
1022 goto finish;
1023 }
1024
1025 /* Substitute %p for the current PID (useful for attaching a debugger) */
1026 while ((q = strstr(p, "%p"))) {
1027 out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid());
1028 if (left <= ret) {
1029 oob:
1030 FR_FAULT_LOG("Panic action too long");
1031 fr_exit_now(128 + sig);
1032 }
1033 left -= ret;
1034 p = q + 2;
1035 }
1036 if (strlen(p) >= left) goto oob;
1037 strlcpy(out, p, left);
1038
1039 {
1040 bool disable = false;
1041
1042 FR_FAULT_LOG("Calling: %s", cmd);
1043
1044 /*
1045 * Here we temporarily enable the dumpable flag so if GBD or LLDB
1046 * is called in the panic_action, they can pattach to the running
1047 * process.
1048 */
1049 if (fr_get_pr_dumpable_flag() == 0) {
1050 if ((fr_set_pr_dumpable_flag(true) < 0) || !fr_get_pr_dumpable_flag()) {
1051 FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror());
1052 } else {
1053 disable = true;
1054 }
1055 FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1");
1056 }
1057
1058 code = system(cmd);
1059
1060 /*
1061 * We only want to error out here, if dumpable was originally disabled
1062 * and we managed to change the value to enabled, but failed
1063 * setting it back to disabled.
1064 */
1065 if (disable) {
1066 FR_FAULT_LOG("Resetting PR_DUMPABLE to 0");
1067 if (fr_set_pr_dumpable_flag(false) < 0) {
1068 FR_FAULT_LOG("Failed resetting dumpable flag to off: %s", fr_strerror());
1069 FR_FAULT_LOG("Exiting due to insecure process state");
1070 fr_exit_now(EXIT_FAILURE);
1071 }
1072 }
1073
1074 FR_FAULT_LOG("Panic action exited with %i", code);
1075
1076 fr_exit_now(128 + sig);
1077 }
1078
1079finish:
1080 /*
1081 * (Re-)Raise the signal, so that if we're running under
1082 * a debugger.
1083 *
1084 * This allows debuggers to function normally and catch
1085 * fatal signals.
1086 */
1087 fr_unset_signal(sig); /* Make sure we don't get into a loop */
1088 raise(sig);
1089 fr_exit_now(128 + sig); /* Function marked as noreturn */
1090}
1091
1092/** Callback executed on fatal talloc error
1093 *
1094 * This is the simple version which mostly behaves the same way as the default
1095 * one, and will not call panic_action.
1096 *
1097 * @param reason string provided by talloc.
1098 */
1099static void _fr_talloc_fault_simple(char const *reason) CC_HINT(noreturn);
1100static void _fr_talloc_fault_simple(char const *reason)
1101{
1102 FR_FAULT_LOG("talloc abort: %s\n", reason);
1103
1104#if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
1105 if (fr_fault_log_fd >= 0) {
1106 size_t frame_count;
1107 void *stack[MAX_BT_FRAMES];
1108
1109 frame_count = backtrace(stack, MAX_BT_FRAMES);
1110 FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
1111 backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
1112 }
1113#endif
1114 abort();
1115}
1116
1117/** Callback executed on fatal talloc error
1118 *
1119 * Translates a talloc abort into a fr_fault call.
1120 * Mostly to work around issues with some debuggers not being able to
1121 * attach after a SIGABRT has been raised.
1122 *
1123 * @param reason string provided by talloc.
1124 */
1125static void _fr_talloc_fault(char const *reason) CC_HINT(noreturn);
1126static void _fr_talloc_fault(char const *reason)
1127{
1128 FR_FAULT_LOG("talloc abort: %s", reason);
1129#ifdef SIGABRT
1130 fr_fault(SIGABRT);
1131#endif
1132 fr_exit_now(128 + SIGABRT);
1133}
1134
1135/** Wrapper to pass talloc log output to our fr_fault_log function
1136 *
1137 */
1138static void _fr_talloc_log(char const *msg)
1139{
1140 fr_fault_log("%s\n", msg);
1141}
1142
1143/** Generate a talloc memory report for a context and print to stderr/stdout
1144 *
1145 * @param ctx to generate a report for, may be NULL in which case the root context is used.
1146 */
1147int fr_log_talloc_report(TALLOC_CTX const *ctx)
1148{
1149#define TALLOC_REPORT_MAX_DEPTH 20
1150
1151 FILE *log;
1152 int fd;
1153
1154 fd = dup(fr_fault_log_fd);
1155 if (fd < 0) {
1156 fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno));
1157 return -1;
1158 }
1159 log = fdopen(fd, "w");
1160 if (!log) {
1161 close(fd);
1162 fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno));
1163 return -1;
1164 }
1165
1166 if (!ctx) {
1167 fprintf(log, "Current state of talloced memory:\n");
1168 talloc_report_full(talloc_null_ctx(), log);
1169 } else {
1170 int i;
1171
1172 fprintf(log, "Talloc chunk lineage:\n");
1173 fprintf(log, "%p (%s)", ctx, talloc_get_name(ctx));
1174
1175 i = 0;
1176 while ((i < TALLOC_REPORT_MAX_DEPTH) && (ctx = talloc_parent(ctx))) {
1177 fprintf(log, " < %p (%s)", ctx, talloc_get_name(ctx));
1178 i++;
1179 }
1180 fprintf(log, "\n");
1181
1182 i = 0;
1183 do {
1184 fprintf(log, "Talloc context level %i:\n", i++);
1185 talloc_report_full(ctx, log);
1186 } while ((ctx = talloc_parent(ctx)) &&
1188 (talloc_parent(ctx) != talloc_autofree_ctx) && /* Stop before we hit the autofree ctx */
1189 (talloc_parent(ctx) != talloc_null_ctx())); /* Stop before we hit NULL ctx */
1190 }
1191
1192 fclose(log);
1193
1194 return 0;
1195}
1196
1197
1199{
1200 talloc_disable_null_tracking();
1201 return 0;
1202}
1203
1204/** Disable the null tracking context when a talloc chunk is freed
1205 *
1206 */
1208{
1209 bool *marker;
1210
1211 /*
1212 * Disable null tracking on exit, else valgrind complains
1213 */
1214 marker = talloc(ctx, bool);
1215 talloc_set_destructor(marker, _disable_null_tracking);
1216}
1217
1218/** Register talloc fault handlers
1219 *
1220 * Just register the fault handlers we need to make talloc
1221 * produce useful debugging output.
1222 */
1224{
1225 talloc_set_log_fn(_fr_talloc_log);
1226 talloc_set_abort_fn(_fr_talloc_fault_simple);
1227}
1228
1229/** Registers signal handlers to execute panic_action on fatal signal
1230 *
1231 * May be called multiple time to change the panic_action/program.
1232 *
1233 * @param[in] ctx to allocate autofreeable resources in.
1234 * @param[in] cmd to execute on fault. If present %p will be substituted
1235 * for the parent PID before the command is executed, and %e
1236 * will be substituted for the currently running program.
1237 * @param program Name of program currently executing (argv[0]).
1238 * @return
1239 * - 0 on success.
1240 * - -1 on failure.
1241 */
1242int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
1243{
1244 static bool setup = false;
1245
1246 char *out = panic_action;
1247 size_t left = sizeof(panic_action);
1248
1249 char const *p = cmd;
1250 char const *q;
1251
1252 if (cmd) {
1253 size_t ret;
1254
1255 /* Substitute %e for the current program */
1256 while ((q = strstr(p, "%e"))) {
1257 out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
1258 if (left <= ret) {
1259 oob:
1260 fr_strerror_const("Panic action too long");
1261 return -1;
1262 }
1263 left -= ret;
1264 p = q + 2;
1265 }
1266 if (strlen(p) >= left) goto oob;
1267 strlcpy(out, p, left);
1268 } else {
1269 *panic_action = '\0';
1270 }
1271
1272 /*
1273 * Check for administrator sanity.
1274 */
1275 if (fr_fault_check_permissions() < 0) return -1;
1276
1277 /* Unsure what the side effects of changing the signal handler mid execution might be */
1278 if (!setup) {
1279 char *env;
1280
1281 /*
1282 * Installing signal handlers interferes with some debugging
1283 * operations. Give the developer control over whether the
1284 * signal handlers are installed or not.
1285 */
1286 env = getenv("DEBUGGER_ATTACHED");
1287 if (env && (strcmp(env, "yes") == 0)) {
1288 fr_debug_state = DEBUGGER_STATE_ATTACHED; /* i.e. disable signal handlers */
1289
1290 } else if (env && (strcmp(env, "no") == 0)) {
1291 fr_debug_state = DEBUGGER_STATE_NOT_ATTACHED; /* i.e. enable signal handlers */
1292
1293 /*
1294 * Figure out if we were started under a debugger
1295 */
1296 } else {
1298 }
1299
1300 talloc_set_log_fn(_fr_talloc_log);
1301
1302 /*
1303 * These signals can't be properly dealt with in the debugger
1304 * if we set our own signal handlers.
1305 */
1306 switch (fr_debug_state) {
1307 default:
1309#ifdef SIGABRT
1310 if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
1311
1312 /*
1313 * Use this instead of abort so we get a
1314 * full backtrace with broken versions of LLDB
1315 */
1316 talloc_set_abort_fn(_fr_talloc_fault);
1317#endif
1318#ifdef SIGILL
1319 if (fr_set_signal(SIGILL, fr_fault) < 0) return -1;
1320#endif
1321#ifdef SIGFPE
1322 if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
1323#endif
1324#ifdef SIGSEGV
1325 if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
1326#endif
1327#ifdef SIGALRM
1328 /*
1329 * This is used be jlibtool to terminate
1330 * processes which have been running too
1331 * long.
1332 */
1333 if (fr_set_signal(SIGALRM, fr_fault) < 0) return -1;
1334#endif
1335 break;
1336
1338 break;
1339 }
1340
1341 /*
1342 * Needed for memory reports
1343 */
1345
1346#if defined(HAVE_MALLOPT) && !defined(NDEBUG)
1347 /*
1348 * If were using glibc malloc > 2.4 this scribbles over
1349 * uninitialised and freed memory, to make memory issues easier
1350 * to track down.
1351 */
1352# ifdef M_PERTURB
1353 if (!getenv("TALLOC_FREE_FILL")) mallopt(M_PERTURB, 0x42);
1354# endif
1355# ifdef M_CHECK_ACTION
1356 mallopt(M_CHECK_ACTION, 3);
1357# endif
1358#endif
1359
1360#if defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
1361 /*
1362 * We need to pre-load lgcc_s, else we can get into a deadlock
1363 * in fr_fault, as backtrace() attempts to dlopen it.
1364 *
1365 * Apparently there's a performance impact of loading lgcc_s,
1366 * so only do it if this is a debug build.
1367 *
1368 * See: https://sourceware.org/bugzilla/show_bug.cgi?id=16159
1369 */
1370 {
1371 void *stack[10];
1372
1373 backtrace(stack, 10);
1374 }
1375#endif
1376 }
1377 setup = true;
1378
1379 return 0;
1380}
1381
1382/** Set a callback to be called before fr_fault()
1383 *
1384 * @param func to execute. If callback returns < 0
1385 * fr_fault will exit before running panic_action code.
1386 */
1388{
1389 panic_cb = func;
1390}
1391
1392/** Log output to the fr_fault_log_fd
1393 *
1394 * We used to support a user defined callback, which was set to a radlog
1395 * function. Unfortunately, when logging to syslog, syslog would alloc memory
1396 * which would result in a deadlock if fr_fault was triggered from within
1397 * a allocation call.
1398 *
1399 * Now we just write directly to the FD.
1400 */
1401void fr_fault_log(char const *msg, ...)
1402{
1403 va_list ap;
1404
1405 if (fr_fault_log_fd < 0) return;
1406
1407 va_start(ap, msg);
1409 va_end(ap);
1410}
1411
1412/** Print data as a hex block
1413 *
1414 */
1415void fr_fault_log_hex(uint8_t const *data, size_t data_len)
1416{
1417 size_t i, j, len;
1418 char buffer[(0x10 * 3) + 1];
1419 char *p, *end = buffer + sizeof(buffer);
1420
1421 for (i = 0; i < data_len; i += 0x10) {
1422 len = 0x10;
1423 if ((i + len) > data_len) len = data_len - i;
1424
1425 for (p = buffer, j = 0; j < len; j++, p += 3) snprintf(p, end - p, "%02x ", data[i + j]);
1426
1427 dprintf(fr_fault_log_fd, "%04x: %s\n", (unsigned int) i, buffer);
1428 }
1429}
1430
1431/** Set a file descriptor to log memory reports to.
1432 *
1433 * @param fd to write output to.
1434 */
1436{
1437 fr_fault_log_fd = fd;
1438}
1439
1440/** A soft assertion which triggers the fault handler in debug builds
1441 *
1442 * @param[in] file the assertion failed in.
1443 * @param[in] line of the assertion in the file.
1444 * @param[in] expr that was evaluated.
1445 * @param[in] msg Message to print (may be NULL).
1446 * @param[in] ... Arguments for msg string.
1447 * @return the value of cond.
1448 */
1449bool _fr_assert_fail(char const *file, int line, char const *expr, char const *msg, ...)
1450{
1451 if (msg) {
1452 char str[256]; /* Decent compilers won't allocate this unless fmt is !NULL... */
1453 va_list ap;
1454
1455 va_start(ap, msg);
1456 (void)vsnprintf(str, sizeof(str), msg, ap);
1457 va_end(ap);
1458
1459#ifndef NDEBUG
1460 FR_FAULT_LOG("ASSERT FAILED %s[%d]: %s: %s", file, line, expr, str);
1461 fr_fault(SIGABRT);
1462#else
1463 FR_FAULT_LOG("ASSERT WOULD FAIL %s[%d]: %s: %s", file, line, expr, str);
1464 return false;
1465#endif
1466 }
1467
1468#ifndef NDEBUG
1469 FR_FAULT_LOG("ASSERT FAILED %s[%d]: %s", file, line, expr);
1470 fr_fault(SIGABRT);
1471#else
1472 FR_FAULT_LOG("ASSERT WOULD FAIL %s[%d]: %s", file, line, expr);
1473 return false;
1474#endif
1475}
1476
1477/** A fatal assertion which triggers the fault handler in debug builds or exits
1478 *
1479 * @param[in] file the assertion failed in.
1480 * @param[in] line of the assertion in the file.
1481 * @param[in] expr that was evaluated.
1482 * @param[in] msg Message to print (may be NULL).
1483 * @param[in] ... Arguments for msg string.
1484 */
1485void _fr_assert_fatal(char const *file, int line, char const *expr, char const *msg, ...)
1486{
1487 if (msg) {
1488 char str[256]; /* Decent compilers won't allocate this unless fmt is !NULL... */
1489 va_list ap;
1490
1491 va_start(ap, msg);
1492 (void)vsnprintf(str, sizeof(str), msg, ap);
1493 va_end(ap);
1494
1495 FR_FAULT_LOG("FATAL ASSERT %s[%d]: %s: %s", file, line, expr, str);
1496 } else {
1497 FR_FAULT_LOG("FATAL ASSERT %s[%d]: %s", file, line, expr);
1498 }
1499
1500#ifdef NDEBUG
1501 _fr_exit(file, line, 128 + SIGABRT, true);
1502#else
1503 fr_fault(SIGABRT);
1504#endif
1505}
1506
1507/** Exit possibly printing a message about why we're exiting.
1508 *
1509 * @note Use the fr_exit(status) macro instead of calling this function directly.
1510 *
1511 * @param[in] file where fr_exit() was called.
1512 * @param[in] line where fr_exit() was called.
1513 * @param[in] status we're exiting with.
1514 * @param[in] now Exit immediately.
1515 */
1516#ifndef NDEBUG
1517NEVER_RETURNS void _fr_exit(char const *file, int line, int status, bool now)
1518{
1519 if (status != EXIT_SUCCESS) {
1520 char const *error = fr_strerror();
1521
1522 if (error && *error && (status != 0)) {
1523 FR_FAULT_LOG("%sEXIT(%i) CALLED %s[%d]. Last error was: %s", now ? "_" : "",
1524 status, file, line, error);
1525 } else {
1526 FR_FAULT_LOG("%sEXIT(%i) CALLED %s[%d]", now ? "_" : "", status, file, line);
1527 }
1528
1529 fr_debug_break(false); /* If running under GDB we'll break here */
1530 }
1531
1532 if (now) _Exit(status);
1533 exit(status);
1534}
1535#else
1536NEVER_RETURNS void _fr_exit(UNUSED char const *file, UNUSED int line, int status, bool now)
1537{
1538 if (status != EXIT_SUCCESS) fr_debug_break(false); /* If running under GDB we'll break here */
1539
1540 if (now) _Exit(status);
1541 exit(status);
1542}
1543#endif
1544
1545/*
1546 * Sign a structure, but skip _signature at "offset".
1547 */
1548static uint32_t fr_hash_struct(void const *ptr, size_t size, size_t offset)
1549{
1550 uint32_t hash;
1551
1552 /*
1553 * Hash entry is at the end of the structure, that's
1554 * best...
1555 */
1556 if ((size + 4) == offset) {
1557 return fr_hash(ptr, size);
1558 }
1559
1560 hash = fr_hash(ptr, offset);
1561 return fr_hash_update(((uint8_t const *) ptr) + offset + 4, size - (offset + 4), hash);
1562}
1563
1564void fr_sign_struct(void *ptr, size_t size, size_t offset)
1565{
1566 *(uint32_t *) (((uint8_t *) ptr) + offset) = fr_hash_struct(ptr, size, offset);
1567}
1568
1569void fr_verify_struct(void const *ptr, size_t size, size_t offset)
1570{
1571 uint32_t hash;
1572
1573 hash = fr_hash_struct(ptr, size, offset);
1574
1575 (void) fr_cond_assert(hash == *(uint32_t const *) (((uint8_t const *) ptr) + offset));
1576}
1577
1578void fr_verify_struct_member(void const *ptr, size_t len, uint32_t *signature)
1579{
1580 uint32_t hash;
1581
1582 hash = fr_hash(ptr, len);
1583 (void) fr_cond_assert(hash == *signature);
1584}
vsnprintf(buffer, sizeof(buffer), fmt, args)
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_end(args)
log_entry msg
Definition acutest.h:794
int const char int line
Definition acutest.h:702
va_start(args, fmt)
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
#define DIAG_ON(_x)
Definition build.h:458
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define DIAG_OFF(_x)
Definition build.h:457
static int fr_fault_check_permissions(void)
Check to see if panic_action file is world writable.
Definition debug.c:901
static char panic_action[512]
The command to execute when panicking.
Definition debug.c:96
char const * fr_debug_state_to_msg(fr_debug_state_t state)
Return current value of debug_state.
Definition debug.c:541
static int _disable_null_tracking(UNUSED bool *p)
Definition debug.c:1198
static int _panic_on_free(UNUSED char *foo)
Definition debug.c:701
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition debug.c:1207
bool _fr_assert_fail(char const *file, int line, char const *expr, char const *msg,...)
A soft assertion which triggers the fault handler in debug builds.
Definition debug.c:1449
void fr_fault_set_log_fd(int fd)
Set a file descriptor to log memory reports to.
Definition debug.c:1435
static bool dump_core
Whether we should drop a core on fatal signals.
Definition debug.c:100
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition debug.c:1147
int fr_set_dumpable(bool allow_core_dumps)
Enable or disable core dumps.
Definition debug.c:822
static void _fr_talloc_fault_simple(char const *reason)
Callback executed on fatal talloc error.
Definition debug.c:1100
void fr_verify_struct(void const *ptr, size_t size, size_t offset)
Definition debug.c:1569
static int fr_set_pr_dumpable_flag(UNUSED bool dumpable)
Set the dumpable flag, also controls whether processes can PATTACH.
Definition debug.c:749
static fr_fault_cb_t panic_cb
Callback to execute whilst panicking, before the panic_action.
Definition debug.c:97
static TALLOC_CTX * talloc_autofree_ctx
Definition debug.c:110
void fr_fault_backtrace(void)
Split out so it can be sprinkled throughout the server and called via a debugger.
Definition debug.c:945
static uint32_t fr_hash_struct(void const *ptr, size_t size, size_t offset)
Definition debug.c:1548
static int fr_fault_log_fd
Where to write debug output.
Definition debug.c:102
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:890
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1242
void fr_verify_struct_member(void const *ptr, size_t len, uint32_t *signature)
Definition debug.c:1578
#define TALLOC_REPORT_MAX_DEPTH
NEVER_RETURNS void fr_fault(int sig)
Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
Definition debug.c:975
void fr_sign_struct(void *ptr, size_t size, size_t offset)
Definition debug.c:1564
int fr_get_lsan_state(void)
Definition debug.c:261
void fr_debug_state_store(void)
Should be run before using setuid or setgid to get useful results.
Definition debug.c:521
NEVER_RETURNS void _fr_exit(char const *file, int line, int status, bool now)
Exit possibly printing a message about why we're exiting.
Definition debug.c:1517
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1223
void fr_debug_break(bool always)
Break in debugger (if were running under a debugger)
Definition debug.c:570
void fr_fault_set_cb(fr_fault_cb_t func)
Set a callback to be called before fr_fault()
Definition debug.c:1387
void _fr_assert_fatal(char const *file, int line, char const *expr, char const *msg,...)
A fatal assertion which triggers the fault handler in debug builds or exits.
Definition debug.c:1485
void fr_fault_log_hex(uint8_t const *data, size_t data_len)
Print data as a hex block.
Definition debug.c:1415
int fr_set_dumpable_init(void)
Get the current maximum for core files.
Definition debug.c:807
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:712
static void _fr_talloc_fault(char const *reason)
Callback executed on fatal talloc error.
Definition debug.c:1126
fr_bt_marker_t * fr_backtrace_attach(UNUSED fr_fring_t **fring, UNUSED TALLOC_CTX *obj)
Definition debug.c:694
static void _fr_talloc_log(char const *msg)
Wrapper to pass talloc log output to our fr_fault_log function.
Definition debug.c:1138
static int fr_get_pr_dumpable_flag(void)
Get the processes dumpable flag.
Definition debug.c:795
fr_debug_state_t fr_debug_state
Whether we're attached to by a debugger.
Definition debug.c:104
void backtrace_print(UNUSED fr_fring_t *fring, UNUSED void *obj)
Definition debug.c:690
int fr_get_debug_state(void)
Definition debug.c:509
void fr_fault_log(char const *msg,...)
Log output to the fr_fault_log_fd.
Definition debug.c:1401
fr_debug_state_t
Definition debug.h:39
@ DEBUGGER_STATE_NOT_ATTACHED
We can attach, so a debugger must not be.
Definition debug.h:43
@ DEBUGGER_STATE_UNKNOWN_NO_PTRACE
We don't have ptrace so can't check.
Definition debug.h:40
@ DEBUGGER_STATE_UNKNOWN_NO_PTRACE_CAP
CAP_SYS_PTRACE not set for the process.
Definition debug.h:41
@ DEBUGGER_STATE_UNKNOWN
Unknown, likely fr_get_debug_state() not called yet.
Definition debug.h:42
@ DEBUGGER_STATE_ATTACHED
We can't attach, it's likely a debugger is already tracing.
Definition debug.h:44
struct fr_bt_marker fr_bt_marker_t
Definition debug.h:64
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
int(* fr_fault_cb_t)(int signum)
Optional callback passed to fr_fault_setup.
Definition debug.h:63
#define FR_FAULT_LOG(_fmt,...)
Definition debug.h:49
int fr_backtrace_do(fr_bt_marker_t *marker)
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:234
int fr_fring_overwrite(fr_fring_t *fring, void *in)
Insert a new item into the circular buffer, freeing the tail if we hit it.
Definition fring.c:120
void * fr_fring_next(fr_fring_t *fring)
Remove an item from the buffer.
Definition fring.c:177
fr_fring_t * fr_fring_alloc(TALLOC_CTX *ctx, uint32_t size, bool lock)
Initialise a ring buffer with fixed element size.
Definition fring.c:78
Standard thread safe circular buffer.
Definition fring.c:36
uint32_t fr_hash_update(void const *data, size_t size, uint32_t hash)
Definition hash.c:846
uint32_t fr_hash(void const *data, size_t size)
Definition hash.c:812
waitpid(reap->pid_ev->pid, &status, 0)
static char * stack[MAX_STACK]
Definition radmin.c:158
unsigned int uint32_t
unsigned char uint8_t
static size_t used
int fr_unset_signal(int sig)
Uninstall a signal for a specific handler.
Definition misc.c:76
int fr_set_signal(int sig, sig_t func)
Sets a signal handler using sigaction if available, else signal.
Definition misc.c:47
int vdprintf(int fd, char const *format, va_list args)
Definition missing.c:210
#define is_truncated(_ret, _max)
Definition print.h:48
static rc_request_t * current
static unsigned int hash(char const *username, unsigned int tablesize)
Definition rlm_passwd.c:132
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
return count
Definition module.c:163
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
Definition talloc.c:53
close(uq->fd)
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997