The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fuzzer_der.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 * @file src/fuzzer/fuzzer_der.c
19 * @brief Fuzz the DER (ASN.1) decoder against an explicit list of root attributes.
20 *
21 * The DER decoder is unusual among FreeRADIUS protocol decoders in that
22 * it cannot meaningfully run with the dictionary root as its starting
23 * attribute - fr_der_decode_proto() explicitly rejects that. Each useful
24 * DER decode begins at a top-level ASN.1 structure such as Certificate
25 * (RFC 5280) or CertificationRequest (RFC 2986). This harness keeps an
26 * explicit list of those roots and selects one per input so a single
27 * binary exercises all DER entry points instead of being pinned to one
28 * via the FR_FUZZER_ROOT_ATTR environment variable.
29 *
30 * Input layout:
31 * byte[0] - selects which root attribute to decode against,
32 * modulo the size of the root table
33 * byte[1..] - DER-encoded payload passed to fr_der_decode_proto()
34 */
35RCSID("$Id: af9119b609ad976548702b3cdd7a56ec9e599026 $")
36
37#include <freeradius-devel/fuzzer/common.h>
38
39/*
40 * The set of DER root attributes this harness fuzzes against.
41 * These names must exist as top-level attributes (DEFINE) in the
42 * DER dictionary - share/dictionary/der/. Adding a new root here
43 * is sufficient to extend coverage; no other change is required.
44 */
45static char const *der_root_names[] = {
46 "Certificate", /* RFC 5280 - X.509 */
47 "CertificateRequest", /* RFC 2986 - PKCS#10 CSR */
48};
49
50#define NUM_DER_ROOTS (sizeof(der_root_names) / sizeof(der_root_names[0]))
51
53
55
56int LLVMFuzzerInitialize(int *argc, char ***argv);
57int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len);
58
59int LLVMFuzzerInitialize(int *argc, char ***argv)
60{
61 size_t i;
62 fr_dict_t const *dict_der;
63
64 if (fuzzer_common_init(argc, argv, true) < 0) fr_exit_now(EXIT_FAILURE);
65
66 /*
67 * The DER protocol dictionary is loaded by fuzzer_common_init()
68 * via libfreeradius_der_dict_protocol's autoload table. The
69 * global `dict` in common.c is the internal dictionary; the
70 * per-protocol dict (which holds Certificate, CertificateRequest
71 * etc.) must be looked up by protocol name.
72 */
74 if (!dict_der) {
75 fr_perror("fuzzer_der: DER protocol dictionary is not loaded");
76 fr_exit_now(EXIT_FAILURE);
77 }
78
79 /*
80 * Resolve each root attribute once. A missing root is a
81 * hard failure: it means the harness is out of sync with
82 * the DER dictionary and the next time CI runs the fuzzer
83 * would silently skip that path.
84 */
85 for (i = 0; i < NUM_DER_ROOTS; i++) {
87 if (!der_roots[i]) {
88 fr_perror("fuzzer_der: failed to find DER root attribute '%s'", der_root_names[i]);
89 fr_exit_now(EXIT_FAILURE);
90 }
91 }
92
93 return 1;
94}
95
96int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
97{
98 TALLOC_CTX *ctx;
100 void *decode_ctx = NULL;
101 fr_dict_attr_t const *root;
103
104 if (!dict) LLVMFuzzerInitialize(NULL, NULL);
105
106 /*
107 * Need at least one selector byte plus one DER byte to
108 * have a non-trivial payload.
109 */
110 if (len < 2) return 0;
111
112 root = der_roots[buf[0] % NUM_DER_ROOTS];
113 buf++;
114 len--;
115
116 ctx = talloc_init_const("fuzzer_der");
117 fr_pair_list_init(&vps);
118
119 if (tp->test_ctx && (tp->test_ctx(&decode_ctx, NULL, dict, root) < 0)) {
120 fr_perror("fuzzer_der: failed initializing decode_ctx");
121 fr_exit_now(EXIT_FAILURE);
122 }
123
124 if (tp->func(ctx, &vps, buf, len, decode_ctx) > 0) {
125 PAIR_LIST_VERIFY_WITH_CTX(ctx, &vps);
126 if (fr_debug_lvl > 3) fr_pair_list_debug(stderr, &vps);
127 }
128
129 talloc_free(decode_ctx);
130 talloc_free(ctx);
131
132 /*
133 * Drop accumulated strerror messages so libFuzzer's leak
134 * heuristics don't see growing allocations.
135 */
137
138 return 0;
139}
#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
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:226
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:3505
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2639
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition dict_util.c:2819
fr_test_point_proto_decode_t der_tp_decode_proto
Definition decode.c:2816
#define NUM_DER_ROOTS
Definition fuzzer_der.c:50
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition fuzzer_der.c:59
static char const * der_root_names[]
Definition fuzzer_der.c:45
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
Definition fuzzer_der.c:96
static fr_dict_attr_t const * der_roots[NUM_DER_ROOTS]
Definition fuzzer_der.c:52
talloc_free(hp)
HIDDEN fr_dict_t const * dict_der
Definition base.c:38
int fr_debug_lvl
Definition log.c:41
unsigned char uint8_t
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
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_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
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
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