Bug Summary

File:src/usr.sbin/ripd/ripd.c
Warning:line 192, column 14
Access to field 'opts' results in a dereference of a null pointer (loaded from variable 'conf')

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 ripd.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/ripd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/ripd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/ripd/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/ripd/ripd.c
1/* $OpenBSD: ripd.c,v 1.36 2021/09/06 13:32:18 deraadt Exp $ */
2
3/*
4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/queue.h>
25#include <sys/time.h>
26#include <sys/stat.h>
27#include <sys/wait.h>
28#include <sys/sysctl.h>
29
30#include <netinet/in.h>
31#include <arpa/inet.h>
32
33#include <event.h>
34#include <err.h>
35#include <errno(*__errno()).h>
36#include <pwd.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <signal.h>
41#include <unistd.h>
42
43#include "rip.h"
44#include "ripd.h"
45#include "ripe.h"
46#include "log.h"
47#include "control.h"
48#include "rde.h"
49
50__dead__attribute__((__noreturn__)) void usage(void);
51void main_sig_handler(int, short, void *);
52__dead__attribute__((__noreturn__)) void ripd_shutdown(void);
53void main_dispatch_ripe(int, short, void *);
54void main_dispatch_rde(int, short, void *);
55
56int pipe_parent2ripe[2];
57int pipe_parent2rde[2];
58int pipe_ripe2rde[2];
59
60struct ripd_conf *conf = NULL((void *)0);
61static struct imsgev *iev_ripe;
62static struct imsgev *iev_rde;
63
64pid_t ripe_pid = 0;
65pid_t rde_pid = 0;
66
67__dead__attribute__((__noreturn__)) void
68usage(void)
69{
70 extern char *__progname;
71
72 fprintf(stderr(&__sF[2]),
73 "usage: %s [-dnv] [-D macro=value] [-f file] [-s socket]\n",
74 __progname);
75 exit(1);
76}
77
78/* ARGSUSED */
79void
80main_sig_handler(int sig, short event, void *arg)
81{
82 /* signal handler rules don't apply, libevent decouples for us */
83 switch (sig) {
84 case SIGTERM15:
85 case SIGINT2:
86 ripd_shutdown();
87 /* NOTREACHED */
88 case SIGHUP1:
89 /* reconfigure */
90 /* ... */
91 break;
92 default:
93 fatalx("unexpected signal");
94 /* NOTREACHED */
95 }
96}
97
98int
99main(int argc, char *argv[])
100{
101 struct event ev_sigint, ev_sigterm, ev_sighup;
102 int mib[4];
103 int debug = 0;
104 int ipforwarding;
105 int ch;
106 int opts = 0;
107 char *conffile;
108 char *sockname;
109 size_t len;
110
111 conffile = CONF_FILE"/etc/ripd.conf";
112 log_procname = "parent";
113 sockname = RIPD_SOCKET"/var/run/ripd.sock";
114
115 log_init(1); /* log to stderr until daemonized */
116 log_verbose(1);
117
118 while ((ch = getopt(argc, argv, "cdD:f:ns:v")) != -1) {
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 151
119 switch (ch) {
120 case 'c':
121 opts |= RIPD_OPT_FORCE_DEMOTE0x00000008;
122 break;
123 case 'd':
124 debug = 1;
125 break;
126 case 'D':
127 if (cmdline_symset(optarg) < 0)
128 log_warnx("could not parse macro definition %s",
129 optarg);
130 break;
131 case 'f':
132 conffile = optarg;
133 break;
134 case 'n':
135 opts |= RIPD_OPT_NOACTION0x00000004;
136 break;
137 case 's':
138 sockname = optarg;
139 break;
140 case 'v':
141 if (opts & RIPD_OPT_VERBOSE0x00000001)
142 opts |= RIPD_OPT_VERBOSE20x00000002;
143 opts |= RIPD_OPT_VERBOSE0x00000001;
144 break;
145 default:
146 usage();
147 /* NOTREACHED */
148 }
149 }
150
151 argc -= optind;
152 argv += optind;
153 if (argc > 0)
3
Assuming 'argc' is <= 0
4
Taking false branch
154 usage();
155
156 mib[0] = CTL_NET4;
157 mib[1] = PF_INET2;
158 mib[2] = IPPROTO_IP0;
159 mib[3] = IPCTL_FORWARDING1;
160 len = sizeof(ipforwarding);
161 if (sysctl(mib, 4, &ipforwarding, &len, NULL((void *)0), 0) == -1)
5
Assuming the condition is false
6
Taking false branch
162 err(1, "sysctl");
163
164 if (!ipforwarding)
7
Assuming 'ipforwarding' is not equal to 0
8
Taking false branch
165 log_warnx("WARNING: IP forwarding NOT enabled");
166
167 /* fetch interfaces early */
168 kif_init();
169
170 /* parse config file */
171 if ((conf = parse_config(conffile, opts)) == NULL((void *)0) )
9
Assuming the condition is false
10
Taking false branch
172 exit(1);
173 conf->csock = sockname;
174
175 if (conf->opts & RIPD_OPT_NOACTION0x00000004) {
11
Assuming the condition is false
12
Taking false branch
176 if (conf->opts & RIPD_OPT_VERBOSE0x00000001)
177 print_config(conf);
178 else
179 fprintf(stderr(&__sF[2]), "configuration OK\n");
180 exit(0);
181 }
182
183 /* check for root privileges */
184 if (geteuid())
13
Assuming the condition is false
14
Taking false branch
185 errx(1, "need root privileges");
186
187 /* check for ripd user */
188 if (getpwnam(RIPD_USER"_ripd") == NULL((void *)0))
15
Assuming the condition is false
16
Taking false branch
189 errx(1, "unknown user %s", RIPD_USER"_ripd");
190
191 log_init(debug);
17
Null pointer value stored to 'conf'
192 log_verbose(conf->opts & RIPD_OPT_VERBOSE0x00000001);
18
Access to field 'opts' results in a dereference of a null pointer (loaded from variable 'conf')
193
194 if (!debug)
195 daemon(1, 0);
196
197 log_info("startup");
198
199 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
200 PF_UNSPEC0, pipe_parent2ripe) == -1)
201 fatal("socketpair");
202 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
203 PF_UNSPEC0, pipe_parent2rde) == -1)
204 fatal("socketpair");
205 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
206 PF_UNSPEC0, pipe_ripe2rde) == -1)
207 fatal("socketpair");
208
209 /* start children */
210 rde_pid = rde(conf, pipe_parent2rde, pipe_ripe2rde, pipe_parent2ripe);
211 ripe_pid = ripe(conf, pipe_parent2ripe, pipe_ripe2rde, pipe_parent2rde);
212
213 /* no filesystem visibility */
214 if (unveil("/", "") == -1)
215 fatal("unveil /");
216 if (unveil(NULL((void *)0), NULL((void *)0)) == -1)
217 fatal("unveil");
218
219 event_init();
220
221 /* setup signal handler */
222 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void
*)0))
;
223 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, (
(void *)0))
;
224 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void
*)0))
;
225 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
226 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
227 signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0));
228 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
229
230 /* setup pipes to children */
231 close(pipe_parent2ripe[1]);
232 close(pipe_parent2rde[1]);
233 close(pipe_ripe2rde[0]);
234 close(pipe_ripe2rde[1]);
235
236 if ((iev_ripe = malloc(sizeof(struct imsgev))) == NULL((void *)0) ||
237 (iev_rde = malloc(sizeof(struct imsgev))) == NULL((void *)0))
238 fatal(NULL((void *)0));
239 imsg_init(&iev_ripe->ibuf, pipe_parent2ripe[0]);
240 iev_ripe->handler = main_dispatch_ripe;
241 imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]);
242 iev_rde->handler = main_dispatch_rde;
243
244 /* setup event handler */
245 iev_ripe->events = EV_READ0x02;
246 event_set(&iev_ripe->ev, iev_ripe->ibuf.fd, iev_ripe->events,
247 iev_ripe->handler, iev_ripe);
248 event_add(&iev_ripe->ev, NULL((void *)0));
249
250 iev_rde->events = EV_READ0x02;
251 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
252 iev_rde->handler, iev_rde);
253 event_add(&iev_rde->ev, NULL((void *)0));
254
255 if (kr_init(!(conf->flags & RIPD_FLAG_NO_FIB_UPDATE0x0001),
256 conf->rdomain, conf->fib_priority) == -1)
257 fatalx("kr_init failed");
258
259 event_dispatch();
260
261 ripd_shutdown();
262 /* NOTREACHED */
263 return (0);
264}
265
266__dead__attribute__((__noreturn__)) void
267ripd_shutdown(void)
268{
269 struct iface *i;
270 pid_t pid;
271 int status;
272
273 /* close pipes */
274 msgbuf_clear(&iev_ripe->ibuf.w);
275 close(iev_ripe->ibuf.fd);
276 msgbuf_clear(&iev_rde->ibuf.w);
277 close(iev_rde->ibuf.fd);
278
279 while ((i = LIST_FIRST(&conf->iface_list)((&conf->iface_list)->lh_first)) != NULL((void *)0)) {
280 LIST_REMOVE(i, entry)do { if ((i)->entry.le_next != ((void *)0)) (i)->entry.
le_next->entry.le_prev = (i)->entry.le_prev; *(i)->entry
.le_prev = (i)->entry.le_next; ; ; } while (0)
;
281 if_del(i);
282 }
283
284 kr_shutdown();
285
286 log_debug("waiting for children to terminate");
287 do {
288 pid = wait(&status);
289 if (pid == -1) {
290 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10)
291 fatal("wait");
292 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
293 log_warnx("%s terminated; signal %d",
294 (pid == rde_pid) ? "route decision engine" :
295 "rip engine", WTERMSIG(status)(((status) & 0177)));
296 } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4));
297
298 free(iev_ripe);
299 free(iev_rde);
300 free(conf);
301
302 log_info("terminating");
303 exit(0);
304}
305
306/* imsg handling */
307/* ARGSUSED */
308void
309main_dispatch_ripe(int fd, short event, void *bula)
310{
311 struct imsgev *iev = bula;
312 struct imsgbuf *ibuf = &iev->ibuf;
313 struct imsg imsg;
314 struct demote_msg dmsg;
315 ssize_t n;
316 int shut = 0, verbose;
317
318 if (event & EV_READ0x02) {
319 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
320 fatal("imsg_read error");
321 if (n == 0) /* connection closed */
322 shut = 1;
323 }
324 if (event & EV_WRITE0x04) {
325 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
326 fatal("msgbuf_write");
327 if (n == 0) /* connection closed */
328 shut = 1;
329 }
330
331 for (;;) {
332 if ((n = imsg_get(ibuf, &imsg)) == -1)
333 fatal("imsg_get");
334
335 if (n == 0)
336 break;
337
338 switch (imsg.hdr.type) {
339 case IMSG_CTL_RELOAD:
340 /* XXX reconfig */
341 break;
342 case IMSG_CTL_FIB_COUPLE:
343 kr_fib_couple();
344 break;
345 case IMSG_CTL_FIB_DECOUPLE:
346 kr_fib_decouple();
347 break;
348 case IMSG_CTL_KROUTE:
349 case IMSG_CTL_KROUTE_ADDR:
350 kr_show_route(&imsg);
351 break;
352 case IMSG_CTL_IFINFO:
353 if (imsg.hdr.len == IMSG_HEADER_SIZEsizeof(struct imsg_hdr))
354 kr_ifinfo(NULL((void *)0), imsg.hdr.pid);
355 else if (imsg.hdr.len == IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + IFNAMSIZ16)
356 kr_ifinfo(imsg.data, imsg.hdr.pid);
357 else
358 log_warnx("IFINFO request with wrong len");
359 break;
360 case IMSG_DEMOTE:
361 if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(dmsg))
362 fatalx("invalid size of OE request");
363 memcpy(&dmsg, imsg.data, sizeof(dmsg));
364 carp_demote_set(dmsg.demote_group, dmsg.level);
365 break;
366 case IMSG_CTL_LOG_VERBOSE:
367 /* already checked by ripe */
368 memcpy(&verbose, imsg.data, sizeof(verbose));
369 log_verbose(verbose);
370 break;
371 default:
372 log_debug("main_dispatch_ripe: error handling imsg %d",
373 imsg.hdr.type);
374 break;
375 }
376 imsg_free(&imsg);
377 }
378 if (!shut)
379 imsg_event_add(iev);
380 else {
381 /* this pipe is dead, so remove the event handler */
382 event_del(&iev->ev);
383 event_loopexit(NULL((void *)0));
384 }
385}
386
387/* ARGSUSED */
388void
389main_dispatch_rde(int fd, short event, void *bula)
390{
391 struct imsgev *iev = bula;
392 struct imsgbuf *ibuf = &iev->ibuf;
393 struct imsg imsg;
394 ssize_t n;
395 int shut = 0;
396
397 if (event & EV_READ0x02) {
398 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
399 fatal("imsg_read error");
400 if (n == 0) /* connection closed */
401 shut = 1;
402 }
403 if (event & EV_WRITE0x04) {
404 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
405 fatal("msgbuf_write");
406 if (n == 0) /* connection closed */
407 shut = 1;
408 }
409
410 for (;;) {
411 if ((n = imsg_get(ibuf, &imsg)) == -1)
412 fatal("imsg_get");
413
414 if (n == 0)
415 break;
416
417 switch (imsg.hdr.type) {
418 case IMSG_KROUTE_CHANGE:
419 if (kr_change(imsg.data))
420 log_warn("main_dispatch_rde: error changing "
421 "route");
422 break;
423 case IMSG_KROUTE_DELETE:
424 if (kr_delete(imsg.data))
425 log_warn("main_dispatch_rde: error deleting "
426 "route");
427 break;
428 default:
429 log_debug("main_dispatch_rde: error handling imsg %d",
430 imsg.hdr.type);
431 break;
432 }
433 imsg_free(&imsg);
434 }
435 if (!shut)
436 imsg_event_add(iev);
437 else {
438 /* this pipe is dead, so remove the event handler */
439 event_del(&iev->ev);
440 event_loopexit(NULL((void *)0));
441 }
442}
443
444void
445main_imsg_compose_ripe(int type, pid_t pid, void *data, u_int16_t datalen)
446{
447 imsg_compose_event(iev_ripe, type, 0, pid, -1, data, datalen);
448}
449
450void
451main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
452{
453 imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
454}
455
456int
457rip_redistribute(struct kroute *kr)
458{
459 struct redistribute *r;
460 u_int8_t is_default = 0;
461
462 if (kr->flags & F_RIPD_INSERTED0x0001)
463 return (1);
464
465 /* only allow 0.0.0.0/0 via REDIST_DEFAULT */
466 if (kr->prefix.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) && kr->netmask.s_addr == INADDR_ANY((u_int32_t)(0x00000000)))
467 is_default = 1;
468
469 SIMPLEQ_FOREACH(r, &conf->redist_list, entry)for((r) = ((&conf->redist_list)->sqh_first); (r) !=
((void *)0); (r) = ((r)->entry.sqe_next))
{
470 switch (r->type & ~REDIST_NO0x20) {
471 case REDIST_LABEL0x04:
472 if (kr->rtlabel == r->label)
473 return (r->type & REDIST_NO0x20 ? 0 : 1);
474 break;
475 case REDIST_STATIC0x02:
476 /*
477 * Dynamic routes are not redistributable. Placed here
478 * so that link local addresses can be redistributed
479 * via a rtlabel.
480 */
481 if (is_default)
482 continue;
483 if (kr->flags & F_DYNAMIC0x0040)
484 continue;
485 if (kr->flags & F_STATIC0x0020)
486 return (r->type & REDIST_NO0x20 ? 0 : 1);
487 break;
488 case REDIST_CONNECTED0x01:
489 if (is_default)
490 continue;
491 if (kr->flags & F_DYNAMIC0x0040)
492 continue;
493 if (kr->flags & F_CONNECTED0x0008)
494 return (r->type & REDIST_NO0x20 ? 0 : 1);
495 break;
496 case REDIST_ADDR0x08:
497 if (kr->flags & F_DYNAMIC0x0040)
498 continue;
499
500 if (r->addr.s_addr == INADDR_ANY((u_int32_t)(0x00000000)) &&
501 r->mask.s_addr == INADDR_ANY((u_int32_t)(0x00000000))) {
502 if (is_default)
503 return (r->type & REDIST_NO0x20? 0 : 1);
504 else
505 return (0);
506 }
507
508 if ((kr->prefix.s_addr & r->mask.s_addr) ==
509 (r->addr.s_addr & r->mask.s_addr) &&
510 (kr->netmask.s_addr & r->mask.s_addr) ==
511 r->mask.s_addr)
512 return (r->type & REDIST_NO0x20? 0 : 1);
513 break;
514 case REDIST_DEFAULT0x10:
515 if (is_default)
516 return (r->type & REDIST_NO0x20? 0 : 1);
517 break;
518 }
519 }
520
521 return (0);
522}
523
524void
525imsg_event_add(struct imsgev *iev)
526{
527 if (iev->handler == NULL((void *)0)) {
528 imsg_flush(&iev->ibuf);
529 return;
530 }
531
532 iev->events = EV_READ0x02;
533 if (iev->ibuf.w.queued)
534 iev->events |= EV_WRITE0x04;
535
536 event_del(&iev->ev);
537 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
538 event_add(&iev->ev, NULL((void *)0));
539}
540
541int
542imsg_compose_event(struct imsgev *iev, u_int16_t type,
543 u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
544{
545 int ret;
546
547 if ((ret = imsg_compose(&iev->ibuf, type, peerid,
548 pid, fd, data, datalen)) != -1)
549 imsg_event_add(iev);
550 return (ret);
551}