Coverage Report

Created: 2025-12-14 06:30

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
179
#define INIT_OFFSETS(name, var, default_offsets) (var) = (default_offsets)
38
39
#define MAKE_EMPTY(name)                           \
40
179
  do {                                       \
41
179
    name->ndata = NULL;                \
42
179
    name->length = 0;                  \
43
179
    name->attributes.absolute = false; \
44
179
  } 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
179
      unsigned int options, isc_buffer_t *target) {
51
179
  unsigned char *cdata, *ndata;
52
179
  unsigned int cused; /* Bytes of compressed name data used */
53
179
  unsigned int nused, labels, n, nmax;
54
179
  unsigned int current, new_current, biggest_pointer;
55
179
  bool done;
56
179
  fw_state state = fw_start;
57
179
  unsigned int c;
58
179
  unsigned char *offsets;
59
179
  dns_offsets_t odata;
60
179
  bool downcase;
61
179
  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
179
  REQUIRE(VALID_NAME(name));
70
179
  REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
71
179
    (target == NULL && ISC_BUFFER_VALID(name->buffer)));
72
73
179
  downcase = ((options & DNS_NAME_DOWNCASE) != 0);
74
75
179
  if (target == NULL && name->buffer != NULL) {
76
179
    target = name->buffer;
77
179
    isc_buffer_clear(target);
78
179
  }
79
80
179
  REQUIRE(BINDABLE(name));
81
82
179
  INIT_OFFSETS(name, offsets, odata);
83
84
  /*
85
   * Make 'name' empty in case of failure.
86
   */
87
179
  MAKE_EMPTY(name);
88
89
  /*
90
   * Initialize things to make the compiler happy; they're not required.
91
   */
92
179
  n = 0;
93
179
  new_current = 0;
94
95
  /*
96
   * Set up.
97
   */
98
179
  labels = 0;
99
179
  done = false;
100
101
179
  ndata = isc_buffer_used(target);
102
179
  nused = 0;
103
179
  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
179
  nmax = isc_buffer_availablelength(target);
112
179
  if (nmax > DNS_NAME_MAXWIRE) {
113
0
    nmax = DNS_NAME_MAXWIRE;
114
0
  }
115
116
179
  cdata = isc_buffer_current(source);
117
179
  cused = 0;
118
119
179
  current = source->current;
120
179
  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
13.3k
  while (current < source->active && !done) {
128
13.2k
    c = *cdata++;
129
13.2k
    current++;
130
13.2k
    if (!seen_pointer) {
131
8.33k
      cused++;
132
8.33k
    }
133
134
13.2k
    switch (state) {
135
3.94k
    case fw_start:
136
3.94k
      if (c < 64) {
137
3.59k
        offsets[labels] = nused;
138
3.59k
        labels++;
139
3.59k
        if (nused + c + 1 > nmax) {
140
21
          goto full;
141
21
        }
142
3.56k
        nused += c + 1;
143
3.56k
        *ndata++ = c;
144
3.56k
        if (c == 0) {
145
64
          done = true;
146
64
        }
147
3.56k
        n = c;
148
3.56k
        state = fw_ordinary;
149
3.56k
      } else if (c >= 192) {
150
        /*
151
         * 14-bit compression pointer
152
         */
153
331
        if (!dns_decompress_getpermitted(dctx)) {
154
0
          return DNS_R_DISALLOWED;
155
0
        }
156
331
        new_current = c & 0x3F;
157
331
        state = fw_newcurrent;
158
331
      } else {
159
20
        return DNS_R_BADLABELTYPE;
160
20
      }
161
3.90k
      break;
162
9.00k
    case fw_ordinary:
163
9.00k
      if (downcase) {
164
0
        c = isc_ascii_tolower(c);
165
0
      }
166
9.00k
      *ndata++ = c;
167
9.00k
      n--;
168
9.00k
      if (n == 0) {
169
3.46k
        state = fw_start;
170
3.46k
      }
171
9.00k
      break;
172
328
    case fw_newcurrent:
173
328
      new_current *= 256;
174
328
      new_current += c;
175
328
      if (new_current >= biggest_pointer) {
176
25
        return DNS_R_BADPOINTER;
177
25
      }
178
303
      biggest_pointer = new_current;
179
303
      current = new_current;
180
303
      cdata = (unsigned char *)source->base + current;
181
303
      seen_pointer = true;
182
303
      state = fw_start;
183
303
      break;
184
0
    default:
185
0
      FATAL_ERROR("Unknown state %d", state);
186
      /* Does not return. */
187
13.2k
    }
188
13.2k
  }
189
190
113
  if (!done) {
191
49
    return ISC_R_UNEXPECTEDEND;
192
49
  }
193
194
64
  name->ndata = (unsigned char *)target->base + target->used;
195
64
  name->length = nused;
196
64
  name->attributes.absolute = true;
197
198
64
  isc_buffer_forward(source, cused);
199
64
  isc_buffer_add(target, name->length);
200
201
64
  return ISC_R_SUCCESS;
202
203
21
full:
204
21
  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
21
    return DNS_R_NAMETOOLONG;
210
21
  } 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
21
}