The FreeRADIUS server
$Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
src
fuzzer
fuzzer_cf.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: d335ad83535571590eb1b4c8cc7bf8546247652e $
19
*
20
* @file src/bin/fuzzer_cf.c
21
* @brief Functions to fuzz the FreeRADIUS config-file parser
22
*
23
* Targets cf_file_read() and the section/pair tokenisers it drives
24
* (cf_file.c, cf_util.c, cf_parse.c). The full configuration grammar -
25
* sections, pairs, quoting, line continuation, $INCLUDE / $-INCLUDE
26
* resolution, operators, and xlat expansions - is exercised through
27
* this single entry point.
28
*
29
* The harness writes each fuzzer input to a per-process file under the
30
* system temporary directory because cf_file_read() is path-based and
31
* resolves $INCLUDE relative to the directory of the file being parsed.
32
* A pid-suffixed name keeps the harness safe under libFuzzer's -jobs=N.
33
*/
34
RCSID
(
"$Id: d335ad83535571590eb1b4c8cc7bf8546247652e $"
)
35
36
#include <freeradius-devel/build.h>
37
#include <freeradius-devel/server/cf_file.h>
38
#include <freeradius-devel/server/cf_util.h>
39
#include <freeradius-devel/server/main_config.h>
40
#include <freeradius-devel/util/strerror.h>
41
#include <freeradius-devel/util/talloc.h>
42
43
#include <stdint.h>
44
#include <stddef.h>
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <string.h>
48
#include <unistd.h>
49
#include <fcntl.h>
50
51
int
LLVMFuzzerInitialize
(
int
*argc,
char
***argv);
52
int
LLVMFuzzerTestOneInput
(
const
uint8_t
*buf,
size_t
len);
53
54
static
char
fuzz_path
[64];
55
56
int
LLVMFuzzerInitialize
(
UNUSED
int
*argc,
UNUSED
char
***argv)
57
{
58
/*
59
* Each fuzzer worker (libFuzzer -jobs=N) gets its own pid,
60
* so a pid-suffixed path avoids races between workers.
61
*/
62
snprintf
(
fuzz_path
,
sizeof
(
fuzz_path
),
"/tmp/fuzzer_cf_input.%d.conf"
,
63
(
int
) getpid());
64
return
0;
65
}
66
67
int
LLVMFuzzerTestOneInput
(
const
uint8_t
*
data
,
size_t
size)
68
{
69
int
fd;
70
main_config_t
*
config
;
71
size_t
depth
= 0, max_depth = 0;
72
73
/*
74
* cap input size: the parser is line-oriented and a
75
* pathological input can cost a great deal of time without
76
* exposing new states.
77
*/
78
if
(size > 16 * 1024)
return
0;
79
80
/*
81
* Pre-filter on brace nesting depth. The config parser
82
* recurses via C function calls on '{'-introduced
83
* sub-sections (parse_subrequest, parse_foreach,
84
* parse_switch, etc., and cf_section_pass2 walking the
85
* section tree). libFuzzer trivially discovers inputs of
86
* the form "{{{{ ... }}}}" that exhaust the C stack without
87
* revealing any new parser states. Real configs nest fewer
88
* than ten levels deep; the cap is set generously here so
89
* that any legitimate nesting still reaches the parser.
90
*
91
* Quoting is intentionally ignored: a conservative count
92
* can only over-reject, never under-reject, and the cost of
93
* dropping a few well-formed inputs with '{' embedded in
94
* strings is negligible compared with the cost of burning
95
* every fuzz cycle on the same recursion failure.
96
*/
97
for
(
size_t
i = 0; i < size; i++) {
98
if
(
data
[i] ==
'{'
) {
99
depth
++;
100
if
(
depth
> max_depth) max_depth =
depth
;
101
}
else
if
((
data
[i] ==
'}'
) && (
depth
> 0)) {
102
depth
--;
103
}
104
}
105
if
(max_depth > 64)
return
0;
106
107
/*
108
* cf_file_read() takes a path; mirror the input to disk.
109
*/
110
fd = open(
fuzz_path
, O_WRONLY | O_CREAT | O_TRUNC, 0600);
111
if
(fd < 0)
return
0;
112
if
(size && write(fd,
data
, size) != (
ssize_t
) size) {
113
close(fd);
114
unlink(
fuzz_path
);
115
return
0;
116
}
117
close(fd);
118
119
config
=
main_config_alloc
(NULL);
120
if
(!
config
) {
121
unlink(
fuzz_path
);
122
return
0;
123
}
124
125
config
->root_cs =
cf_section_alloc
(
config
, NULL,
"main"
, NULL);
126
if
(!
config
->root_cs) {
127
talloc_free
(
config
);
128
unlink(
fuzz_path
);
129
return
0;
130
}
131
cf_section_set_unlang
(
config
->root_cs);
132
133
(void)
cf_file_read
(
config
->root_cs,
fuzz_path
,
true
);
134
135
talloc_free
(
config
);
136
unlink(
fuzz_path
);
137
138
/*
139
* Clear error messages from the run, keeping malloc/free
140
* balanced so the fuzzer's leak heuristics do not fire.
141
*/
142
fr_strerror_clear
();
143
144
return
0;
145
}
RCSID
#define RCSID(id)
Definition
build.h:512
UNUSED
#define UNUSED
Definition
build.h:336
cf_section_set_unlang
void cf_section_set_unlang(CONF_SECTION *cs)
Definition
cf_file.c:4202
cf_file_read
int cf_file_read(CONF_SECTION *cs, char const *filename, bool root)
Definition
cf_file.c:3710
cf_section_alloc
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition
cf_util.h:201
LLVMFuzzerInitialize
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition
fuzzer.c:94
fuzz_path
static char fuzz_path[64]
Definition
fuzzer_cf.c:54
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
Definition
fuzzer_cf.c:67
talloc_free
talloc_free(hp)
main_config_alloc
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
Definition
main_config.c:1000
main_config_s
Main server configuration.
Definition
main_config.h:51
ssize_t
long int ssize_t
Definition
merged_model.c:24
uint8_t
unsigned char uint8_t
Definition
merged_model.c:30
depth
static uint8_t depth(fr_minmax_heap_index_t i)
Definition
minmax_heap.c:83
config
static const conf_parser_t config[]
Definition
base.c:163
snprintf
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition
snprintf.c:689
fr_strerror_clear
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition
strerror.c:581
data
static fr_slen_t data
Definition
value.h:1340
Generated by
1.9.8