Bug Summary

File:src/usr.sbin/eigrpd/rtp.c
Warning:line 215, column 2
Potential leak of memory pointed to by 'pbuf'

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 rtp.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/eigrpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/eigrpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/eigrpd/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/eigrpd/rtp.c
1/* $OpenBSD: rtp.c,v 1.7 2016/09/02 16:44:33 renato Exp $ */
2
3/*
4 * Copyright (c) 2015 Renato Westphal <renato@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 <netinet/in.h>
21#include <netinet/ip.h>
22
23#include <stdlib.h>
24
25#include "eigrpd.h"
26#include "eigrpe.h"
27#include "log.h"
28
29static struct pbuf *rtp_buf_new(struct ibuf *);
30static struct pbuf *rtp_buf_hold(struct pbuf *);
31static void rtp_buf_release(struct pbuf *);
32static struct packet *rtp_packet_new(struct nbr *, uint32_t, struct pbuf *);
33static void rtp_send_packet(struct packet *);
34static void rtp_enqueue_packet(struct packet *);
35static void rtp_send_mcast(struct eigrp_iface *, struct ibuf *);
36static void rtp_retrans_timer(int, short, void *);
37static void rtp_retrans_start_timer(struct packet *);
38static void rtp_retrans_stop_timer(struct packet *);
39
40static struct pbuf *
41rtp_buf_new(struct ibuf *buf)
42{
43 struct pbuf *pbuf;
44
45 if ((pbuf = calloc(1, sizeof(*pbuf))) == NULL((void *)0))
16
Memory is allocated
17
Assuming the condition is false
18
Taking false branch
46 fatal("rtp_buf_new");
47 pbuf->buf = buf;
48
49 return (pbuf);
50}
51
52static struct pbuf *
53rtp_buf_hold(struct pbuf *pbuf)
54{
55 pbuf->refcnt++;
56 return (pbuf);
57}
58
59static void
60rtp_buf_release(struct pbuf *pbuf)
61{
62 if (--pbuf->refcnt == 0) {
63 ibuf_free(pbuf->buf);
64 free(pbuf);
65 }
66}
67
68static struct packet *
69rtp_packet_new(struct nbr *nbr, uint32_t seq_num, struct pbuf *pbuf)
70{
71 struct packet *pkt;
72
73 if ((pkt = calloc(1, sizeof(struct packet))) == NULL((void *)0))
74 fatal("rtp_packet_new");
75
76 pkt->nbr = nbr;
77 pkt->seq_num = seq_num;
78 pkt->pbuf = rtp_buf_hold(pbuf);
79 pkt->attempts = 1;
80 evtimer_set(&pkt->ev_timeout, rtp_retrans_timer, pkt)event_set(&pkt->ev_timeout, -1, 0, rtp_retrans_timer, pkt
)
;
81
82 return (pkt);
83}
84
85void
86rtp_packet_del(struct packet *pkt)
87{
88 TAILQ_REMOVE(&pkt->nbr->retrans_list, pkt, entry)do { if (((pkt)->entry.tqe_next) != ((void *)0)) (pkt)->
entry.tqe_next->entry.tqe_prev = (pkt)->entry.tqe_prev;
else (&pkt->nbr->retrans_list)->tqh_last = (pkt
)->entry.tqe_prev; *(pkt)->entry.tqe_prev = (pkt)->entry
.tqe_next; ; ; } while (0)
;
89 rtp_retrans_stop_timer(pkt);
90 rtp_buf_release(pkt->pbuf);
91 free(pkt);
92}
93
94void
95rtp_process_ack(struct nbr *nbr, uint32_t ack_num)
96{
97 struct eigrp *eigrp = nbr->ei->eigrp;
98 struct packet *pkt;
99
100 /* window size is one */
101 pkt = TAILQ_FIRST(&nbr->retrans_list)((&nbr->retrans_list)->tqh_first);
102 if (pkt && pkt->seq_num == ack_num) {
103 log_debug("%s: nbr %s ack %u", __func__,
104 log_addr(eigrp->af, &nbr->addr), ack_num);
105
106 /* dequeue packet from retransmission queue */
107 rtp_packet_del(pkt);
108
109 /* enqueue next packet from retransmission queue */
110 pkt = TAILQ_FIRST(&nbr->retrans_list)((&nbr->retrans_list)->tqh_first);
111 if (pkt)
112 rtp_send_packet(pkt);
113 }
114}
115
116static void
117rtp_send_packet(struct packet *pkt)
118{
119 rtp_retrans_start_timer(pkt);
120 send_packet(pkt->nbr->ei, pkt->nbr, 0, pkt->pbuf->buf);
121}
122
123static void
124rtp_enqueue_packet(struct packet *pkt)
125{
126 /* only send packet if transmission queue is empty */
127 if (TAILQ_EMPTY(&pkt->nbr->retrans_list)(((&pkt->nbr->retrans_list)->tqh_first) == ((void
*)0))
)
128 rtp_send_packet(pkt);
129
130 TAILQ_INSERT_TAIL(&pkt->nbr->retrans_list, pkt, entry)do { (pkt)->entry.tqe_next = ((void *)0); (pkt)->entry.
tqe_prev = (&pkt->nbr->retrans_list)->tqh_last; *
(&pkt->nbr->retrans_list)->tqh_last = (pkt); (&
pkt->nbr->retrans_list)->tqh_last = &(pkt)->entry
.tqe_next; } while (0)
;
131}
132
133static void
134rtp_seq_inc(struct eigrp *eigrp)
135{
136 /* automatic wraparound with unsigned arithmetic */
137 eigrp->seq_num++;
138
139 /* sequence number 0 is reserved for unreliably transmission */
140 if (eigrp->seq_num == 0)
141 eigrp->seq_num = 1;
142}
143
144void
145rtp_send_ucast(struct nbr *nbr, struct ibuf *buf)
146{
147 struct eigrp *eigrp = nbr->ei->eigrp;
148 struct packet *pkt;
149 struct pbuf *pbuf;
150
151 pbuf = rtp_buf_new(buf);
152 pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
153 rtp_enqueue_packet(pkt);
154 rtp_seq_inc(eigrp);
155}
156
157static void
158rtp_send_mcast(struct eigrp_iface *ei, struct ibuf *buf)
159{
160 struct eigrp *eigrp = ei->eigrp;
161 struct nbr *nbr;
162 int total = 0, pending = 0;
163 struct packet *pkt;
164 struct pbuf *pbuf;
165 uint32_t flags = 0;
166 struct seq_addr_entry *sa;
167 struct seq_addr_head seq_addr_list;
168
169 TAILQ_FOREACH(nbr, &ei->nbr_list, entry)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != (
(void *)0); (nbr) = ((nbr)->entry.tqe_next))
{
4
Assuming 'nbr' is not equal to null
5
Loop condition is true. Entering loop body
10
Assuming 'nbr' is equal to null
11
Loop condition is false. Execution continues on line 176
170 if (nbr->flags & F_EIGRP_NBR_SELF0x01)
6
Assuming the condition is false
7
Taking false branch
171 continue;
172 if (!TAILQ_EMPTY(&nbr->retrans_list)(((&nbr->retrans_list)->tqh_first) == ((void *)0)))
8
Assuming field 'tqh_first' is equal to null
9
Taking false branch
173 pending++;
174 total++;
175 }
176 if (total
11.1
'total' is not equal to 0
== 0)
12
Taking false branch
177 return;
178
179 /*
180 * send a multicast if there's at least one neighbor with an empty
181 * queue on the interface.
182 */
183 if (pending
12.1
'pending' is < 'total'
< total) {
13
Taking true branch
184 /*
185 * build a hello packet with a seq tlv indicating all the
186 * neighbors that have full queues.
187 */
188 if (pending
13.1
'pending' is <= 0
> 0) {
14
Taking false branch
189 flags |= EIGRP_HDR_FLAG_CR0x02;
190 TAILQ_INIT(&seq_addr_list)do { (&seq_addr_list)->tqh_first = ((void *)0); (&
seq_addr_list)->tqh_last = &(&seq_addr_list)->tqh_first
; } while (0)
;
191
192 TAILQ_FOREACH(nbr, &ei->nbr_list, entry)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != (
(void *)0); (nbr) = ((nbr)->entry.tqe_next))
{
193 if (TAILQ_EMPTY(&nbr->retrans_list)(((&nbr->retrans_list)->tqh_first) == ((void *)0)))
194 continue;
195 if ((sa = calloc(1, sizeof(*sa))) == NULL((void *)0))
196 fatal("rtp_send_mcast");
197 sa->af = eigrp->af;
198 sa->addr = nbr->addr;
199 TAILQ_INSERT_TAIL(&seq_addr_list, sa, entry)do { (sa)->entry.tqe_next = ((void *)0); (sa)->entry.tqe_prev
= (&seq_addr_list)->tqh_last; *(&seq_addr_list)->
tqh_last = (sa); (&seq_addr_list)->tqh_last = &(sa
)->entry.tqe_next; } while (0)
;
200 }
201
202 send_hello(ei, &seq_addr_list, eigrp->seq_num);
203 seq_addr_list_clr(&seq_addr_list);
204 }
205 send_packet(ei, NULL((void *)0), flags, buf);
206 }
207
208 /* schedule an unicast retransmission for each neighbor */
209 pbuf = rtp_buf_new(buf);
15
Calling 'rtp_buf_new'
19
Returned allocated memory
210 TAILQ_FOREACH(nbr, &ei->nbr_list, entry)for((nbr) = ((&ei->nbr_list)->tqh_first); (nbr) != (
(void *)0); (nbr) = ((nbr)->entry.tqe_next))
{
20
Assuming 'nbr' is equal to null
21
Loop condition is false. Execution continues on line 215
211 pkt = rtp_packet_new(nbr, eigrp->seq_num, pbuf);
212 TAILQ_INSERT_TAIL(&nbr->retrans_list, pkt, entry)do { (pkt)->entry.tqe_next = ((void *)0); (pkt)->entry.
tqe_prev = (&nbr->retrans_list)->tqh_last; *(&nbr
->retrans_list)->tqh_last = (pkt); (&nbr->retrans_list
)->tqh_last = &(pkt)->entry.tqe_next; } while (0)
;
213 }
214
215 rtp_seq_inc(eigrp);
22
Potential leak of memory pointed to by 'pbuf'
216}
217
218void
219rtp_send(struct eigrp_iface *ei, struct nbr *nbr, struct ibuf *buf)
220{
221 if (nbr)
1
Assuming 'nbr' is null
2
Taking false branch
222 rtp_send_ucast(nbr, buf);
223 else
224 rtp_send_mcast(ei, buf);
3
Calling 'rtp_send_mcast'
225}
226
227void
228rtp_send_ack(struct nbr *nbr)
229{
230 struct eigrp *eigrp = nbr->ei->eigrp;
231 struct ibuf *buf;
232
233 if ((buf = ibuf_dynamic(PKG_DEF_SIZE512,
234 IP_MAXPACKET65535 - sizeof(struct ip))) == NULL((void *)0))
235 fatal("rtp_send_ack");
236
237 /* EIGRP header */
238 if (gen_eigrp_hdr(buf, EIGRP_OPC_HELLO5, 0, 0, eigrp->as)) {
239 log_warnx("%s: failed to send message", __func__);
240 ibuf_free(buf);
241 return;
242 }
243
244 /* send unreliably */
245 send_packet(nbr->ei, nbr, 0, buf);
246 ibuf_free(buf);
247}
248
249/* timers */
250
251/* ARGSUSED */
252static void
253rtp_retrans_timer(int fd, short event, void *arg)
254{
255 struct packet *pkt = arg;
256 struct eigrp *eigrp = pkt->nbr->ei->eigrp;
257
258 pkt->attempts++;
259
260 if (pkt->attempts > RTP_RTRNS_MAX_ATTEMPTS16) {
261 log_warnx("%s: retry limit exceeded, nbr %s", __func__,
262 log_addr(eigrp->af, &pkt->nbr->addr));
263 nbr_del(pkt->nbr);
264 return;
265 }
266
267 rtp_send_packet(pkt);
268}
269
270static void
271rtp_retrans_start_timer(struct packet *pkt)
272{
273 struct timeval tv;
274
275 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
276 tv.tv_sec = RTP_RTRNS_INTERVAL5;
277 if (evtimer_add(&pkt->ev_timeout, &tv)event_add(&pkt->ev_timeout, &tv) == -1)
278 fatal("rtp_retrans_start_timer");
279}
280
281static void
282rtp_retrans_stop_timer(struct packet *pkt)
283{
284 if (evtimer_pending(&pkt->ev_timeout, NULL)event_pending(&pkt->ev_timeout, 0x01, ((void *)0)) &&
285 evtimer_del(&pkt->ev_timeout)event_del(&pkt->ev_timeout) == -1)
286 fatal("rtp_retrans_stop_timer");
287}
288
289/* ARGSUSED */
290void
291rtp_ack_timer(int fd, short event, void *arg)
292{
293 struct nbr *nbr = arg;
294
295 rtp_send_ack(nbr);
296}
297
298void
299rtp_ack_start_timer(struct nbr *nbr)
300{
301 struct timeval tv;
302
303 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
304 tv.tv_usec = RTP_ACK_TIMEOUT100000;
305 if (evtimer_add(&nbr->ev_ack, &tv)event_add(&nbr->ev_ack, &tv) == -1)
306 fatal("rtp_ack_start_timer");
307}
308
309void
310rtp_ack_stop_timer(struct nbr *nbr)
311{
312 if (evtimer_pending(&nbr->ev_ack, NULL)event_pending(&nbr->ev_ack, 0x01, ((void *)0)) &&
313 evtimer_del(&nbr->ev_ack)event_del(&nbr->ev_ack) == -1)
314 fatal("rtp_ack_stop_timer");
315}