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