Bug Summary

File:src/usr.sbin/dvmrpd/neighbor.c
Warning:line 143, 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 neighbor.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/neighbor.c
1/* $OpenBSD: neighbor.c,v 1.7 2009/04/16 20:11:12 michele Exp $ */
2
3/*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/types.h>
21#include <sys/ioctl.h>
22#include <sys/time.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <net/if.h>
27
28#include <ctype.h>
29#include <err.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <event.h>
34
35#include "igmp.h"
36#include "dvmrpd.h"
37#include "dvmrp.h"
38#include "dvmrpe.h"
39#include "log.h"
40#include "rde.h"
41
42LIST_HEAD(nbr_head, nbr)struct nbr_head { struct nbr *lh_first; };
43
44struct nbr_table {
45 struct nbr_head *hashtbl;
46 u_int32_t hashmask;
47} nbrtable;
48
49#define NBR_HASH(x)&nbrtable.hashtbl[(x) & nbrtable.hashmask] \
50 &nbrtable.hashtbl[(x) & nbrtable.hashmask]
51
52u_int32_t peercnt = NBR_CNTSTART(1 + 1);
53
54struct {
55 int state;
56 enum nbr_event event;
57 enum nbr_action action;
58 int new_state;
59} nbr_fsm_tbl[] = {
60 /* current state event that happened action to take resulting state */
61 {NBR_STA_DOWN0x01, NBR_EVT_PROBE_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_1_WAY0x02},
62 {NBR_STA_ACTIVE(~0x01), NBR_EVT_PROBE_RCVD, NBR_ACT_RST_ITIMER, 0},
63 {NBR_STA_1_WAY0x02, NBR_EVT_2_WAY_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_2_WAY0x04},
64 {NBR_STA_ACTIVE(~0x01), NBR_EVT_1_WAY_RCVD, NBR_ACT_RESET, NBR_STA_1_WAY0x02},
65 {NBR_STA_ANY0xff, NBR_EVT_KILL_NBR, NBR_ACT_DEL, NBR_STA_DOWN0x01},
66 {NBR_STA_ANY0xff, NBR_EVT_ITIMER, NBR_ACT_DEL, NBR_STA_DOWN0x01},
67 {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0},
68};
69
70const char * const nbr_event_names[] = {
71 "NOTHING",
72 "PROBE RCVD",
73 "1-WAY RCVD",
74 "2-WAY RCVD",
75 "KILL NBR",
76 "ITIMER",
77 "LL DOWN"
78};
79
80const char * const nbr_action_names[] = {
81 "NOTHING",
82 "RESET ITIMER",
83 "START ITIMER",
84 "RESET",
85 "DELETE",
86 "CLEAR LISTS"
87};
88
89int
90nbr_fsm(struct nbr *nbr, enum nbr_event event)
91{
92 struct timeval now;
93 int old_state;
94 int new_state = 0;
95 int i, ret = 0;
96
97 old_state = nbr->state;
98 for (i = 0; nbr_fsm_tbl[i].state != -1; i++)
2
Assuming the condition is true
3
Loop condition is true. Entering loop body
99 if ((nbr_fsm_tbl[i].state & old_state) &&
4
Assuming the condition is true
6
Taking true branch
100 (nbr_fsm_tbl[i].event == event)) {
5
Assuming 'event' is equal to field 'event'
101 new_state = nbr_fsm_tbl[i].new_state;
102 break;
7
Execution continues on line 105
103 }
104
105 if (nbr_fsm_tbl[i].state == -1) {
8
Taking false branch
106 /* XXX event outside of the defined fsm, ignore it. */
107 log_warnx("nbr_fsm: neighbor ID %s, "
108 "event '%s' not expected in state '%s'",
109 inet_ntoa(nbr->id), nbr_event_name(event),
110 nbr_state_name(old_state));
111 return (0);
112 }
113
114 switch (nbr_fsm_tbl[i].action) {
9
Control jumps to 'case NBR_ACT_DEL:' at line 124
115 case NBR_ACT_RST_ITIMER:
116 ret = nbr_act_reset_itimer(nbr);
117 break;
118 case NBR_ACT_STRT_ITIMER:
119 ret = nbr_act_start_itimer(nbr);
120 break;
121 case NBR_ACT_RESET:
122 /* XXX nbr action reset */
123 break;
124 case NBR_ACT_DEL:
125 ret = nbr_act_delete(nbr);
10
Calling 'nbr_act_delete'
22
Returning; memory was released via 1st parameter
126 break;
23
Execution continues on line 135
127 case NBR_ACT_CLR_LST:
128 ret = nbr_act_clear_lists(nbr);
129 break;
130 case NBR_ACT_NOTHING:
131 /* do nothing */
132 break;
133 }
134
135 if (ret
23.1
'ret' is 0
) {
24
Taking false branch
136 log_warnx("nbr_fsm: error changing state for neighbor ID %s, "
137 "event '%s', state '%s'", inet_ntoa(nbr->id),
138 nbr_event_name(event), nbr_state_name(old_state));
139 return (-1);
140 }
141
142 if (new_state != 0)
25
Assuming 'new_state' is not equal to 0
26
Taking true branch
143 nbr->state = new_state;
27
Use of memory after it is freed
144
145 if (old_state != nbr->state) {
146 if (old_state & NBR_STA_2_WAY0x04 || nbr->state & NBR_STA_2_WAY0x04) {
147 /* neighbor changed from/to 2_WAY */
148
149 gettimeofday(&now, NULL((void *)0));
150 nbr->uptime = now.tv_sec;
151
152 if (nbr->state & NBR_STA_2_WAY0x04)
153 nbr->iface->adj_cnt++;
154 else
155 nbr->iface->adj_cnt--;
156 }
157
158 log_debug("nbr_fsm: event '%s' resulted in action '%s' and "
159 "changing state for neighbor ID %s from '%s' to '%s'",
160 nbr_event_name(event),
161 nbr_action_name(nbr_fsm_tbl[i].action),
162 inet_ntoa(nbr->id), nbr_state_name(old_state),
163 nbr_state_name(nbr->state));
164 }
165
166 return (ret);
167}
168
169void
170nbr_init(u_int32_t hashsize)
171{
172 u_int32_t hs, i;
173
174 for (hs = 1; hs < hashsize; hs <<= 1)
175 ;
176 nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head));
177 if (nbrtable.hashtbl == NULL((void *)0))
178 fatal("nbr_init");
179
180 for (i = 0; i < hs; i++)
181 LIST_INIT(&nbrtable.hashtbl[i])do { ((&nbrtable.hashtbl[i])->lh_first) = ((void *)0);
} while (0)
;
182
183 nbrtable.hashmask = hs - 1;
184}
185
186struct nbr *
187nbr_new(u_int32_t nbr_id, struct iface *iface, int self)
188{
189 struct nbr_head *head;
190 struct nbr *nbr = NULL((void *)0);
191
192 if ((nbr = calloc(1, sizeof(*nbr))) == NULL((void *)0))
193 fatal("nbr_new");
194
195 nbr->state = NBR_STA_DOWN0x01;
196 nbr->id.s_addr = nbr_id;
197
198 /* get next unused peerid */
199 while (nbr_find_peerid(++peercnt))
200 ;
201 nbr->peerid = peercnt;
202 head = NBR_HASH(nbr->peerid)&nbrtable.hashtbl[(nbr->peerid) & nbrtable.hashmask
]
;
203 LIST_INSERT_HEAD(head, nbr, hash)do { if (((nbr)->hash.le_next = (head)->lh_first) != ((
void *)0)) (head)->lh_first->hash.le_prev = &(nbr)->
hash.le_next; (head)->lh_first = (nbr); (nbr)->hash.le_prev
= &(head)->lh_first; } while (0)
;
204
205 /* add to peer list */
206 nbr->iface = iface;
207 LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry)do { if (((nbr)->entry.le_next = (&iface->nbr_list)
->lh_first) != ((void *)0)) (&iface->nbr_list)->
lh_first->entry.le_prev = &(nbr)->entry.le_next; (&
iface->nbr_list)->lh_first = (nbr); (nbr)->entry.le_prev
= &(&iface->nbr_list)->lh_first; } while (0)
;
208
209 TAILQ_INIT(&nbr->rr_list)do { (&nbr->rr_list)->tqh_first = ((void *)0); (&
nbr->rr_list)->tqh_last = &(&nbr->rr_list)->
tqh_first; } while (0)
;
210
211 /* set event structures */
212 evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr)event_set(&nbr->inactivity_timer, -1, 0, nbr_itimer, nbr
)
;
213
214 log_debug("nbr_new: neighbor ID %s, peerid %lu",
215 inet_ntoa(nbr->id), nbr->peerid);
216
217 return (nbr);
218}
219
220int
221nbr_del(struct nbr *nbr)
222{
223 /* clear lists */
224 rr_list_clr(&nbr->rr_list);
225
226 LIST_REMOVE(nbr, entry)do { if ((nbr)->entry.le_next != ((void *)0)) (nbr)->entry
.le_next->entry.le_prev = (nbr)->entry.le_prev; *(nbr)->
entry.le_prev = (nbr)->entry.le_next; ; ; } while (0)
;
14
Assuming field 'le_next' is equal to null
15
Taking false branch
16
Loop condition is false. Exiting loop
227 LIST_REMOVE(nbr, hash)do { if ((nbr)->hash.le_next != ((void *)0)) (nbr)->hash
.le_next->hash.le_prev = (nbr)->hash.le_prev; *(nbr)->
hash.le_prev = (nbr)->hash.le_next; ; ; } while (0)
;
17
Assuming field 'le_next' is equal to null
18
Taking false branch
19
Loop condition is false. Exiting loop
228
229 free(nbr);
20
Memory is released
230
231 return (0);
232}
233
234struct nbr *
235nbr_find_peerid(u_int32_t peerid)
236{
237 struct nbr_head *head;
238 struct nbr *nbr;
239
240 head = NBR_HASH(peerid)&nbrtable.hashtbl[(peerid) & nbrtable.hashmask];
241
242 LIST_FOREACH(nbr, head, hash)for((nbr) = ((head)->lh_first); (nbr)!= ((void *)0); (nbr)
= ((nbr)->hash.le_next))
{
243 if (nbr->peerid == peerid)
244 return (nbr);
245 }
246
247 return (NULL((void *)0));
248}
249
250struct nbr *
251nbr_find_ip(struct iface *iface, u_int32_t src_ip)
252{
253 struct nbr *nbr = NULL((void *)0);
254
255 LIST_FOREACH(nbr, &iface->nbr_list, entry)for((nbr) = ((&iface->nbr_list)->lh_first); (nbr)!=
((void *)0); (nbr) = ((nbr)->entry.le_next))
{
256 if (nbr->id.s_addr == src_ip) {
257 return (nbr);
258 }
259 }
260
261 return (NULL((void *)0));
262}
263
264/* timers */
265void
266nbr_itimer(int fd, short event, void *arg)
267{
268 struct nbr *nbr = arg;
269
270 log_debug("nbr_itimer: %s", inet_ntoa(nbr->id));
271
272 nbr_fsm(nbr, NBR_EVT_ITIMER);
1
Calling 'nbr_fsm'
273}
274
275int
276nbr_start_itimer(struct nbr *nbr)
277{
278 struct timeval tv;
279
280 log_debug("nbr_start_itimer: %s", inet_ntoa(nbr->id));
281
282 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
283 tv.tv_sec = nbr->iface->dead_interval;
284
285 return (evtimer_add(&nbr->inactivity_timer, &tv)event_add(&nbr->inactivity_timer, &tv));
286}
287
288int
289nbr_stop_itimer(struct nbr *nbr)
290{
291 return (evtimer_del(&nbr->inactivity_timer)event_del(&nbr->inactivity_timer));
292}
293
294int
295nbr_reset_itimer(struct nbr *nbr)
296{
297 struct timeval tv;
298
299 timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0;
300 tv.tv_sec = nbr->iface->dead_interval;
301
302 return (evtimer_add(&nbr->inactivity_timer, &tv)event_add(&nbr->inactivity_timer, &tv));
303}
304
305/* actions */
306int
307nbr_act_start(struct nbr *nbr)
308{
309 log_debug("nbr_act_start: neighbor ID %s", inet_ntoa(nbr->id));
310
311 return (-1);
312}
313
314int
315nbr_act_reset_itimer(struct nbr *nbr)
316{
317 if (nbr_reset_itimer(nbr)) {
318 log_warnx("nbr_act_reset_itimer: cannot schedule inactivity "
319 "timer, neighbor ID %s", inet_ntoa(nbr->id));
320 return (-1);
321 }
322
323 return (0);
324}
325
326int
327nbr_act_start_itimer(struct nbr *nbr)
328{
329 if (nbr_start_itimer(nbr)) {
330 log_warnx("nbr_act_start_itimer: cannot schedule inactivity "
331 "timer, neighbor ID %s",
332 inet_ntoa(nbr->id));
333 return (-1);
334 }
335
336 if (nbr->state == NBR_STA_1_WAY0x02) {
337 /* new nbr, send entire route table, unicast */
338 log_debug("nbr_act_start_itimer: nbr %s, send route table",
339 inet_ntoa(nbr->id));
340
341 dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, nbr->peerid, 0,
342 NULL((void *)0), 0);
343 }
344
345 return (0);
346}
347
348int
349nbr_act_delete(struct nbr *nbr)
350{
351 struct nbr_msg nm;
352
353 log_debug("nbr_act_delete: neighbor ID %s", inet_ntoa(nbr->id));
354
355 /* stop timers */
356 if (nbr_stop_itimer(nbr)) {
11
Assuming the condition is false
12
Taking false branch
357 log_warnx("nbr_act_delete: error removing inactivity timer, "
358 "neighbor ID %s", inet_ntoa(nbr->id));
359 return (-1);
360 }
361
362 nm.address.s_addr = nbr->addr.s_addr;
363 nm.ifindex = nbr->iface->ifindex;
364
365 dvmrpe_imsg_compose_rde(IMSG_NBR_DEL, 0, 0, &nm, sizeof(nm));
366
367 return (nbr_del(nbr));
13
Calling 'nbr_del'
21
Returning; memory was released via 1st parameter
368}
369
370int
371nbr_act_clear_lists(struct nbr *nbr)
372{
373 log_debug("nbr_act_clear_lists: neighbor ID %s", inet_ntoa(nbr->id));
374 rr_list_clr(&nbr->rr_list);
375
376 return (0);
377}
378
379/* names */
380const char *
381nbr_event_name(int event)
382{
383 return (nbr_event_names[event]);
384}
385
386const char *
387nbr_action_name(int action)
388{
389 return (nbr_action_names[action]);
390}
391
392struct ctl_nbr *
393nbr_to_ctl(struct nbr *nbr)
394{
395 static struct ctl_nbr nctl;
396 struct timeval tv, now, res;
397
398 memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name));
399 memcpy(&nctl.id, &nbr->id, sizeof(nctl.id));
400 memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr));
401
402 nctl.state = nbr->state;
403
404 gettimeofday(&now, NULL((void *)0));
405 if (evtimer_pending(&nbr->inactivity_timer, &tv)event_pending(&nbr->inactivity_timer, 0x01, &tv)) {
406 timersub(&tv, &now, &res)do { (&res)->tv_sec = (&tv)->tv_sec - (&now
)->tv_sec; (&res)->tv_usec = (&tv)->tv_usec -
(&now)->tv_usec; if ((&res)->tv_usec < 0) {
(&res)->tv_sec--; (&res)->tv_usec += 1000000; }
} while (0)
;
407 nctl.dead_timer = res.tv_sec;
408 } else
409 nctl.dead_timer = 0;
410
411 if (nbr->state == NBR_STA_2_WAY0x04) {
412 nctl.uptime = now.tv_sec - nbr->uptime;
413 } else
414 nctl.uptime = 0;
415
416 return (&nctl);
417}