Bug Summary

File:src/usr.sbin/dhcpd/bootp.c
Warning:line 259, column 8
Access to field 'group' results in a dereference of a null pointer (loaded from variable 'hp')

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 bootp.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/bootp.c
1/* $OpenBSD: bootp.c,v 1.18 2017/02/13 22:33:39 krw Exp $ */
2
3/*
4 * BOOTP Protocol support.
5 */
6
7/*
8 * Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of The Internet Software Consortium nor the names
21 * of its contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
25 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
32 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * This software has been written for the Internet Software Consortium
39 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
40 * Enterprises. To learn more about the Internet Software Consortium,
41 * see ``http://www.vix.com/isc''. To learn more about Vixie
42 * Enterprises, see ``http://www.vix.com''.
43 */
44
45#include <sys/socket.h>
46
47#include <arpa/inet.h>
48
49#include <net/if.h>
50
51#include <netinet/in.h>
52
53#include <errno(*__errno()).h>
54#include <stdio.h>
55#include <string.h>
56
57#include "dhcp.h"
58#include "tree.h"
59#include "dhcpd.h"
60#include "log.h"
61
62void
63bootp(struct packet *packet)
64{
65 struct host_decl *hp, *host = NULL((void *)0);
66 struct packet outgoing;
67 struct dhcp_packet raw;
68 struct sockaddr_in to;
69 struct in_addr from;
70 struct tree_cache *options[256];
71 struct shared_network *s;
72 struct subnet *subnet = NULL((void *)0);
73 struct lease *lease;
74 struct iaddr ip_address;
75 int i;
76
77 if (packet->raw->op != BOOTREQUEST1)
1
Assuming field 'op' is equal to BOOTREQUEST
2
Taking false branch
78 return;
79
80 log_info("BOOTREQUEST from %s via %s%s",
81 print_hw_addr(packet->raw->htype, packet->raw->hlen,
82 packet->raw->chaddr), packet->raw->giaddr.s_addr ?
3
Assuming field 's_addr' is 0
4
'?' condition is false
83 inet_ntoa(packet->raw->giaddr) : packet->interface->name,
84 packet->options_valid ? "" : " (non-rfc1048)");
5
Assuming field 'options_valid' is 0
6
'?' condition is false
85
86 if (!locate_network(packet))
7
Assuming the condition is false
8
Taking false branch
87 return;
88
89 hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr,
90 packet->raw->hlen);
91
92 s = packet->shared_network;
93 lease = find_lease(packet, s, 0);
94
95 /*
96 * Find an IP address in the host_decl that matches the specified
97 * network.
98 */
99 if (hp)
9
Assuming 'hp' is non-null
10
Taking true branch
100 subnet = find_host_for_network(&hp, &ip_address, s);
11
Value assigned to 'hp'
101
102 if (!subnet) {
12
Assuming 'subnet' is non-null
13
Taking false branch
103 /*
104 * We didn't find an applicable host declaration. Just in case
105 * we may be able to dynamically assign an address, see if
106 * there's a host declaration that doesn't have an ip address
107 * associated with it.
108 */
109 if (hp)
110 for (; hp; hp = hp->n_ipaddr)
111 if (!hp->fixed_addr) {
112 host = hp;
113 break;
114 }
115
116 if (host && (!host->group->allow_booting)) {
117 log_info("Ignoring excluded BOOTP client %s",
118 host->name ? host->name :
119 print_hw_addr (packet->raw->htype,
120 packet->raw->hlen, packet->raw->chaddr));
121 return;
122 }
123
124 if (host && (!host->group->allow_bootp)) {
125 log_info("Ignoring BOOTP request from client %s",
126 host->name ? host->name :
127 print_hw_addr(packet->raw->htype,
128 packet->raw->hlen, packet->raw->chaddr));
129 return;
130 }
131
132 /*
133 * If we've been told not to boot unknown clients, and we
134 * didn't find any host record for this client, ignore it.
135 */
136 if (!host && !(s->group->boot_unknown_clients)) {
137 log_info("Ignoring unknown BOOTP client %s via %s",
138 print_hw_addr(packet->raw->htype,
139 packet->raw->hlen, packet->raw->chaddr),
140 packet->raw->giaddr.s_addr ?
141 inet_ntoa(packet->raw->giaddr) :
142 packet->interface->name);
143 return;
144 }
145
146 /*
147 * If we've been told not to boot with bootp on this network,
148 * ignore it.
149 */
150 if (!host && !(s->group->allow_bootp)) {
151 log_info("Ignoring BOOTP request from client %s via "
152 "%s", print_hw_addr(packet->raw->htype,
153 packet->raw->hlen, packet->raw->chaddr),
154 packet->raw->giaddr.s_addr ?
155 inet_ntoa(packet->raw->giaddr) :
156 packet->interface->name);
157 return;
158 }
159
160 /*
161 * If the packet is from a host we don't know and there are no
162 * dynamic bootp addresses on the network it came in on, drop
163 * it on the floor.
164 */
165 if (!(s->group->dynamic_bootp)) {
166lose:
167 log_info("No applicable record for BOOTP host %s via "
168 "%s", print_hw_addr(packet->raw->htype,
169 packet->raw->hlen, packet->raw->chaddr),
170 packet->raw->giaddr.s_addr ?
171 inet_ntoa(packet->raw->giaddr) :
172 packet->interface->name);
173 return;
174 }
175
176 /*
177 * If a lease has already been assigned to this client and it's
178 * still okay to use dynamic bootp on that lease, reassign it.
179 */
180 if (lease) {
181 /*
182 * If this lease can be used for dynamic bootp, do so.
183 */
184 if ((lease->flags & DYNAMIC_BOOTP_OK4)) {
185 /*
186 * If it's not a DYNAMIC_BOOTP lease, release
187 * it before reassigning it so that we don't
188 * get a lease conflict.
189 */
190 if (!(lease->flags & BOOTP_LEASE2))
191 release_lease(lease);
192
193 lease->host = host;
194 ack_lease(packet, lease, 0, 0);
195 return;
196 }
197
198 /*
199 * If dynamic BOOTP is no longer allowed for this
200 * lease, set it free.
201 */
202 release_lease(lease);
203 }
204
205 /*
206 * If there are dynamic bootp addresses that might be
207 * available, try to snag one.
208 */
209 for (lease = s->last_lease;
210 lease && lease->ends <= cur_time;
211 lease = lease->prev) {
212 if ((lease->flags & DYNAMIC_BOOTP_OK4)) {
213 lease->host = host;
214 ack_lease(packet, lease, 0, 0);
215 return;
216 }
217 }
218 goto lose;
219 }
220
221 /* Make sure we're allowed to boot this client. */
222 if (hp && (!hp->group->allow_booting)) {
14
Assuming 'hp' is null
223 log_info("Ignoring excluded BOOTP client %s", hp->name);
224 return;
225 }
226
227 /* Make sure we're allowed to boot this client with bootp. */
228 if (hp
14.1
'hp' is null
&& (!hp->group->allow_bootp)) {
229 log_info("Ignoring BOOTP request from client %s", hp->name);
230 return;
231 }
232
233 /* Set up the outgoing packet... */
234 memset(&outgoing, 0, sizeof outgoing);
235 memset(&raw, 0, sizeof raw);
236 outgoing.raw = &raw;
237
238 /*
239 * If we didn't get a known vendor magic number on the way in, just
240 * copy the input options to the output.
241 */
242 if (!packet->options_valid && !subnet->group->always_reply_rfc1048 &&
15
Assuming field 'options_valid' is not equal to 0
243 (!hp || !hp->group->always_reply_rfc1048)) {
244 memcpy(outgoing.raw->options, packet->raw->options,
245 DHCP_OPTION_LEN(1500 - (236 + (20 + 8))));
246 outgoing.packet_length = BOOTP_MIN_LEN300;
247 } else {
248 struct tree_cache netmask_tree; /* -- RBF */
249
250 /*
251 * Come up with a list of options that we want to send to this
252 * client. Start with the per-subnet options, and then override
253 * those with client-specific options.
254 */
255
256 memcpy(options, subnet->group->options, sizeof(options));
257
258 for (i = 0; i < 256; i++)
16
Loop condition is true. Entering loop body
259 if (hp->group->options[i])
17
Access to field 'group' results in a dereference of a null pointer (loaded from variable 'hp')
260 options[i] = hp->group->options[i];
261
262 /*
263 * Use the subnet mask from the subnet declaration if no other
264 * mask has been provided.
265 */
266 if (!options[DHO_SUBNET_MASK1]) {
267 options[DHO_SUBNET_MASK1] = &netmask_tree;
268 netmask_tree.flags = TC_TEMPORARY2;
269 netmask_tree.value = lease->subnet->netmask.iabuf;
270 netmask_tree.len = lease->subnet->netmask.len;
271 netmask_tree.buf_size = lease->subnet->netmask.len;
272 netmask_tree.timeout = -1;
273 netmask_tree.tree = NULL((void *)0);
274 }
275
276 /*
277 * Pack the options into the buffer. Unlike DHCP, we can't pack
278 * options into the filename and server name buffers.
279 */
280
281 outgoing.packet_length = cons_options(packet, outgoing.raw,
282 0, options, 0, 0, 1, NULL((void *)0), 0);
283
284 if (outgoing.packet_length < BOOTP_MIN_LEN300)
285 outgoing.packet_length = BOOTP_MIN_LEN300;
286 }
287
288 /* Take the fields that we care about... */
289 raw.op = BOOTREPLY2;
290 raw.htype = packet->raw->htype;
291 raw.hlen = packet->raw->hlen;
292 memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr));
293 raw.hops = packet->raw->hops;
294 raw.xid = packet->raw->xid;
295 raw.secs = packet->raw->secs;
296 raw.flags = packet->raw->flags;
297 raw.ciaddr = packet->raw->ciaddr;
298 memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr));
299
300 /* Figure out the address of the next server. */
301 if (hp && hp->group->next_server.len)
302 memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4);
303 else if (subnet->group->next_server.len)
304 memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4);
305 else if (subnet->interface_address.len)
306 memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4);
307 else
308 raw.siaddr = packet->interface->primary_address;
309
310 raw.giaddr = packet->raw->giaddr;
311 if (hp->group->server_name)
312 strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname));
313 else if (subnet->group->server_name)
314 strncpy(raw.sname, subnet->group->server_name,
315 sizeof(raw.sname));
316
317 if (hp->group->filename)
318 strncpy(raw.file, hp->group->filename, sizeof(raw.file));
319 else if (subnet->group->filename)
320 strncpy(raw.file, subnet->group->filename, sizeof(raw.file));
321 else
322 memcpy(raw.file, packet->raw->file, sizeof(raw.file));
323
324 from = packet->interface->primary_address;
325
326 /* Report what we're doing... */
327 log_info("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address),
328 hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen,
329 packet->raw->chaddr), packet->raw->giaddr.s_addr ?
330 inet_ntoa(packet->raw->giaddr) : packet->interface->name);
331
332 /* Set up the parts of the address that are in common. */
333 memset(&to, 0, sizeof(to));
334 to.sin_family = AF_INET2;
335#ifdef HAVE_SA_LEN
336 to.sin_len = sizeof(to);
337#endif
338
339 /* If this was gatewayed, send it back to the gateway... */
340 if (raw.giaddr.s_addr) {
341 to.sin_addr = raw.giaddr;
342 to.sin_port = server_port;
343
344 (void) packet->interface->send_packet(packet->interface, &raw,
345 outgoing.packet_length, from, &to, packet->haddr);
346 return;
347 }
348
349 /*
350 * If it comes from a client that already knows its address and is not
351 * requesting a broadcast response, and we can unicast to a client
352 * without using the ARP protocol, sent it directly to that client.
353 */
354 else if (!(raw.flags & htons(BOOTP_BROADCAST)(__uint16_t)(__builtin_constant_p(32768L) ? (__uint16_t)(((__uint16_t
)(32768L) & 0xffU) << 8 | ((__uint16_t)(32768L) &
0xff00U) >> 8) : __swap16md(32768L))
)) {
355 to.sin_addr = raw.yiaddr;
356 to.sin_port = client_port;
357 } else {
358 /* Otherwise, broadcast it on the local network. */
359 to.sin_addr.s_addr = INADDR_BROADCAST((u_int32_t)(0xffffffff));
360 to.sin_port = client_port; /* XXX */
361 }
362
363 errno(*__errno()) = 0;
364 (void) packet->interface->send_packet(packet->interface, &raw,
365 outgoing.packet_length, from, &to, packet->haddr);
366}