Bug Summary

File:src/usr.sbin/dvmrpd/dvmrpd.c
Warning:line 207, column 27
Access to field 'mroute_socket' 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 dvmrpd.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/dvmrpd.c
1/* $OpenBSD: dvmrpd.c,v 1.27 2021/01/19 12:29:46 claudio Exp $ */
2
3/*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2005, 2006 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/queue.h>
24#include <sys/time.h>
25#include <sys/stat.h>
26#include <sys/sysctl.h>
27#include <sys/wait.h>
28
29#include <netinet/in.h>
30#include <arpa/inet.h>
31
32#include <event.h>
33#include <err.h>
34#include <errno(*__errno()).h>
35#include <pwd.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <signal.h>
40#include <unistd.h>
41#include <util.h>
42
43#include "igmp.h"
44#include "dvmrpd.h"
45#include "dvmrp.h"
46#include "dvmrpe.h"
47#include "control.h"
48#include "log.h"
49#include "rde.h"
50
51void main_sig_handler(int, short, void *);
52__dead__attribute__((__noreturn__)) void usage(void);
53__dead__attribute__((__noreturn__)) void dvmrpd_shutdown(void);
54
55void main_dispatch_dvmrpe(int, short, void *);
56void main_dispatch_rde(int, short, void *);
57void main_imsg_compose_dvmrpe(int, pid_t, void *, u_int16_t);
58void main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
59
60int pipe_parent2dvmrpe[2];
61int pipe_parent2rde[2];
62int pipe_dvmrpe2rde[2];
63
64struct dvmrpd_conf *conf = NULL((void *)0);
65static struct imsgev *iev_dvmrpe;
66static struct imsgev *iev_rde;
67
68pid_t dvmrpe_pid;
69pid_t rde_pid;
70
71void
72main_sig_handler(int sig, short event, void *arg)
73{
74 /* signal handler rules don't apply, libevent decouples for us */
75 switch (sig) {
76 case SIGTERM15:
77 case SIGINT2:
78 dvmrpd_shutdown();
79 /* NOTREACHED */
80 case SIGHUP1:
81 /* reconfigure */
82 /* ... */
83 break;
84 default:
85 fatalx("unexpected signal");
86 /* NOTREACHED */
87 }
88}
89
90__dead__attribute__((__noreturn__)) void
91usage(void)
92{
93 extern char *__progname;
94
95 fprintf(stderr(&__sF[2]), "usage: %s [-dnv] [-f file]\n", __progname);
96 exit(1);
97}
98
99int
100main(int argc, char *argv[])
101{
102 struct event ev_sigint, ev_sigterm, ev_sighup;
103 char *conffile;
104 int ch, opts = 0;
105 int debug = 0;
106 int ipmforwarding;
107 int mib[4];
108 size_t len;
109
110 conffile = CONF_FILE"/etc/dvmrpd.conf";
111 log_procname = "parent";
112
113 log_init(1); /* log to stderr until daemonized */
114 log_verbose(1);
115
116 while ((ch = getopt(argc, argv, "df:nv")) != -1) {
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 139
117 switch (ch) {
118 case 'd':
119 debug = 1;
120 break;
121 case 'f':
122 conffile = optarg;
123 break;
124 case 'n':
125 opts |= DVMRPD_OPT_NOACTION0x00000004;
126 break;
127 case 'v':
128 if (opts & DVMRPD_OPT_VERBOSE0x00000001)
129 opts |= DVMRPD_OPT_VERBOSE20x00000002;
130 opts |= DVMRPD_OPT_VERBOSE0x00000001;
131 log_verbose(1);
132 break;
133 default:
134 usage();
135 /* NOTREACHED */
136 }
137 }
138
139 argc -= optind;
140 argv += optind;
141 if (argc > 0)
3
Assuming 'argc' is <= 0
4
Taking false branch
142 usage();
143
144 log_init(debug);
145 log_verbose(opts & DVMRPD_OPT_VERBOSE0x00000001);
146
147 /* multicast IP forwarding must be enabled */
148 mib[0] = CTL_NET4;
149 mib[1] = PF_INET2;
150 mib[2] = IPPROTO_IP0;
151 mib[3] = IPCTL_MFORWARDING31;
152 len = sizeof(ipmforwarding);
153 if (sysctl(mib, 4, &ipmforwarding, &len, NULL((void *)0), 0) == -1)
5
Assuming the condition is false
6
Taking false branch
154 err(1, "sysctl");
155
156 if (!ipmforwarding)
7
Assuming 'ipmforwarding' is not equal to 0
8
Taking false branch
157 errx(1, "multicast IP forwarding not enabled");
158
159 /* fetch interfaces early */
160 kif_init();
161
162 /* parse config file */
163 if ((conf = parse_config(conffile, opts)) == NULL((void *)0) )
9
Assuming the condition is false
10
Taking false branch
164 exit(1);
165
166 if (conf->opts & DVMRPD_OPT_NOACTION0x00000004) {
11
Assuming the condition is false
12
Taking false branch
167 if (conf->opts & DVMRPD_OPT_VERBOSE0x00000001)
168 print_config(conf);
169 else
170 fprintf(stderr(&__sF[2]), "configuration OK\n");
171 exit(0);
172 }
173
174 /* check for root privileges */
175 if (geteuid())
13
Assuming the condition is false
14
Taking false branch
176 errx(1, "need root privileges");
177
178 /* check for dvmrpd user */
179 if (getpwnam(DVMRPD_USER"_dvmrpd") == NULL((void *)0))
15
Assuming the condition is false
16
Taking false branch
180 errx(1, "unknown user %s", DVMRPD_USER"_dvmrpd");
181
182 /* start logging */
183 log_init(1);
17
Null pointer value stored to 'conf'
184
185 if (!debug
17.1
'debug' is 0
)
18
Taking true branch
186 daemon(1, 0);
187
188 log_info("startup");
189
190 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
19
Assuming the condition is false
20
Taking false branch
191 PF_UNSPEC0, pipe_parent2dvmrpe) == -1)
192 fatal("socketpair");
193 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
21
Assuming the condition is false
22
Taking false branch
194 PF_UNSPEC0, pipe_parent2rde) == -1)
195 fatal("socketpair");
196 if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
23
Assuming the condition is false
24
Taking false branch
197 PF_UNSPEC0, pipe_dvmrpe2rde) == -1)
198 fatal("socketpair");
199
200 /* start children */
201 rde_pid = rde(conf, pipe_parent2rde, pipe_dvmrpe2rde,
202 pipe_parent2dvmrpe);
203 dvmrpe_pid = dvmrpe(conf, pipe_parent2dvmrpe, pipe_dvmrpe2rde,
204 pipe_parent2rde);
205
206 /* create the raw ip socket */
207 if ((conf->mroute_socket = socket(AF_INET2,
25
Access to field 'mroute_socket' results in a dereference of a null pointer (loaded from variable 'conf')
208 SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000,
209 IPPROTO_IGMP2)) == -1)
210 fatal("error creating raw socket");
211
212 if_set_recvbuf(conf->mroute_socket);
213
214 if (mrt_init(conf->mroute_socket))
215 fatal("multicast routing not enabled in kernel");
216
217 event_init();
218
219 /* setup signal handler */
220 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void
*)0))
;
221 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, (
(void *)0))
;
222 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void
*)0))
;
223 signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0));
224 signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0));
225 signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0));
226 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
227
228 /* setup pipes to children */
229 close(pipe_parent2dvmrpe[1]);
230 close(pipe_parent2rde[1]);
231 close(pipe_dvmrpe2rde[0]);
232 close(pipe_dvmrpe2rde[1]);
233
234 if ((iev_dvmrpe = malloc(sizeof(struct imsgev))) == NULL((void *)0) ||
235 (iev_rde = malloc(sizeof(struct imsgev))) == NULL((void *)0))
236 fatal(NULL((void *)0));
237 imsg_init(&iev_dvmrpe->ibuf, pipe_parent2dvmrpe[0]);
238 imsg_init(&iev_rde->ibuf, pipe_parent2rde[0]);
239 iev_dvmrpe->handler = main_dispatch_dvmrpe;
240 iev_rde->handler = main_dispatch_rde;
241
242 /* setup event handler */
243 iev_dvmrpe->events = EV_READ0x02;
244 event_set(&iev_dvmrpe->ev, iev_dvmrpe->ibuf.fd, iev_dvmrpe->events,
245 iev_dvmrpe->handler, iev_dvmrpe);
246 event_add(&iev_dvmrpe->ev, NULL((void *)0));
247
248 iev_rde->events = EV_READ0x02;
249 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
250 iev_rde->handler, iev_rde);
251 event_add(&iev_rde->ev, NULL((void *)0));
252
253 if (kmr_init(!(conf->flags & DVMRPD_FLAG_NO_FIB_UPDATE0x0001)) == -1)
254 dvmrpd_shutdown();
255 if (kr_init() == -1)
256 dvmrpd_shutdown();
257
258 event_set(&conf->ev, conf->mroute_socket, EV_READ0x02|EV_PERSIST0x10,
259 kmr_recv_msg, conf);
260 event_add(&conf->ev, NULL((void *)0));
261
262 event_dispatch();
263
264 dvmrpd_shutdown();
265 /* NOTREACHED */
266 return (0);
267}
268
269__dead__attribute__((__noreturn__)) void
270dvmrpd_shutdown(void)
271{
272 struct iface *iface;
273 pid_t pid;
274 int status;
275
276 /* close pipes */
277 msgbuf_clear(&iev_dvmrpe->ibuf.w);
278 close(iev_dvmrpe->ibuf.fd);
279 msgbuf_clear(&iev_rde->ibuf.w);
280 close(iev_rde->ibuf.fd);
281
282 control_cleanup();
283 kmr_shutdown();
284 kr_shutdown();
285 LIST_FOREACH(iface, &conf->iface_list, entry)for((iface) = ((&conf->iface_list)->lh_first); (iface
)!= ((void *)0); (iface) = ((iface)->entry.le_next))
{
286 if_del(iface);
287 }
288 mrt_done(conf->mroute_socket);
289
290 log_debug("waiting for children to terminate");
291 do {
292 pid = wait(&status);
293 if (pid == -1) {
294 if (errno(*__errno()) != EINTR4 && errno(*__errno()) != ECHILD10)
295 fatal("wait");
296 } else if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
297 log_warnx("%s terminated; signal %d",
298 (pid == rde_pid) ? "route decision engine" :
299 "dvmrp engine", WTERMSIG(status)(((status) & 0177)));
300 } while (pid != -1 || (pid == -1 && errno(*__errno()) == EINTR4));
301
302 free(iev_dvmrpe);
303 free(iev_rde);
304
305 log_info("terminating");
306 exit(0);
307}
308
309/* imsg handling */
310void
311main_dispatch_dvmrpe(int fd, short event, void *bula)
312{
313 struct imsgev *iev = bula;
314 struct imsgbuf *ibuf = &iev->ibuf;
315 struct imsg imsg;
316 ssize_t n;
317 int shut = 0, verbose;
318
319 if (event & EV_READ0x02) {
320 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
321 fatal("imsg_read error");
322 if (n == 0) /* connection closed */
323 shut = 1;
324 }
325 if (event & EV_WRITE0x04) {
326 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
327 fatal("msgbuf_write");
328 if (n == 0) /* connection closed */
329 shut = 1;
330 }
331
332 for (;;) {
333 if ((n = imsg_get(ibuf, &imsg)) == -1)
334 fatal("imsg_get");
335
336 if (n == 0)
337 break;
338
339 switch (imsg.hdr.type) {
340 case IMSG_CTL_RELOAD:
341 log_debug("main_dispatch_dvmrpe: IMSG_CTL_RELOAD");
342 /* reconfig */
343 break;
344 case IMSG_CTL_MFC_COUPLE:
345 kmr_mfc_couple();
346 break;
347 case IMSG_CTL_MFC_DECOUPLE:
348 kmr_mfc_decouple();
349 break;
350 case IMSG_CTL_LOG_VERBOSE:
351 /* already checked by dvmrpe */
352 memcpy(&verbose, imsg.data, sizeof(verbose));
353 log_verbose(verbose);
354 break;
355 default:
356 log_debug("main_dispatch_dvmrpe: error handling "
357 "imsg %d", imsg.hdr.type);
358 break;
359 }
360 imsg_free(&imsg);
361 }
362 if (!shut)
363 imsg_event_add(iev);
364 else {
365 /* this pipe is dead, so remove the event handler */
366 event_del(&iev->ev);
367 event_loopexit(NULL((void *)0));
368 }
369}
370
371void
372main_dispatch_rde(int fd, short event, void *bula)
373{
374 struct mfc mfc;
375 struct imsgev *iev = bula;
376 struct imsgbuf *ibuf = &iev->ibuf;
377 struct imsg imsg;
378 ssize_t n;
379 int shut = 0;
380
381 if (event & EV_READ0x02) {
382 if ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) != EAGAIN35)
383 fatal("imsg_read error");
384 if (n == 0) /* connection closed */
385 shut = 1;
386 }
387 if (event & EV_WRITE0x04) {
388 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno(*__errno()) != EAGAIN35)
389 fatal("msgbuf_write");
390 if (n == 0) /* connection closed */
391 shut = 1;
392 }
393
394 for (;;) {
395 if ((n = imsg_get(ibuf, &imsg)) == -1)
396 fatal("imsg_get");
397
398 if (n == 0)
399 break;
400
401 switch (imsg.hdr.type) {
402 case IMSG_MFC_ADD:
403 if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(mfc))
404 fatalx("invalid size of RDE request");
405 memcpy(&mfc, imsg.data, sizeof(mfc));
406
407 /* add to MFC */
408 mrt_add_mfc(conf->mroute_socket, &mfc);
409 break;
410 case IMSG_MFC_DEL:
411 if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != sizeof(mfc))
412 fatalx("invalid size of RDE request");
413 memcpy(&mfc, imsg.data, sizeof(mfc));
414
415 /* remove from MFC */
416 mrt_del_mfc(conf->mroute_socket, &mfc);
417 break;
418 default:
419 log_debug("main_dispatch_rde: error handling imsg %d",
420 imsg.hdr.type);
421 break;
422 }
423 imsg_free(&imsg);
424 }
425 if (!shut)
426 imsg_event_add(iev);
427 else {
428 /* this pipe is dead, so remove the event handler */
429 event_del(&iev->ev);
430 event_loopexit(NULL((void *)0));
431 }
432}
433
434void
435main_imsg_compose_dvmrpe(int type, pid_t pid, void *data, u_int16_t datalen)
436{
437 imsg_compose_event(iev_dvmrpe, type, 0, pid, -1, data, datalen);
438}
439
440void
441main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
442{
443 imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
444}
445
446void
447imsg_event_add(struct imsgev *iev)
448{
449 iev->events = EV_READ0x02;
450 if (iev->ibuf.w.queued)
451 iev->events |= EV_WRITE0x04;
452
453 event_del(&iev->ev);
454 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
455 event_add(&iev->ev, NULL((void *)0));
456}
457
458int
459imsg_compose_event(struct imsgev *iev, u_int16_t type,
460 u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
461{
462 int ret;
463
464 if ((ret = imsg_compose(&iev->ibuf, type, peerid,
465 pid, fd, data, datalen)) != -1)
466 imsg_event_add(iev);
467 return (ret);
468}