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