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