Coverage Report

Created: 2023-06-07 06:23

/src/bind9/fuzz/dns_rdata_fromwire_text.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <assert.h>
15
#include <stddef.h>
16
#include <stdint.h>
17
#include <string.h>
18
19
#include <isc/buffer.h>
20
#include <isc/lex.h>
21
#include <isc/mem.h>
22
#include <isc/result.h>
23
#include <isc/util.h>
24
25
#include <dns/callbacks.h>
26
#include <dns/compress.h>
27
#include <dns/master.h>
28
#include <dns/rdata.h>
29
#include <dns/rdatatype.h>
30
31
#include "fuzz.h"
32
33
bool debug = false;
34
35
/*
36
 * Fuzz input to dns_rdata_fromwire(). Then convert the result
37
 * to text, back to wire format, to multiline text, and back to wire
38
 * format again, checking for consistency throughout the sequence.
39
 */
40
41
static isc_mem_t *mctx = NULL;
42
static isc_lex_t *lex = NULL;
43
44
int
45
18
LLVMFuzzerInitialize(int *argc ISC_ATTR_UNUSED, char ***argv ISC_ATTR_UNUSED) {
46
18
  isc_lexspecials_t specials;
47
48
18
  isc_mem_create(&mctx);
49
18
  isc_lex_create(mctx, 64, &lex);
50
51
18
  memset(specials, 0, sizeof(specials));
52
18
  specials[0] = 1;
53
18
  specials['('] = 1;
54
18
  specials[')'] = 1;
55
18
  specials['"'] = 1;
56
18
  isc_lex_setspecials(lex, specials);
57
18
  isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
58
59
18
  return (0);
60
18
}
61
62
static void
63
0
nullmsg(dns_rdatacallbacks_t *cb, const char *fmt, ...) {
64
0
  va_list args;
65
66
0
  UNUSED(cb);
67
68
0
  if (debug) {
69
0
    va_start(args, fmt);
70
0
    vfprintf(stderr, fmt, args);
71
0
    fprintf(stderr, "\n");
72
0
    va_end(args);
73
0
  }
74
0
}
75
76
int
77
6.26k
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
78
6.26k
  char totext[64 * 1044 * 4];
79
6.26k
  dns_compress_t cctx;
80
6.26k
  dns_rdatatype_t rdtype;
81
6.26k
  dns_rdataclass_t rdclass;
82
6.26k
  dns_rdatatype_t typelist[256] = { 1000 }; /* unknown */
83
6.26k
  dns_rdataclass_t classlist[] = { dns_rdataclass_in, dns_rdataclass_hs,
84
6.26k
           dns_rdataclass_ch, dns_rdataclass_any,
85
6.26k
           60 };
86
6.26k
  dns_rdata_t rdata1 = DNS_RDATA_INIT, rdata2 = DNS_RDATA_INIT,
87
6.26k
        rdata3 = DNS_RDATA_INIT;
88
6.26k
  dns_rdatacallbacks_t callbacks;
89
6.26k
  isc_buffer_t source, target;
90
6.26k
  isc_result_t result;
91
6.26k
  unsigned char fromtext[1024];
92
6.26k
  unsigned char fromwire[1024];
93
6.26k
  unsigned char towire[1024];
94
6.26k
  unsigned int classes = (sizeof(classlist) / sizeof(classlist[0]));
95
6.26k
  unsigned int types = 1, flags, t;
96
97
  /*
98
   * First 2 bytes are used to select type and class.
99
   * dns_rdata_fromwire() only accepts input up to 2^16-1 octets.
100
   */
101
6.26k
  if (size < 2 || size > 0xffff + 2) {
102
10
    return (0);
103
10
  }
104
105
  /*
106
   * Append known types to list.
107
   */
108
409M
  for (t = 1; t <= 0x10000; t++) {
109
409M
    char typebuf[256];
110
409M
    if (dns_rdatatype_ismeta(t)) {
111
806k
      continue;
112
806k
    }
113
408M
    dns_rdatatype_format(t, typebuf, sizeof(typebuf));
114
408M
    if (strncmp(typebuf, "TYPE", 4) != 0) {
115
      /* Assert when we need to grow typelist. */
116
506k
      assert(types < sizeof(typelist) / sizeof(typelist[0]));
117
506k
      typelist[types++] = t;
118
506k
    }
119
408M
  }
120
121
  /*
122
   * Random type and class from a limited set.
123
   */
124
6.25k
  rdtype = typelist[(*data++) % types];
