Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name report.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -I /usr/src/usr.sbin/dvmrpd -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/dvmrpd/report.c
1/* $OpenBSD: report.c,v 1.12 2023/06/26 10:08:56 claudio 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 int ret = 0;
45
46 log_debug("send_report: interface %s addr %s",
47 iface->name, inet_ntoa(addr));
48
49 if (iface->passive)
50 return (0);
51
52 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL((void *)0))
53 fatal("send_report");
54
55 /* DVMRP header */
56 if (gen_dvmrp_hdr(buf, iface, DVMRP_CODE_REPORT0x02))
57 goto fail;
58
59 ibuf_add(buf, data, len);
60
61 dst.sin_family = AF_INET2;
62 dst.sin_len = sizeof(struct sockaddr_in);
63 dst.sin_addr.s_addr = addr.s_addr;
64
65 ret = send_packet(iface, buf, &dst);
66 ibuf_free(buf);
67 return (ret);
68fail:
69 log_warn("send_report");
70 ibuf_free(buf);
71 return (-1);
72}
73
74void
75recv_report(struct nbr *nbr, char *buf, u_int16_t len)
76{
77 struct route_report rr;
78 u_int32_t netid, netmask;
79 u_int8_t metric, netid_len, prefixlen;
80
81 log_debug("recv_report: neighbor ID %s", inet_ntoa(nbr->id));
82
83 if ((nbr->state != NBR_STA_2_WAY0x04) && (!nbr->compat)) {
84 log_warnx("recv_report: neighbor %s not in state %s",
85 inet_ntoa(nbr->id), "2-WAY");
86 return;
87 }
88
89 /* parse route report */
90 do {
91 /*
92 * get netmask
93 *
94 * The netmask in a DVMRP report is only represented by 3 bytes,
95 * to cope with that we read 4 bytes and shift 8 bits.
96 * The most significant part of the mask is always 255.
97 */
98
99 /* read four bytes */
100 memcpy(&netmask, buf, sizeof(netmask));
101 /* ditch one byte, since we only need three */
102 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;
103 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))
;
104
105 /* set the highest byte to 255 */
106 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))
;
107 buf += 3;
108 len -= 3;
109
110 prefixlen = mask2prefixlen(netmask);
111 netid_len = PREFIX_SIZE(prefixlen)(((prefixlen) + 7) / 8);
112
113 do {
114 /*
115 * get netid
116 *
117 * The length of the netid is depending on the above
118 * netmask.
119 * Read 4 bytes and use the netmask from above to
120 * determine the netid.
121 */
122 memcpy(&netid, buf, sizeof(netid));
123 netid &= netmask;
124
125 buf += netid_len;
126 len -= netid_len;
127
128 /* get metric */
129 memcpy(&metric, buf, sizeof(metric));
130 buf += sizeof(metric);
131 len -= sizeof(metric);
132
133 rr.net.s_addr = netid;
134 rr.mask.s_addr = netmask;
135 rr.nexthop = nbr->id;
136 rr.metric = (metric & METRIC_MASK~0x80);
137
138 /* ifindex */
139 rr.ifindex = nbr->iface->ifindex;
140
141 /* send route report to RDE */
142 dvmrpe_imsg_compose_rde(IMSG_ROUTE_REPORT, nbr->peerid,
143 0, &rr, sizeof(rr));
144
145 } while (!(metric & LAST_MASK0x80) && (len > 0));
146 } while (len > 0);
147
148 return;
149}
150
151/* timers */
152void
153report_timer(int fd, short event, void *arg)
154{
155 struct timeval tv;
156
157 /* request full route report */
158 dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, 0, 0, NULL((void *)0), 0);
159
160 /* restart report timer */
161 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
162 tv.tv_sec = ROUTE_REPORT_INTERVAL60;
163 evtimer_add(&deconf->report_timer, &tv)event_add(&deconf->report_timer, &tv);
164}
165
166int
167start_report_timer(void)
168{
169 struct timeval tv;
170
171 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
172 tv.tv_sec = MIN_FLASH_UPDATE_INTERVAL5; /* XXX safe?? */
173 return (evtimer_add(&deconf->report_timer, &tv)event_add(&deconf->report_timer, &tv));
174}
175
176int
177stop_report_timer(void)
178{
179 return (evtimer_del(&deconf->report_timer)event_del(&deconf->report_timer));
180}
181
182/* route report list */
183void
184rr_list_add(struct rr_head *rr_list, struct route_report *rr)
185{
186 struct rr_entry *le;
187
188 if (rr == NULL((void *)0))
189 fatalx("rr_list_add: no route report");
190
191 if ((le = calloc(1, sizeof(*le))) == NULL((void *)0))
192 fatal("rr_list_add");
193
194 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)
;
195 le->re = rr;
196 rr->refcount++;
197}
198
199void
200rr_list_remove(struct route_report *rr)
201{
202 if (--rr->refcount == 0)
203 free(rr);
204}
205
206void
207rr_list_clr(struct rr_head *rr_list)
208{
209 struct rr_entry *le;
210
211 while ((le = TAILQ_FIRST(rr_list)((rr_list)->tqh_first)) != NULL((void *)0)) {
212 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)
;
213 rr_list_remove(le->re);
214 free(le);
215 }
216}
217
218void
219rr_list_send(struct rr_head *rr_list, struct iface *xiface, struct nbr *nbr)
220{
221 struct rr_entry *le, *le2;
222 struct ibuf *buf;
223 struct iface *iface;
224 struct in_addr addr;
225 u_int32_t netid, netmask;
226 u_int8_t metric, netid_len, prefixlen;
227
228 /* set destination */
229 if (xiface == NULL((void *)0)) {
1
Assuming 'xiface' is not equal to NULL
2
Taking false branch
230 /* directly to a nbr */
231 iface = nbr->iface;
232 addr = nbr->addr;
233 } else {
234 /* multicast on interface */
235 iface = xiface;
236 inet_aton(AllDVMRPRouters"224.0.0.4", &addr);
237 }
238
239 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
240 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL((void *)0))
5
Assuming the condition is false
6
Taking false branch
241 fatal("rr_list_send");
242
243 prefixlen = 0;
244 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
245 (ibuf_size(buf) < 1000)) {
7
Assuming the condition is true
18
Assuming the condition is true
246 /* netmask */
247 netmask = le->re->mask.s_addr;
20
Use of memory after it is freed
248 if (prefixlen != mask2prefixlen(netmask)) {
9
Assuming the condition is false
10
Taking false branch
249 prefixlen = mask2prefixlen(netmask);
250 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;
251 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))
;
252 ibuf_add(buf, &netmask, 3);
253 }
254 netid_len = PREFIX_SIZE(prefixlen)(((prefixlen) + 7) / 8);
255
256 /* netid */
257 netid = le->re->net.s_addr;
258 ibuf_add(buf, &netid, netid_len);
259
260 /* metric */
261 if (iface->ifindex == le->re->ifindex)
11
Assuming 'iface->ifindex' is not equal to 'le->re->ifindex'
12
Taking false branch
262 /* poison reverse */
263 metric = le->re->metric + INFINITY_METRIC31;
264 else
265 metric = le->re->metric;
266
267 /*
268 * determine if we need to flag last entry with current
269 * netmask.
270 */
271 le2 = TAILQ_NEXT(le, entry)((le)->entry.tqe_next);
272 if (le2 != NULL((void *)0)) {
13
Assuming 'le2' is equal to NULL
14
Taking false branch
273 if (mask2prefixlen(le2->re->mask.s_addr) !=
274 prefixlen)
275 metric = metric | LAST_MASK0x80;
276 } else {
277 metric = metric | LAST_MASK0x80;
278 }
279
280 ibuf_add(buf, &metric, sizeof(metric));
281
282 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
283 rr_list_remove(le->re);
284 free(le);
17
Memory is released
285 }
286 send_report(iface, addr, ibuf_data(buf), ibuf_size(buf));
287 ibuf_free(buf);
288 }
289}