The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
common.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/**
18 * $Id: fb354ecbc4cf2fe48742bfcc86e2f3b79b4b3199 $
19 *
20 * @file src/fuzzer/common.c
21 * @brief Common initialization for fuzzers
22 *
23 * @copyright 2026 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSID("$Id: fb354ecbc4cf2fe48742bfcc86e2f3b79b4b3199 $")
26
27#include <freeradius-devel/fuzzer/common.h>
28
29TALLOC_CTX *autofree = NULL;
30
32fr_dict_attr_t const *root_da = NULL;
33
35
36
37static void exitHandler(void)
38{
40
41 fr_dict_free(&dict, __FILE__);
42
44
45 /*
46 * Ensure our atexit handlers run before any other
47 * atexit handlers registered by third party libraries.
48 */
50}
51
52/** Perform all bootstrapping for the fuzzer.
53 *
54 */
55int fuzzer_common_init(int *argc, char ***argv, bool load_proto)
56{
57 char const *lib_dir = getenv("FR_LIBRARY_PATH");
58 char const *dict_dir = getenv("FR_DICTIONARY_DIR");
59 char const *debug_lvl_str = getenv("FR_DEBUG_LVL");
60 char const *panic_action = getenv("PANIC_ACTION");
61
62 char const *proto = getenv("FR_LIBRARY_FUZZ_PROTOCOL");
63 char const *root_attr = getenv("FR_FUZZER_ROOT_ATTR");
64
65 char *p, buffer[256];
66
67 if (!argc || !argv || !*argv) return -1; /* shut up clang scan */
68
70
71 if (debug_lvl_str) {
72 fr_debug_lvl = atoi(debug_lvl_str);
73 }
74
76 /*
77 * libFuzzer installs its own SIGALRM handler for its
78 * -timeout option, so we skip that signal here rather
79 * than let fr_fault_setup() overwrite it.
80 */
81 if (fr_fault_setup(autofree, panic_action, (*argv)[0],
82 PANIC_ACTION_SIGNALS & ~(1UL << SIGALRM)) < 0) {
83 fr_perror("fuzzer: Failed to register fault handler: %s", fr_syserror(errno));
84 return -1;
85 }
86
87 /*
88 * Setup atexit handlers to free any thread local
89 * memory on exit
90 */
92
93 /*
94 * Initialise the talloc fault handlers.
95 */
97
98 /*
99 * Initialise the error stack _before_ we run any
100 * tests so there's no chance of the memory
101 * appearing as a leak the first time an error
102 * is generated.
103 */
104 fr_strerror_const("fuzz"); /* allocate the pools */
105 fr_strerror_clear(); /* clears the message, leaves the pools */
106
107 /*
108 * Setup our own internal atexit handler
109 */
110 if (atexit(exitHandler)) {
111 fr_perror("fuzzer: Failed to register exit handler: %s", fr_syserror(errno));
112 return -1;
113 }
114
115 /*
116 * Disable hostname lookups, so we don't produce spurious DNS
117 * queries, and there's no chance of spurious failures if
118 * it takes a long time to get a response.
119 */
121
122 /*
123 * Look for -D dir
124 *
125 * If found, nuke it from the argument list.
126 */
127 if (!dict_dir) {
128 int i, j;
129
130 for (i = 0; i < *argc - 1; i++) {
131 p = (*argv)[i];
132
133 if ((p[0] == '-') && (p[1] == 'D')) {
134 dict_dir = (*argv)[i + 1];
135
136 for (j = i + 2; j < *argc; i++, j++) {
137 (*argv)[i] = (*argv)[j];
138 }
139
140 *argc -= 2;
141 break;
142 }
143 }
144 }
145
146#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
147 /*
148 * oss-fuzz puts the dictionaries, etc. into subdirectories named after the location of the
149 * binary. So we find the directory of the binary, and append "/dict" or "/lib" to find
150 * dictionaries and libraries.
151 */
152 p = strrchr((*argv)[0], '/');
153 if (p) {
154 if (!dict_dir) {
155 dict_dir = talloc_asprintf(autofree, "%.*s/dict", (int) (p - (*argv)[0]), (*argv)[0]);
156 if (!dict_dir) return -1;
157 }
158
159 if (!lib_dir) {
160 lib_dir = talloc_asprintf(autofree, "%.*s/lib", (int) (p - (*argv)[0]), (*argv)[0]);
161 if (!lib_dir) return -1;
162 }
163 }
164#endif
165
166 if (!dict_dir) dict_dir = DICTDIR;
167 if (!lib_dir) lib_dir = LIBDIR;
168
169 /*
170 * Set the global search path for all dynamic libraries we load.
171 */
172 if (dl_search_global_path_set(lib_dir) < 0) {
173 fr_perror("fuzzer: Failed setting library path");
174 return -1;
175 }
176
177 /*
178 * When jobs=N is specified the fuzzer spawns worker processes via
179 * a shell. We have removed any -D dictdir argument that were
180 * supplied, so we pass it to our children via the environment.
181 */
182 if (setenv("FR_DICTIONARY_DIR", dict_dir, 1)) {
183 fprintf(stderr, "Failed to set FR_DICTIONARY_DIR env variable\n");
184 return -1;
185 }
186
187 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
188 fr_perror("fuzzer: Failed initializing global dictionary context");
189 return -1;
190 }
191
193 fr_perror("fuzzer: Failed initializing internal dictionary");
194 return -1;
195 }
196
197 if (!load_proto) return 0;
198
199 /*
200 * Get the name from the binary name of fuzzer_foo
201 */
202 if (!proto) {
203 proto = strrchr((*argv)[0], '_');
204 if (proto) proto++;
205 }
206
207 if (!proto) {
208 fr_perror("Failed to find protocol for fuzzer");
209 return -1;
210 }
211
212 if (root_attr) {
213 root_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict), root_attr);
214 if (!root_da) {
215 fr_perror("Failed to find root attribute '%s'", root_attr);
216 return -1;
217 }
218 }
219
220 /*
221 * Search in our symbol space first. We may have been dynamically
222 * or statically linked to the library we're fuzzing...
223 */
224 snprintf(buffer, sizeof(buffer), "libfreeradius_%s_dict_protocol", proto);
225
226 dl_proto = dlsym(RTLD_DEFAULT, buffer);
227 if (!dl_proto) return 0;
228
229 if (dl_proto->init && (dl_proto->init() < 0)) {
230 fr_perror("fuzzer: Failed initializing library %s", buffer);
231 return -1;
232 }
233
234 return 0;
235}
static int const char char buffer[256]
Definition acutest.h:576
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:179
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:310
#define RCSID(id)
Definition build.h:560
TALLOC_CTX * autofree
Definition common.c:29
fr_dict_t * dict
Definition common.c:31
fr_dict_protocol_t * dl_proto
Definition common.c:34
int fuzzer_common_init(int *argc, char ***argv, bool load_proto)
Perform all bootstrapping for the fuzzer.
Definition common.c:55
static void exitHandler(void)
Definition common.c:37
fr_dict_attr_t const * root_da
Definition common.c:32
static char panic_action[512]
The command to execute when panicking.
Definition debug.c:66
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1050
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program, unsigned long fault_signals)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1074
#define PANIC_ACTION_SIGNALS
Definition debug.h:128
fr_dict_protocol_free_t free
free the library
Definition dict.h:485
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3518
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent))
(Re-)Initialize the special internal dictionary
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2637
fr_dict_protocol_init_t init
initialize the library
Definition dict.h:484
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4327
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4711
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:455
int dl_search_global_path_set(char const *lib_dir)
Set the global library path.
Definition dl.c:790
talloc_free(hp)
bool fr_hostname_lookups
hostname -> IP lookups?
Definition inet.c:52
bool fr_reverse_lookups
IP -> hostname lookups?
Definition inet.c:51
int fr_debug_lvl
Definition log.c:41
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_asprintf
Definition talloc.h:151
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
int fr_time_start(void)
Initialize the local time.
Definition time.c:150
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:7
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:581
#define fr_strerror_const(_msg)
Definition strerror.h:223