Bug Summary

File:src/usr.sbin/dhcpd/options.c
Warning:line 207, column 3
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name options.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/dhcpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/dhcpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/dhcpd/options.c
1/* $OpenBSD: options.c,v 1.35 2017/02/13 22:33:39 krw Exp $ */
2
3/* DHCP options parsing and reassembly. */
4
5/*
6 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43#include <sys/types.h>
44#include <sys/socket.h>
45
46#include <net/if.h>
47
48#include <netinet/in.h>
49
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53
54#include "dhcp.h"
55#include "tree.h"
56#include "dhcpd.h"
57#include "log.h"
58
59int bad_options = 0;
60int bad_options_max = 5;
61
62void parse_options(struct packet *);
63void parse_option_buffer(struct packet *, unsigned char *, int);
64void create_priority_list(unsigned char *, unsigned char *, int);
65int store_option_fragment(unsigned char *, int, unsigned char,
66 int, unsigned char *);
67int store_options(unsigned char *, int, struct tree_cache **,
68 unsigned char *, int, int);
69
70
71/*
72 * Parse all available options out of the specified packet.
73 */
74void
75parse_options(struct packet *packet)
76{
77 /* Initially, zero all option pointers. */
78 memset(packet->options, 0, sizeof(packet->options));
79
80 /* If we don't see the magic cookie, there's nothing to parse. */
81 if (memcmp(packet->raw->options, DHCP_OPTIONS_COOKIE"\143\202\123\143", 4)) {
4
Assuming the condition is false
5
Taking false branch
82 packet->options_valid = 0;
83 return;
84 }
85
86 /*
87 * Go through the options field, up to the end of the packet or
88 * the End field.
89 */
90 parse_option_buffer(packet, &packet->raw->options[4],
91 packet->packet_length - DHCP_FIXED_NON_UDP236 - 4);
92
93 /*
94 * If we parsed a DHCP Option Overload option, parse more
95 * options out of the buffer(s) containing them.
96 */
97 if (packet->options_valid
5.1
Field 'options_valid' is 1
&&
7
Taking true branch
98 packet->options[DHO_DHCP_OPTION_OVERLOAD52].data) {
6
Assuming field 'data' is non-null
99 if (packet->options[DHO_DHCP_OPTION_OVERLOAD52].data[0] & 1)
8
Assuming the condition is true
9
Taking true branch
100 parse_option_buffer(packet,
10
Calling 'parse_option_buffer'
24
Returned allocated memory
101 (unsigned char *)packet->raw->file,
102 sizeof(packet->raw->file));
103 if (packet->options[DHO_DHCP_OPTION_OVERLOAD52].data[0] & 2)
25
Assuming the condition is true
26
Taking true branch
104 parse_option_buffer(packet,
27
Calling 'parse_option_buffer'
105 (unsigned char *)packet->raw->sname,
106 sizeof(packet->raw->sname));
107 }
108}
109
110/*
111 * Parse options out of the specified buffer, storing addresses of
112 * option values in packet->options and setting packet->options_valid if
113 * no errors are encountered.
114 */
115void
116parse_option_buffer(struct packet *packet,
117 unsigned char *buffer, int length)
118{
119 unsigned char *s, *t;
120 unsigned char *end = buffer + length;
121 int len;
122 int code;
123
124 for (s = buffer; *s != DHO_END255 && s < end; ) {
11
Assuming the condition is true
12
Loop condition is true. Entering loop body
23
Assuming the condition is false
28
Assuming the condition is true
29
Loop condition is true. Entering loop body
125 code = s[0];
126
127 /* Pad options don't have a length - just skip them. */
128 if (code == DHO_PAD0) {
13
Assuming 'code' is not equal to DHO_PAD
14
Taking false branch
30
Assuming 'code' is not equal to DHO_PAD
31
Taking false branch
129 s++;
130 continue;
131 }
132 if (s + 2 > end) {
15
Taking false branch
32
Taking false branch
133 len = 65536;
134 goto bogus;
135 }
136
137 /*
138 * All other fields (except end, see above) have a
139 * one-byte length.
140 */
141 len = s[1];
142
143 /*
144 * If the length is outrageous, silently skip the rest,
145 * and mark the packet bad. Unfortunately some crappy
146 * dhcp servers always seem to give us garbage on the
147 * end of a packet. so rather than keep refusing, give
148 * up and try to take one after seeing a few without
149 * anything good.
150 */
151 if (s + len + 2 > end) {
16
Assuming the condition is false
17
Taking false branch
33
Assuming the condition is false
34
Taking false branch
152 bogus:
153 bad_options++;
154 log_warnx("option %s (%d) %s.",
155 dhcp_options[code].name, len,
156 "larger than buffer");
157 if (bad_options == bad_options_max) {
158 packet->options_valid = 1;
159 bad_options = 0;
160 log_warnx("Many bogus options seen in "
161 "offers.");
162 log_warnx("Taking this offer in spite of "
163 "bogus");
164 log_warnx("options - hope for the best!");
165 } else {
166 log_warnx("rejecting bogus offer.");
167 packet->options_valid = 0;
168 }
169 return;
170 }
171 /*
172 * If we haven't seen this option before, just make
173 * space for it and copy it there.
174 */
175 if (!packet->options[code].data) {
18
Assuming field 'data' is null
19
Taking true branch
35
Assuming field 'data' is null
36
Taking true branch
176 t = calloc(1, len + 1);
20
Memory is allocated
177 if (!t)
21
Assuming 't' is non-null
22
Taking false branch
37
Assuming 't' is non-null
38
Taking false branch
178 fatalx("Can't allocate storage for option %s.",
179 dhcp_options[code].name);
180 /*
181 * Copy and NUL-terminate the option (in case
182 * it's an ASCII string).
183 */
184 memcpy(t, &s[2], len);
185 t[len] = 0;
186 packet->options[code].len = len;
187 packet->options[code].data = t;
188 } else {
189 /*
190 * If it's a repeat, concatenate it to whatever
191 * we last saw. This is really only required
192 * for clients, but what the heck...
193 */
194 t = calloc(1, len + packet->options[code].len + 1);
195 if (!t)
196 fatalx("Can't expand storage for option %s.",
197 dhcp_options[code].name);
198 memcpy(t, packet->options[code].data,
199 packet->options[code].len);
200 memcpy(t + packet->options[code].len,
201 &s[2], len);
202 packet->options[code].len += len;
203 t[packet->options[code].len] = 0;
204 free(packet->options[code].data);
205 packet->options[code].data = t;
206 }
207 s += len + 2;
39
Potential memory leak
208 }
209 packet->options_valid = 1;
210}
211
212/*
213 * Fill priority_list with a complete list of DHCP options sorted by
214 * priority. i.e.
215 * 1) Mandatory options.
216 * 2) Options from prl that are not already present.
217 * 3) Options from the default list that are not already present.
218 */
219void
220create_priority_list(unsigned char *priority_list, unsigned char *prl,
221 int prl_len)
222{
223 unsigned char stored_list[256];
224 int i, priority_len = 0;
225
226 /* clear stored_list, priority_list should be cleared before */
227 memset(&stored_list, 0, sizeof(stored_list));
228
229 /* Some options we don't want on the priority list. */
230 stored_list[DHO_PAD0] = 1;
231 stored_list[DHO_END255] = 1;
232
233 /* Mandatory options. */
234 for(i = 0; dhcp_option_default_priority_list[i] != DHO_END255; i++) {
235 priority_list[priority_len++] =
236 dhcp_option_default_priority_list[i];
237 stored_list[dhcp_option_default_priority_list[i]] = 1;
238 }
239
240 /* Supplied priority list. */
241 if (!prl)
242 prl_len = 0;
243 for(i = 0; i < prl_len; i++) {
244 /* CLASSLESS routes always have priority, sayeth RFC 3442. */
245 if (prl[i] == DHO_CLASSLESS_STATIC_ROUTES121 ||
246 prl[i] == DHO_CLASSLESS_MS_STATIC_ROUTES249) {
247 priority_list[priority_len++] = prl[i];
248 stored_list[prl[i]] = 1;
249 }
250 }
251 for(i = 0; i < prl_len; i++) {
252 if (stored_list[prl[i]])
253 continue;
254 priority_list[priority_len++] = prl[i];
255 stored_list[prl[i]] = 1;
256 }
257
258 /* Default priority list. */
259 prl = dhcp_option_default_priority_list;
260 for(i = 0; i < 256; i++) {
261 if (stored_list[prl[i]])
262 continue;
263 priority_list[priority_len++] = prl[i];
264 stored_list[prl[i]] = 1;
265 }
266}
267/*
268 * cons options into a big buffer, and then split them out into the
269 * three separate buffers if needed. This allows us to cons up a set of
270 * vendor options using the same routine.
271 */
272int
273cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
274 int mms, struct tree_cache **options,
275 int overload, /* Overload flags that may be set. */
276 int terminate, int bootpp, u_int8_t *prl, int prl_len)
277{
278 unsigned char priority_list[256];
279 unsigned char buffer[4096]; /* Really big buffer... */
280 int bufix, main_buffer_size, option_size;
281
282 /*
283 * If the client has provided a maximum DHCP message size, use
284 * that; otherwise, if it's BOOTP, only 64 bytes; otherwise use
285 * up to the minimum IP MTU size (576 bytes).
286 *
287 * XXX if a BOOTP client specifies a max message size, we will
288 * honor it.
289 */
290 if (!mms &&
291 inpacket &&
292 inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE57].data &&
293 (inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE57].len >=
294 sizeof(u_int16_t))) {
295 mms = getUShort(
296 inpacket->options[DHO_DHCP_MAX_MESSAGE_SIZE57].data);
297 }
298
299 if (mms) {
300 if (mms < 576)
301 mms = 576; /* mms must be >= minimum IP MTU */
302 main_buffer_size = mms - DHCP_FIXED_LEN(236 + (20 + 8));
303 } else if (bootpp)
304 main_buffer_size = 64;
305 else
306 main_buffer_size = 576 - DHCP_FIXED_LEN(236 + (20 + 8));
307
308 if (main_buffer_size > sizeof(outpacket->options))
309 main_buffer_size = sizeof(outpacket->options);
310
311 /*
312 * Initialize the available buffers, some or all of which may not be
313 * used.
314 */
315 memset(outpacket->options, DHO_PAD0, sizeof(outpacket->options));
316 if (overload & 1)
317 memset(outpacket->file, DHO_PAD0, DHCP_FILE_LEN128);
318 if (overload & 2)
319 memset(outpacket->sname, DHO_PAD0, DHCP_SNAME_LEN64);
320 if (bootpp)
321 overload = 0; /* Don't use overload buffers for bootp! */
322
323 /*
324 * Get complete list of possible options in priority order. Use the
325 * list provided in the options. Lacking that use the list provided by
326 * prl. If that is not available just use the default list.
327 */
328 memset(&priority_list, 0, sizeof(priority_list));
329 if (inpacket &&
330 inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST55].data)
331 create_priority_list(priority_list,
332 inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST55].data,
333 inpacket->options[DHO_DHCP_PARAMETER_REQUEST_LIST55].len);
334 else if (prl)
335 create_priority_list(priority_list, prl, prl_len);
336 else
337 create_priority_list(priority_list, NULL((void *)0), 0);
338
339 /*
340 * Copy the options into the big buffer, including leading cookie and
341 * DHCP_OVERLOAD_OPTION, and DHO_END if it fits. All unused space will
342 * be set to DHO_PAD
343 */
344 option_size = store_options(buffer, main_buffer_size, options,
345 priority_list, overload, terminate);
346 if (option_size == 0)
347 return (DHCP_FIXED_NON_UDP236);
348
349 /* Copy the main buffer. */
350 memcpy(&outpacket->options[0], buffer, main_buffer_size);
351 if (option_size <= main_buffer_size)
352 return (DHCP_FIXED_NON_UDP236 + option_size);
353
354 /* Copy the overflow buffers. */
355 bufix = main_buffer_size;
356 if (overload & 1) {
357 memcpy(outpacket->file, &buffer[bufix], DHCP_FILE_LEN128);
358 bufix += DHCP_FILE_LEN128;
359 }
360 if (overload & 2)
361 memcpy(outpacket->sname, &buffer[bufix], DHCP_SNAME_LEN64);
362
363 return (DHCP_FIXED_NON_UDP236 + main_buffer_size);
364}
365
366/*
367 * Store a <code><length><data> fragment in buffer. Return the number of
368 * characters used. Return 0 if no data could be stored.
369 */
370int
371store_option_fragment(unsigned char *buffer, int buffer_size,
372 unsigned char code, int length, unsigned char *data)
373{
374 buffer_size -= 2; /* Space for option code and option length. */
375
376 if (buffer_size < 1)
377 return (0);
378
379 if (buffer_size > 255)
380 buffer_size = 255;
381 if (length > buffer_size)
382 length = buffer_size;
383
384 buffer[0] = code;
385 buffer[1] = length;
386
387 memcpy(&buffer[2], data, length);
388
389 return (length + 2);
390}
391
392/*
393 * Store all the requested options into the requested buffer. Insert the
394 * required cookie, DHO_DHCP_OPTION_OVERLOAD options and append a DHO_END if
395 * if fits. Ensure all buffer space is set to DHO_PAD if unused.
396 */
397int
398store_options(unsigned char *buffer, int main_buffer_size,
399 struct tree_cache **options, unsigned char *priority_list, int overload,
400 int terminate)
401{
402 int buflen, code, cutoff, i, incr, ix, length, optstart, overflow;
403 int second_cutoff;
404 int bufix = 0;
405 int stored_classless = 0;
406
407 overload &= 3; /* Only consider valid bits. */
408
409 cutoff = main_buffer_size;
410 second_cutoff = cutoff + ((overload & 1) ? DHCP_FILE_LEN128 : 0);
411 buflen = second_cutoff + ((overload & 2) ? DHCP_SNAME_LEN64 : 0);
412
413 memset(buffer, DHO_PAD0, buflen);
414 memcpy(buffer, DHCP_OPTIONS_COOKIE"\143\202\123\143", 4);
415
416 if (overload)
417 bufix = 7; /* Reserve space for DHO_DHCP_OPTION_OVERLOAD. */
418 else
419 bufix = 4;
420
421 /*
422 * Store options in the order they appear in the priority list.
423 */
424 for (i = 0; i < 256; i++) {
425 /* Code for next option to try to store. */
426 code = priority_list[i];
427 if (code == DHO_PAD0 || code == DHO_END255)
428 continue;
429
430 if (!options[code] || !tree_evaluate(options[code]))
431 continue;
432
433 /*
434 * RFC 3442 says:
435 *
436 * When a DHCP client requests the Classless Static
437 * Routes option and also requests either or both of the
438 * Router option and the Static Routes option, and the
439 * DHCP server is sending Classless Static Routes options
440 * to that client, the server SHOULD NOT include the
441 * Router or Static Routes options.
442 */
443 if ((code == DHO_ROUTERS3 || code == DHO_STATIC_ROUTES33) &&
444 stored_classless)
445 continue;
446
447 /* We should now have a constant length for the option. */
448 length = options[code]->len;
449
450 /* Try to store the option. */
451 optstart = bufix;
452 ix = 0;
453 while (length) {
454 incr = store_option_fragment(&buffer[bufix],
455 cutoff - bufix, code, length,
456 options[code]->value + ix);
457
458 if (incr > 0) {
459 bufix += incr;
460 length -= incr - 2;
461 ix += incr - 2;
462 continue;
463 }
464
465 /*
466 * No fragment could be stored in the space before the
467 * cutoff. Fill the unusable space with DHO_PAD and
468 * move cutoff for another attempt.
469 */
470 memset(&buffer[bufix], DHO_PAD0, cutoff - bufix);
471 bufix = cutoff;
472 if (cutoff < second_cutoff)
473 cutoff = second_cutoff;
474 else if (cutoff < buflen)
475 cutoff = buflen;
476 else
477 break;
478 }
479
480 if (length > 0) {
481zapfrags:
482 memset(&buffer[optstart], DHO_PAD0, buflen - optstart);
483 bufix = optstart;
484 } else if (terminate && dhcp_options[code].format[0] == 't') {
485 if (bufix < cutoff)
486 buffer[bufix++] = '\0';
487 else
488 goto zapfrags;
489 }
490 if (code == DHO_CLASSLESS_STATIC_ROUTES121 ||
491 code == DHO_CLASSLESS_MS_STATIC_ROUTES249)
492 stored_classless = 1;
493 }
494
495 if (bufix == (4 + (overload ? 3 : 0)))
496 /* Didn't manage to store any options. */
497 return (0);
498
499 if (bufix < buflen)
500 buffer[bufix++] = DHO_END255;
501
502 /* Fill in overload option value based on space used for options. */
503 if (overload) {
504 overflow = bufix - main_buffer_size;
505 if (overflow > 0) {
506 buffer[4] = DHO_DHCP_OPTION_OVERLOAD52;
507 buffer[5] = 1;
508 if (overload & 1) {
509 buffer[6] |= 1;
510 overflow -= DHCP_FILE_LEN128;
511 }
512 if ((overload & 2) && overflow > 0)
513 buffer[6] |= 2;
514 } else {
515 /*
516 * Compact buffer to eliminate the unused
517 * DHO_DHCP_OPTION_OVERLOAD option. Some clients
518 * choke on DHO_PAD options there.
519 */
520 memmove(&buffer[4], &buffer[7], buflen - 7);
521 bufix -= 3;
522 memset(&buffer[bufix], DHO_PAD0, 3);
523 }
524 }
525
526 return (bufix);
527}
528
529void
530do_packet(struct interface_info *interface, struct dhcp_packet *packet,
531 int len, unsigned int from_port, struct iaddr from, struct hardware *hfrom)
532{
533 struct packet tp;
534 int i;
535
536 if (packet->hlen > sizeof(packet->chaddr)) {
1
Assuming the condition is false
2
Taking false branch
537 log_info("Discarding packet with invalid hlen.");
538 return;
539 }
540
541 memset(&tp, 0, sizeof(tp));
542 tp.raw = packet;
543 tp.packet_length = len;
544 tp.client_port = from_port;
545 tp.client_addr = from;
546 tp.interface = interface;
547 tp.haddr = hfrom;
548
549 parse_options(&tp);
3
Calling 'parse_options'
550 if (tp.options_valid &&
551 tp.options[DHO_DHCP_MESSAGE_TYPE53].data)
552 tp.packet_type = tp.options[DHO_DHCP_MESSAGE_TYPE53].data[0];
553
554 if (tp.packet_type)
555 dhcp(&tp, interface->is_udpsock);
556 else
557 bootp(&tp);
558
559 /* Free the data associated with the options. */
560 for (i = 0; i < 256; i++)
561 free(tp.options[i].data);
562}