Bug Summary

File:src/usr.sbin/dvmrpd/report.c
Warning:line 252, column 14
Use of memory after it is freed

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 report.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/dvmrpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/dvmrpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/dvmrpd/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/dvmrpd/report.c
1/* $OpenBSD: report.c,v 1.11 2015/12/07 18:59:31 mmcc Exp $ */
2
3/*
4 * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <netinet/in.h>
22#include <netinet/ip.h>
23#include <arpa/inet.h>
24
25#include <stdlib.h>
26#include <string.h>
27
28#include "igmp.h"
29#include "dvmrpd.h"
30#include "dvmrp.h"
31#include "dvmrpe.h"
32#include "log.h"
33
34extern struct dvmrpd_conf *deconf;
35
36void rr_list_remove(struct route_report *);
37
38/* DVMRP report packet handling */
39int
40send_report(struct iface *iface, struct in_addr addr, void *data, int len)
41{
42 struct sockaddr_in dst;
43 struct ibuf *buf;
44 struct dvmrp_hdr *dvmrp_hdr;
45 int ret = 0;
46
47 log_debug("send_report: interface %s addr %s",
48 iface->name, inet_ntoa(addr));
49
50 if (iface->passive)
51 return (0);
52
53 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL((void *)0))
54 fatal("send_report");
55
56 /* DVMRP header */
57 if (gen_dvmrp_hdr(buf, iface, DVMRP_CODE_REPORT0x02))
58 goto fail;
59
60 ibuf_add(buf, data, len);
61
62 dst.sin_family = AF_INET2;
63 dst.sin_len = sizeof(struct sockaddr_in);
64 dst.sin_addr.s_addr = addr.s_addr;
65
66 /* update chksum */
67 dvmrp_hdr = ibuf_seek(buf, 0, sizeof(*dvmrp_hdr));
68 dvmrp_hdr->chksum = in_cksum(buf->buf, buf->wpos);
69
70 ret = send_packet(iface, buf->buf, buf->wpos, &dst);
71 ibuf_free(buf);
72 return (ret);
73fail:
74 log_warn("send_report");
75 ibuf_free(buf);
76 return (-1);
77}
78
79void
80recv_report(struct nbr *nbr, char *buf, u_int16_t len)
81{
82 struct route_report rr;
83 u_int32_t netid, netmask;
84 u_int8_t metric, netid_len, prefixlen;
85
86 log_debug("recv_report: neighbor ID %s", inet_ntoa(nbr->id));
87
88 if ((nbr->state != NBR_STA_2_WAY0x04) && (!nbr->compat)) {
89 log_warnx("recv_report: neighbor %s not in state %s",
90 inet_ntoa(nbr->id), "2-WAY");
91 return;
92 }
93
94 /* parse route report */
95 do {
96 /*
97 * get netmask
98 *
99 * The netmask in a DVMRP report is only represented by 3 bytes,
100 * to cope with that we read 4 bytes and shift 8 bits.
101 * The most significant part of the mask is always 255.
102 */
103
104 /* read four bytes */
105 memcpy(&netmask, buf, sizeof(netmask));
106 /* ditch one byte, since we only need three */
107 netmask = ntohl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t
)(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) &
0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >>
8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md
(netmask))
>> 8;
108 netmask = htonl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t
)(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) &
0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >>
8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md
(netmask))
;
109
110 /* set the highest byte to 255 */
111 netmask |= htonl(0xff000000)(__uint32_t)(__builtin_constant_p(0xff000000) ? (__uint32_t)(
((__uint32_t)(0xff000000) & 0xff) << 24 | ((__uint32_t
)(0xff000000) & 0xff00) << 8 | ((__uint32_t)(0xff000000
) & 0xff0000) >> 8 | ((__uint32_t)(0xff000000) &
0xff000000) >> 24) : __swap32md(0xff000000))
;
112 buf += 3;
113 len -= 3;
114
115 prefixlen = mask2prefixlen(netmask);
116 netid_len = PREFIX_SIZE(prefixlen)(((prefixlen) + 7) / 8);
117
118 do {
119 /*
120 * get netid
121 *
122 * The length of the netid is depending on the above
123 * netmask.
124 * Read 4 bytes and use the netmask from above to
125 * determine the netid.
126 */
127 memcpy(&netid, buf, sizeof(netid));
128 netid &= netmask;
129
130 buf += netid_len;
131 len -= netid_len;
132
133 /* get metric */
134 memcpy(&metric, buf, sizeof(metric));
135 buf += sizeof(metric);
136 len -= sizeof(metric);
137
138 rr.net.s_addr = netid;
139 rr.mask.s_addr = netmask;
140 rr.nexthop = nbr->id;
141 rr.metric = (metric & METRIC_MASK~0x80);
142
143 /* ifindex */
144 rr.ifindex = nbr->iface->ifindex;
145
146 /* send route report to RDE */
147 dvmrpe_imsg_compose_rde(IMSG_ROUTE_REPORT, nbr->peerid,
148 0, &rr, sizeof(rr));
149
150 } while (!(metric & LAST_MASK0x80) && (len > 0));
151 } while (len > 0);
152
153 return;
154}
155
156/* timers */
157void
158report_timer(int fd, short event, void *arg)
159{
160 struct timeval tv;
161
162 /* request full route report */
163 dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, 0, 0, NULL((void *)0), 0);
164
165 /* restart report timer */
166 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
167 tv.tv_sec = ROUTE_REPORT_INTERVAL60;
168 evtimer_add(&deconf->report_timer, &tv)event_add(&deconf->report_timer, &tv);
169}
170
171int
172start_report_timer(void)
173{
174 struct timeval tv;
175
176 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
177 tv.tv_sec = MIN_FLASH_UPDATE_INTERVAL5; /* XXX safe?? */
178 return (evtimer_add(&deconf->report_timer, &tv)event_add(&deconf->report_timer, &tv));
179}
180
181int
182stop_report_timer(void)
183{
184 return (evtimer_del(&deconf->report_timer)event_del(&deconf->report_timer));
185}
186
187/* route report list */
188void
189rr_list_add(struct rr_head *rr_list, struct route_report *rr)
190{
191 struct rr_entry *le;
192
193 if (rr == NULL((void *)0))
194 fatalx("rr_list_add: no route report");
195
196 if ((le = calloc(1, sizeof(*le))) == NULL((void *)0))
197 fatal("rr_list_add");
198
199 TAILQ_INSERT_TAIL(rr_list, le, entry)do { (le)->entry.tqe_next = ((void *)0); (le)->entry.tqe_prev
= (rr_list)->tqh_last; *(rr_list)->tqh_last = (le); (rr_list
)->tqh_last = &(le)->entry.tqe_next; } while (0)
;
200 le->re = rr;
201 rr->refcount++;
202}
203
204void
205rr_list_remove(struct route_report *rr)
206{
207 if (--rr->refcount == 0)
208 free(rr);
209}
210
211void
212rr_list_clr(struct rr_head *rr_list)
213{
214 struct rr_entry *le;
215
216 while ((le = TAILQ_FIRST(rr_list)((rr_list)->tqh_first)) != NULL((void *)0)) {
217 TAILQ_REMOVE(rr_list, le, entry)do { if (((le)->entry.tqe_next) != ((void *)0)) (le)->entry
.tqe_next->entry.tqe_prev = (le)->entry.tqe_prev; else (
rr_list)->tqh_last = (le)->entry.tqe_prev; *(le)->entry
.tqe_prev = (le)->entry.tqe_next; ; ; } while (0)
;
218 rr_list_remove(le->re);
219 free(le);
220 }
221}
222
223void
224rr_list_send(struct rr_head *rr_list, struct iface *xiface, struct nbr *nbr)
225{
226 struct rr_entry *le, *le2;
227 struct ibuf *buf;
228 struct iface *iface;
229 struct in_addr addr;
230 u_int32_t netid, netmask;
231 u_int8_t metric, netid_len, prefixlen;
232
233 /* set destination */
234 if (xiface == NULL((void *)0)) {
1
Assuming 'xiface' is not equal to NULL
2
Taking false branch
235 /* directly to a nbr */
236 iface = nbr->iface;
237 addr = nbr->addr;
238 } else {
239 /* multicast on interface */
240 iface = xiface;
241 inet_aton(AllDVMRPRouters"224.0.0.4", &addr);
242 }
243
244 while (!TAILQ_EMPTY(rr_list)(((rr_list)->tqh_first) == ((void *)0))) {
3
Assuming field 'tqh_first' is not equal to null
4
Loop condition is true. Entering loop body
245 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL((void *)0))
5
Assuming the condition is false
6
Taking false branch
246 fatal("rr_list_send");
247
248 prefixlen = 0;
249 while (((le = TAILQ_FIRST(rr_list)((rr_list)->tqh_first)) != NULL((void *)0)) &&
8
Loop condition is true. Entering loop body
19
Loop condition is true. Entering loop body
250 (buf->wpos < 1000)) {
7
Assuming field 'wpos' is < 1000
18
Assuming field 'wpos' is < 1000
251 /* netmask */
252 netmask = le->re->mask.s_addr;
20
Use of memory after it is freed
253 if (prefixlen != mask2prefixlen(netmask)) {
9
Assuming the condition is false
10
Taking false branch
254 prefixlen = mask2prefixlen(netmask);
255 netmask = ntohl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t
)(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) &
0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >>
8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md
(netmask))
<< 8;
256 netmask = htonl(netmask)(__uint32_t)(__builtin_constant_p(netmask) ? (__uint32_t)(((__uint32_t
)(netmask) & 0xff) << 24 | ((__uint32_t)(netmask) &
0xff00) << 8 | ((__uint32_t)(netmask) & 0xff0000) >>
8 | ((__uint32_t)(netmask) & 0xff000000) >> 24) : __swap32md
(netmask))
;
257 ibuf_add(buf, &netmask, 3);
258 }
259 netid_len = PREFIX_SIZE(prefixlen)(((prefixlen) + 7) / 8);
260
261 /* netid */
262 netid = le->re->net.s_addr;
263 ibuf_add(buf, &netid, netid_len);
264
265 /* metric */
266 if (iface->ifindex == le->re->ifindex)
11
Assuming 'iface->ifindex' is not equal to 'le->re->ifindex'
12
Taking false branch
267 /* poison reverse */
268 metric = le->re->metric + INFINITY_METRIC31;
269 else
270 metric = le->re->metric;
271
272 /*
273 * determine if we need to flag last entry with current
274 * netmask.
275 */
276 le2 = TAILQ_NEXT(le, entry)((le)->entry.tqe_next);
277 if (le2 != NULL((void *)0)) {
13
Assuming 'le2' is equal to NULL
14
Taking false branch
278 if (mask2prefixlen(le2->re->mask.s_addr) !=
279 prefixlen)
280 metric = metric | LAST_MASK0x80;
281 } else {
282 metric = metric | LAST_MASK0x80;
283 }
284
285 ibuf_add(buf, &metric, sizeof(metric));
286
287 TAILQ_REMOVE(rr_list, le, entry)do { if (((le)->entry.tqe_next) != ((void *)0)) (le)->entry
.tqe_next->entry.tqe_prev = (le)->entry.tqe_prev; else (
rr_list)->tqh_last = (le)->entry.tqe_prev; *(le)->entry
.tqe_prev = (le)->entry.tqe_next; ; ; } while (0)
;
15
Taking false branch
16
Loop condition is false. Exiting loop
288 rr_list_remove(le->re);
289 free(le);
17
Memory is released
290 }
291 send_report(iface, addr, buf->buf, buf->wpos);
292 ibuf_free(buf);
293 }
294}