Coverage Report

Created: 2026-01-09 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/fuzz/old.c
Line
Count
Source
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 <isc/ascii.h>
15
#include <isc/buffer.h>
16
#include <isc/result.h>
17
#include <isc/types.h>
18
#include <isc/util.h>
19
20
#include <dns/compress.h>
21
#include <dns/types.h>
22
23
/*
24
 */
25
26
#include "old.h"
27
28
/*
29
 * code copied from lib/dns/name.c as of commit
30
 * 6967973568fe80b03e1729259f8907ce8792be34
31
 */
32
33
typedef enum { fw_start = 0, fw_ordinary, fw_newcurrent } fw_state;
34
35
#define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
36
37
174
#define INIT_OFFSETS(name, var, default_offsets) (var) = (default_offsets)
38
39
#define MAKE_EMPTY(name)                           \
40
174
  do {                                       \
41
174
    name->ndata = NULL;                \
42
174
    name->length = 0;                  \
43
174
    name->attributes.absolute = false; \
44
174
  } while (0)
45
46
#define BINDABLE(name) (!name->attributes.readonly && !name->attributes.dynamic)
47
48
isc_result_t
49
old_name_fromwire(dns_name_t *name, isc_buffer_t *source, dns_decompress_t dctx,
50
174
      unsigned int options, isc_buffer_t *target) {
51
174
  unsigned char *cdata, *ndata;
52
174
  unsigned int cused; /* Bytes of compressed name data used */
53
174
  unsigned int nused, labels, n, nmax;
54
174
  unsigned int current, new_current, biggest_pointer;
55
174
  bool done;
56
174
  fw_state state = fw_start;
57
174
  unsigned int c;
58
174
  unsigned char *offsets;
59
174
  dns_offsets_t odata;
60
174
  bool downcase;
61
174
  bool seen_pointer;
62
63
  /*
64
   * Copy the possibly-compressed name at source into target,
65
   * decompressing it.  Loop prevention is performed by checking
66
   * the new pointer against biggest_pointer.
67
   */
68
69
174
  REQUIRE(VALID_NAME(name));
70
174
  REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
71
174
    (target == NULL && ISC_BUFFER_VALID(name->buffer)));
72
73
174
  downcase = ((options & DNS_NAME_DOWNCASE) != 0);
74
75
174
  if (target == NULL && name->buffer != NULL) {
76
174
    target = name->buffer;
77
174
    isc_buffer_clear(target);
78
174
  }
79
80
174
  REQUIRE(BINDABLE(name));
81
82
174
  INIT_OFFSETS(name, offsets, odata);
83
84
  /*
85
   * Make 'name' empty in case of failure.
86
   */
87
174
  MAKE_EMPTY(name);
88
89
  /*
90
   * Initialize things to make the compiler happy; they're not required.
91
   */
92
174
  n = 0;
93
174
  new_current = 0;
94
95
  /*
96
   * Set up.
97
   */
98
174
  labels = 0;
99
174
  done = false;
100
101
174
  ndata = isc_buffer_used(target);
102
174
  nused = 0;
103
174
  seen_pointer = false;
104
105
  /*
106
   * Find the maximum number of uncompressed target name
107
   * bytes we are willing to generate.  This is the smaller
108
   * of the available target buffer length and the
109
   * maximum legal domain name length (255).
110
   */
111
174
  nmax = isc_buffer_availablelength(target);
112
174
  if (nmax > DNS_NAME_MAXWIRE) {
113
0
    nmax = DNS_NAME_MAXWIRE;
114
0
  }
115
116
174
  cdata = isc_buffer_current(source);
117
174
  cused = 0;
118
119
174
  current = source->current;
120
174
  biggest_pointer = current;
121
122
  /*
123
   * Note:  The following code is not optimized for speed, but
124
   * rather for correctness.  Speed will be addressed in the future.
125
   */
126
127
12.3k
  while (current < source->active && !done) {
128
12.2k
    c = *cdata++;
129
12.2k
    current++;
130
12.2k
    if (!seen_pointer) {
131
7.08k
      cused++;
132
7.08k
    }
133
134
12.2k
    switch (state) {
135
3.40k
    case fw_start:
136
3.40k
      if (c < 64) {
137
3.04k
        offsets[labels] = nused;
138
3.04k
        labels++;
139
3.04k
        if (nused + c + 1 > nmax) {
140
18
          goto full;
141
18
        }
142
3.02k
        nused += c + 1;
143
3.02k
        *ndata++ = c;
144
3.02k
        if (c == 0) {
145
68
          done = true;
146
68
        }
147
3.02k
        n = c;
148
3.02k
        state = fw_ordinary;
149
3.02k
      } else if (c >= 192) {
150
        /*
151
         * 14-bit compression pointer
152
         */
153
342
        if (!dns_decompress_getpermitted(dctx)) {
154
0
          return DNS_R_DISALLOWED;
155
0
        }
156
342
        new_current = c & 0x3F;
157
342
        state = fw_newcurrent;
158
342
      } else {
159
17
        return DNS_R_BADLABELTYPE;
160
17
      }
161
3.37k
      break;
162
8.51k
    case fw_ordinary:
163
8.51k
      if (downcase) {
164
0
        c = isc_ascii_tolower(c);
165
0
      }
166
8.51k
      *ndata++ = c;
167
8.51k
      n--;
168
8.51k
      if (n == 0) {
169
2.92k
        state = fw_start;
170
2.92k
      }
171
8.51k
      break;
172
339
    case fw_newcurrent:
173
339
      new_current *= 256;
174
339
      new_current += c;
175
339
      if (new_current >= biggest_pointer) {
176
26
        return DNS_R_BADPOINTER;
177
26
      }
178
313
      biggest_pointer = new_current;
179
313
      current = new_current;
180
313
      cdata = (unsigned char *)source->base + current;
181
313
      seen_pointer = true;
182
313
      state = fw_start;
183
313
      break;
184
0
    default:
185
0
      FATAL_ERROR("Unknown state %d", state);
186
      /* Does not return. */
187
12.2k
    }
188
12.2k
  }
189
190
113
  if (!done) {
191
45
    return ISC_R_UNEXPECTEDEND;
192
45
  }
193
194
68
  name->ndata = (unsigned char *)target->base + target->used;
195
68
  name->length = nused;
196
68
  name->attributes.absolute = true;
197
198
68
  isc_buffer_forward(source, cused);
199
68
  isc_buffer_add(target, name->length);
200
201
68
  return ISC_R_SUCCESS;
202
203
18
full:
204
18
  if (nmax == DNS_NAME_MAXWIRE) {
205
    /*
206
     * The name did not fit even though we had a buffer
207
     * big enough to fit a maximum-length name.
208
     */
209
18
    return DNS_R_NAMETOOLONG;
210
18
  } else {
211
    /*
212
     * The name might fit if only the caller could give us a
213
     * big enough buffer.
214
     */
215
0
    return ISC_R_NOSPACE;
216
0
  }
217
18
}