Bug Summary

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