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],
6
Calling 'parse_option_buffer'
22
Returned allocated memory
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
22.1
Field 'options_valid' is 1
&&
24
Taking true branch
98 packet->options[DHO_DHCP_OPTION_OVERLOAD52].data) {
23
Assuming field 'data' is non-null
99 if (packet->options[DHO_DHCP_OPTION_OVERLOAD52].data[0] & 1)
25
Assuming the condition is true
26
Taking true branch
100 parse_option_buffer(packet,
27
Calling 'parse_option_buffer'
101 (unsigned char *)packet->raw->file,
102 sizeof(packet->raw->file));
103 if (packet->options[DHO_DHCP_OPTION_OVERLOAD52].data[0] & 2)
104 parse_option_buffer(packet,
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; ) {
7
Assuming the condition is true
8
Assuming 's' is < 'end'
9
Loop condition is true. Entering loop body
21
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) {
10
Assuming 'code' is not equal to DHO_PAD
11
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) {
12
Assuming the condition is false
13
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) {
14
Assuming the condition is false
15
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) {
16
Assuming field 'data' is null
17
Taking true branch
35
Assuming field 'data' is null
36
Taking true branch
176 t = calloc(1, len + 1);
18
Memory is allocated
177 if (!t)
19
Assuming 't' is non-null
20
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}