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