125
6.25k
  size--;
126
6.25k
  rdclass = classlist[(*data++) % classes];
127
6.25k
  size--;
128
129
6.25k
  if (debug) {
130
0
    fprintf(stderr, "type=%u, class=%u\n", rdtype, rdclass);
131
0
  }
132
133
6.25k
  dns_rdatacallbacks_init(&callbacks);
134
6.25k
  callbacks.warn = callbacks.error = nullmsg;
135
136
6.25k
  isc_buffer_constinit(&source, data, size);
137
6.25k
  isc_buffer_add(&source, size);
138
6.25k
  isc_buffer_setactive(&source, size);
139
140
6.25k
  isc_buffer_init(&target, fromwire, sizeof(fromwire));
141
142
  /*
143
   * Reject invalid rdata. (Disallow decompression as we are
144
   * reading a packet)
145
   */
146
6.25k
  CHECK(dns_rdata_fromwire(&rdata1, rdclass, rdtype, &source,
147
6.25k
         DNS_DECOMPRESS_NEVER, &target));
148
3.54k
  assert(rdata1.length == size);
149
150
  /*
151
   * Convert to text from wire.
152
   */
153
3.54k
  isc_buffer_init(&target, totext, sizeof(totext) - 1);
154
3.54k
  result = dns_rdata_totext(&rdata1, NULL, &target);
155
3.54k
  assert(result == ISC_R_SUCCESS);
156
157
  /*
158
   * Make debugging easier by NUL terminating.
159
   */
160
3.54k
  totext[isc_buffer_usedlength(&target)] = 0;
161
162
  /*
163
   * Convert to wire from text.
164
   */
165
3.54k
  isc_buffer_constinit(&source, totext, isc_buffer_usedlength(&target));
166
3.54k
  isc_buffer_add(&source, isc_buffer_usedlength(&target));
167
3.54k
  CHECK(isc_lex_openbuffer(lex, &source));
168
169
3.54k
  isc_buffer_init(&target, fromtext, sizeof(fromtext));
170
3.54k
  result = dns_rdata_fromtext(&rdata2, rdclass, rdtype, lex, dns_rootname,
171
3.54k
            0, mctx, &target, &callbacks);
172
3.54k
  if (debug && result != ISC_R_SUCCESS) {
173
0
    fprintf(stderr, "'%s'\n", totext);
174
0
  }
175
3.54k
  assert(result == ISC_R_SUCCESS);
176
3.54k
  assert(rdata2.length == size);
177
3.54k
  assert(!memcmp(rdata2.data, data, size));
178
179
  /*
180
   * Convert to multi-line text from wire.
181
   */
182
3.54k
  isc_buffer_init(&target, totext, sizeof(totext));
183
3.54k
  flags = dns_master_styleflags(&dns_master_style_default);
184
3.54k
  result = dns_rdata_tofmttext(&rdata1, dns_rootname, flags, 80 - 32, 4,
185
3.54k
             "\n", &target);
186
3.54k
  assert(result == ISC_R_SUCCESS);
187
188
  /*
189
   * Convert to wire from text.
190
   */
191
3.54k
  isc_buffer_constinit(&source, totext, isc_buffer_usedlength(&target));
192
3.54k
  isc_buffer_add(&source, isc_buffer_usedlength(&target));
193
3.54k
  CHECK(isc_lex_openbuffer(lex, &source));
194
195
3.54k
  isc_buffer_init(&target, fromtext, sizeof(fromtext));
196
3.54k
  result = dns_rdata_fromtext(&rdata3, rdclass, rdtype, lex, dns_rootname,
197
3.54k
            0, mctx, &target, &callbacks);
198
3.54k
  assert(result == ISC_R_SUCCESS);
199
3.54k
  assert(rdata3.length == size);
200
3.54k
  assert(!memcmp(rdata3.data, data, size));
201
202
  /*
203
   * Convert rdata back to wire.
204
   */
205
3.54k
  dns_compress_init(&cctx, mctx, DNS_COMPRESS_DISABLED);
206
3.54k
  isc_buffer_init(&target, towire, sizeof(towire));
207
3.54k
  result = dns_rdata_towire(&rdata1, &cctx, &target);
208
3.54k
  dns_compress_invalidate(&cctx);
209
3.54k
  assert(result == ISC_R_SUCCESS);
210
3.54k
  assert(target.used == size);
211
3.54k
  assert(!memcmp(target.base, data, size));
212
213
3.54k
  return (0);
214
3.54k
}