The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
fuzzer.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: a94361a62c0da22ceb13848e4bb081e5d4923ce2 $
19 *
20 * @file src/bin/fuzzer.c
21 * @brief Functions to fuzz protocol decoding
22 *
23 * @copyright 2019 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSID("$Id: a94361a62c0da22ceb13848e4bb081e5d4923ce2 $")
26
27#include <freeradius-devel/fuzzer/common.h>
28
29/*
30 * Run from the source directory via:
31 *
32 * ./build/make/jlibtool --mode=execute ./build/bin/local/fuzzer_radius -D share/dictionary /path/to/corpus/directory/
33 */
34
35/*
36 * @todo - re-enable this later.
37 */
38static bool do_encode = false;
39
42
43int LLVMFuzzerInitialize(int *argc, char ***argv);
44int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len);
45
46int LLVMFuzzerInitialize(int *argc, char ***argv)
47{
48 if (fuzzer_common_init(argc, argv, true) < 0) fr_exit_now(EXIT_FAILURE);
49
50 return 1;
51}
52
53static uint8_t encoded_data[65536];
54
55int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
56{
57 TALLOC_CTX * ctx = talloc_init_const("fuzzer");
58 ssize_t slen;
60 void *decode_ctx = NULL;
61 void *encode_ctx = NULL;
64
66 if (!dict) LLVMFuzzerInitialize(NULL, NULL);
67
68 if (tp_decode->test_ctx && (tp_decode->test_ctx(&decode_ctx, NULL, dict, root_da) < 0)) {
69 fr_perror("fuzzer: Failed initializing test point decode_ctx");
70 fr_exit_now(EXIT_FAILURE);
71 }
72
73 if (do_encode) {
74 if (tp_encode->test_ctx && (tp_encode->test_ctx(&encode_ctx, NULL, dict, root_da) < 0)) {
75 fr_perror("fuzzer: Failed initializing test point encode_ctx");
76 fr_exit_now(EXIT_FAILURE);
77 }
78 }
79
80 if (fr_debug_lvl > 3) {
81 FR_PROTO_TRACE("Fuzzer XX_PROTOCOL_XX input");
82
83 FR_PROTO_HEX_DUMP(buf, len, "");
84 }
85
86 /*
87 * Decode the input, and print the resulting data if we
88 * decoded it successfully.
89 *
90 * If we have successfully decoded the data, then encode
91 * it again, too.
92 */
93 if (tp_decode->func(ctx, &vps, buf, len, decode_ctx) < 0) goto cleanup;
94
96
97 if (fr_debug_lvl > 3) fr_pair_list_debug(stderr, &vps);
98
99 if (!do_encode) goto cleanup;
100
101 slen = tp_encode->func(ctx, &vps, encoded_data, sizeof(encoded_data), encode_ctx);
102 if (!slen) goto cleanup;
103
104 if (slen < 0) {
105#if 1
106 /*
107 * We would like to fail on encode, but right now some protocols will decode packets that
108 * they cannot later encode.
109 *
110 * In addition, the decoder "canonicalizes" the value-pairs, by merging the same
111 * attributes into one output pair list. But the encoders don't always split the pair list when encoding.
112 */
113 goto cleanup;
114#else
115 fr_debug_lvl = 4;
116 FR_PROTO_TRACE("Input data for XX_PROTOCOL_XX");
117 FR_PROTO_HEX_DUMP(buf, len, "");
118
119 fr_pair_list_debug(stderr, &vps);
120 fr_perror("fuzzer_XX_PROTOCOL_XX: Failed encoding data");
121 fr_exit_now(EXIT_FAILURE);
122#endif
123 }
124
125 /*
126 * Round-trip: if the encoder produced a packet, decode it again into a fresh pair list. The
127 * result is discarded - the point is that the encoder's output must be something the decoder
128 * accepts without crashing.
129 *
130 * We do this by reinitializing the ctx and decode_ctx.
131 */
132 talloc_free(decode_ctx);
133 talloc_free(ctx);
134 ctx = talloc_init_const("fuzzer-roundtrip");
135 fr_pair_list_init(&vps);
136
137 if (tp_decode->test_ctx && (tp_decode->test_ctx(&decode_ctx, NULL, dict, root_da) < 0)) {
138 fr_perror("fuzzer_XX_PROTOCOL_XX: Failed re-initializing test point decode_ctx");
139 fr_exit_now(EXIT_FAILURE);
140 }
141
142 (void) tp_decode->func(ctx, &vps, encoded_data, (size_t) slen, decode_ctx);
143
144cleanup:
145 talloc_free(decode_ctx);
147 talloc_free(ctx);
148
149 /*
150 * Clear error messages from the run. Clearing these
151 * keeps malloc/free balanced, which helps to avoid the
152 * fuzzers leak heuristics from firing.
153 */
155
156 return 0;
157}
#define RCSID(id)
Definition build.h:512
fr_dict_t * dict
Definition common.c:31
int fuzzer_common_init(int *argc, char ***argv, bool load_proto)
Perform all bootstrapping for the fuzzer.
Definition common.c:55
fr_dict_attr_t const * root_da
Definition common.c:32
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:226
fr_test_point_proto_decode_t XX_PROTOCOL_XX_tp_decode_proto
static bool do_encode
Definition fuzzer.c:38
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition fuzzer.c:46
fr_test_point_proto_encode_t XX_PROTOCOL_XX_tp_encode_proto
static uint8_t encoded_data[65536]
Definition fuzzer.c:53
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
Definition fuzzer.c:55
talloc_free(hp)
int fr_debug_lvl
Definition log.c:41
long int ssize_t
unsigned char uint8_t
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
static fr_internal_encode_ctx_t encode_ctx
static bool cleanup
Definition radsniff.c:59
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:127
fr_tp_proto_decode_t func
Decoder for proto layer.
Definition test_point.h:69
fr_tp_proto_encode_t func
Encoder for proto layer.
Definition test_point.h:77
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:76
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:68
Entry point for protocol decoders.
Definition test_point.h:67
Entry point for protocol encoders.
Definition test_point.h:75
void fr_pair_list_debug(FILE *fp, fr_pair_list_t const *list)
Dumps a list to the default logging destination - Useful for calling from debuggers.
Definition pair_print.c:448
#define PAIR_LIST_VERIFY_WITH_CTX(_c, _x)
Definition pair.h:208
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:41
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