Bug Summary

File:src/usr.bin/netstat/main.c
Warning:line 392, column 7
Access to field 'pr_proto' results in a dereference of a null pointer (loaded from variable 'tp')

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 main.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.bin/netstat/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/netstat/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.bin/netstat/main.c
1/* $OpenBSD: main.c,v 1.121 2021/01/26 18:22:45 deraadt Exp $ */
2/* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */
3
4/*
5 * Copyright (c) 1983, 1988, 1993
6 * Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/protosw.h>
35#include <sys/socket.h>
36#include <sys/sysctl.h>
37
38#include <net/route.h>
39#include <netinet/in.h>
40
41#include <ctype.h>
42#include <err.h>
43#include <errno(*__errno()).h>
44#include <fcntl.h>
45#include <kvm.h>
46#include <limits.h>
47#include <netdb.h>
48#include <nlist.h>
49#include <paths.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54#include "netstat.h"
55
56struct nlist nl[] = {
57#define N_AFMAP0 0
58 { "_afmap"},
59#define N_AF2IDX1 1
60 { "_af2idx" },
61#define N_AF2IDXMAX2 2
62 { "_af2idx_max" },
63
64 { "" }
65};
66
67struct protox {
68 void (*pr_stats)(char *); /* statistics printing routine */
69 char *pr_name; /* well-known name */
70 int pr_proto; /* protocol number */
71} protox[] = {
72 { ip_stats, "ip", IPPROTO_IPV44 },
73 { icmp_stats, "icmp", 0 },
74 { igmp_stats, "igmp", 0 },
75 { ipip_stats, "ipencap", 0 },
76 { tcp_stats, "tcp", IPPROTO_TCP6 },
77 { udp_stats, "udp", IPPROTO_UDP17 },
78 { ipsec_stats, "ipsec", 0 },
79 { esp_stats, "esp", 0 },
80 { ah_stats, "ah", 0 },
81 { etherip_stats,"etherip", 0 },
82 { ipcomp_stats, "ipcomp", 0 },
83 { carp_stats, "carp", 0 },
84 { pfsync_stats, "pfsync", 0 },
85 { div_stats, "divert", IPPROTO_DIVERT258 },
86 { pflow_stats, "pflow", 0 },
87 { NULL((void *)0), NULL((void *)0), 0 }
88};
89
90struct protox ip6protox[] = {
91 { ip6_stats, "ip6", IPPROTO_IPV641 },
92 { div6_stats, "divert6", IPPROTO_DIVERT258 },
93 { icmp6_stats, "icmp6", 0 },
94 { rip6_stats, "rip6", 0 },
95 { NULL((void *)0), NULL((void *)0), 0 }
96};
97
98struct protox *protoprotox[] = {
99 protox, ip6protox, NULL((void *)0)
100};
101
102static void usage(void);
103static struct protox *name2protox(char *);
104static struct protox *knownname(char *);
105void gettable(u_int);
106
107kvm_t *kvmd;
108
109int Aflag; /* show addresses of protocol control block */
110int aflag; /* show all sockets (including servers) */
111int Bflag; /* show TCP send and receive buffer sizes */
112int bflag; /* show bytes instead of packets */
113int dflag; /* show i/f dropped packets */
114int Fflag; /* show routes whose gateways are in specified AF */
115int gflag; /* show group (multicast) routing or stats */
116int hflag; /* print human numbers */
117int iflag; /* show interfaces */
118int lflag; /* show only listening sockets (only servers), */
119 /* with -g, show routing table with use and ref */
120int mflag; /* show memory stats */
121int nflag; /* show addresses numerically */
122int pflag; /* show given protocol */
123int Pflag; /* show given PCB */
124int qflag; /* only display non-zero values for output */
125int rflag; /* show routing tables (or routing stats) */
126int Rflag; /* show rdomain and rtable summary */
127int sflag; /* show protocol statistics */
128int tflag; /* show i/f watchdog timers */
129int vflag; /* be verbose */
130int Wflag; /* show net80211 protocol statistics */
131
132int interval; /* repeat interval for i/f stats */
133
134char *interface; /* desired i/f for stats, or NULL for all i/fs */
135
136int af; /* address family */
137
138int
139main(int argc, char *argv[])
140{
141 extern char *optarg;
142 extern int optind;
143 const char *errstr;
144 struct protox *tp = NULL((void *)0); /* for printing cblocks & stats */
1
'tp' initialized to a null pointer value
145 int ch;
146 char *nlistf = NULL((void *)0), *memf = NULL((void *)0), *ep;
147 char buf[_POSIX2_LINE_MAX2048];
148 u_long pcbaddr = 0;
149 u_int tableid;
150 int Tflag = 0;
151 int repeatcount = 0;
152 int proto = 0;
153 int need_nlist, kvm_flags = O_RDONLY0x0000;
154
155 af = AF_UNSPEC0;
156 tableid = getrtable();
157
158 while ((ch = getopt(argc, argv,
2
Assuming the condition is false
3
Loop condition is false. Execution continues on line 295
159 "AaBbc:deFf:ghI:iLlM:mN:np:P:qRrsT:tuvW:w:")) != -1)
160 switch (ch) {
161 case 'A':
162 Aflag = 1;
163 break;
164 case 'a':
165 aflag = 1;
166 break;
167 case 'B':
168 Bflag = 1;
169 break;
170 case 'b':
171 bflag = 1;
172 break;
173 case 'c':
174 repeatcount = strtonum(optarg, 1, INT_MAX2147483647, &errstr);
175 if (errstr)
176 errx(1, "count is %s", errstr);
177 break;
178 case 'd':
179 dflag = IF_SHOW_DROP2;
180 break;
181 case 'e':
182 dflag = IF_SHOW_ERRS1;
183 break;
184 case 'F':
185 Fflag = 1;
186 break;
187 case 'f':
188 if (strcmp(optarg, "inet") == 0)
189 af = AF_INET2;
190 else if (strcmp(optarg, "inet6") == 0)
191 af = AF_INET624;
192 else if (strcmp(optarg, "local") == 0)
193 af = AF_LOCAL1;
194 else if (strcmp(optarg, "unix") == 0)
195 af = AF_UNIX1;
196 else if (strcmp(optarg, "mpls") == 0)
197 af = AF_MPLS33;
198 else {
199 (void)fprintf(stderr(&__sF[2]),
200 "%s: %s: unknown address family\n",
201 __progname, optarg);
202 exit(1);
203 }
204 break;
205 case 'g':
206 gflag = 1;
207 break;
208 case 'h':
209 hflag = 1;
210 break;
211 case 'I':
212 iflag = 1;
213 interface = optarg;
214 break;
215 case 'i':
216 iflag = 1;
217 break;
218 case 'l':
219 lflag = 1;
220 break;
221 case 'M':
222 memf = optarg;
223 break;
224 case 'm':
225 mflag = 1;
226 break;
227 case 'N':
228 nlistf = optarg;
229 break;
230 case 'n':
231 nflag = 1;
232 break;
233 case 'p':
234 if ((tp = name2protox(optarg)) == NULL((void *)0)) {
235 (void)fprintf(stderr(&__sF[2]),
236 "%s: %s: unknown protocol\n",
237 __progname, optarg);
238 exit(1);
239 }
240 pflag = 1;
241 break;
242 case 'P':
243 errno(*__errno()) = 0;
244 pcbaddr = strtoul(optarg, &ep, 16);
245 if (optarg[0] == '\0' || *ep != '\0' ||
246 errno(*__errno()) == ERANGE34) {
247 (void)fprintf(stderr(&__sF[2]),
248 "%s: %s: invalid PCB address\n",
249 __progname, optarg);
250 exit(1);
251 }
252 Pflag = 1;
253 break;
254 case 'q':
255 qflag = 1;
256 break;
257 case 'R':
258 Rflag = 1;
259 break;
260 case 'r':
261 rflag = 1;
262 break;
263 case 's':
264 ++sflag;
265 break;
266 case 'T':
267 tableid = strtonum(optarg, 0, RT_TABLEID_MAX255, &errstr);
268 if (errstr)
269 errx(1, "invalid table id: %s", errstr);
270 Tflag = 1;
271 break;
272 case 't':
273 tflag = 1;
274 break;
275 case 'u':
276 af = AF_UNIX1;
277 break;
278 case 'v':
279 vflag = 1;
280 break;
281 case 'W':
282 Wflag = 1;
283 interface = optarg;
284 break;
285 case 'w':
286 interval = strtonum(optarg, 1, INT_MAX2147483647, &errstr);
287 if (errstr)
288 errx(1, "interval is %s", errstr);
289 iflag = 1;
290 break;
291 case '?':
292 default:
293 usage();
294 }
295 argv += optind;
296 argc -= optind;
297
298 if (argc) {
4
Assuming 'argc' is 0
5
Taking false branch
299 interval = strtonum(*argv, 1, INT_MAX2147483647, &errstr);
300 if (errstr)
301 errx(1, "interval is %s", errstr);
302 ++argv;
303 --argc;
304 iflag = 1;
305 }
306 if (argc
5.1
'argc' is 0
)
6
Taking false branch
307 usage();
308
309 /*
310 * Show per-interface statistics which don't need access to
311 * kernel memory (they're using IOCTLs)
312 */
313 if (Wflag) {
7
Assuming 'Wflag' is 0
8
Taking false branch
314 if (interface == NULL((void *)0))
315 usage();
316 net80211_ifstats(interface);
317 exit(0);
318 }
319
320 if (mflag) {
9
Assuming 'mflag' is 0
10
Taking false branch
321 mbpr();
322 exit(0);
323 }
324 if (iflag) {
11
Assuming 'iflag' is 0
12
Taking false branch
325 intpr(interval, repeatcount);
326 exit(0);
327 }
328 if (sflag) {
13
Assuming 'sflag' is 0
14
Taking false branch
329 if (rflag) {
330 rt_stats();
331 } else if (gflag) {
332 if (af == AF_INET2 || af == AF_UNSPEC0)
333 mrt_stats();
334 if (af == AF_INET624 || af == AF_UNSPEC0)
335 mrt6_stats();
336 } else if (pflag && tp->pr_name) {
337 (*tp->pr_stats)(tp->pr_name);
338 } else {
339 if (af == AF_INET2 || af == AF_UNSPEC0)
340 for (tp = protox; tp->pr_name; tp++)
341 (*tp->pr_stats)(tp->pr_name);
342 if (af == AF_INET624 || af == AF_UNSPEC0)
343 for (tp = ip6protox; tp->pr_name; tp++)
344 (*tp->pr_stats)(tp->pr_name);
345 }
346 exit(0);
347 }
348 if (gflag) {
15
Assuming 'gflag' is 0
16
Taking false branch
349 if (af == AF_INET2 || af == AF_UNSPEC0)
350 mroutepr();
351 if (af == AF_INET624 || af == AF_UNSPEC0)
352 mroute6pr();
353 exit(0);
354 }
355
356 if (Rflag) {
17
Assuming 'Rflag' is 0
18
Taking false branch
357 rdomainpr();
358 exit(0);
359 }
360
361 /*
362 * The remaining code may need kvm so lets try to open it.
363 * -r and -P are the only bits left that actually can use this.
364 */
365 need_nlist = (nlistf
18.1
'nlistf' is equal to NULL
!= NULL((void *)0)) || (memf
18.2
'memf' is equal to NULL
!= NULL((void *)0)) || (Aflag && rflag);
19
Assuming 'Aflag' is 0
366 if (!need_nlist
19.1
'need_nlist' is 0
&& !Pflag)
20
Assuming 'Pflag' is not equal to 0
21
Taking false branch
367 kvm_flags |= KVM_NO_FILES0x80000000;
368
369 if ((kvmd = kvm_openfiles(nlistf, memf, NULL((void *)0), kvm_flags, buf)) == NULL((void *)0))
22
Assuming the condition is false
23
Taking false branch
370 errx(1, "kvm_openfiles: %s", buf);
371
372 if (need_nlist
23.1
'need_nlist' is 0
&& (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0)) {
373 if (nlistf)
374 errx(1, "%s: no namelist", nlistf);
375 else
376 errx(1, "no namelist");
377 }
378
379 if (!need_nlist
23.2
'need_nlist' is 0
&& Tflag
23.3
'Tflag' is 0
)
24
Taking false branch
380 gettable(tableid);
381
382 if (rflag) {
25
Assuming 'rflag' is 0
26
Taking false branch
383 if (Aflag || nlistf != NULL((void *)0) || memf != NULL((void *)0))
384 routepr(nl[N_AFMAP0].n_value, nl[N_AF2IDX1].n_value,
385 nl[N_AF2IDXMAX2].n_value, tableid);
386 else
387 p_rttables(af, tableid);
388 exit(0);
389 }
390
391 if (pflag) {
27
Assuming 'pflag' is not equal to 0
28
Taking true branch
392 if (tp->pr_proto == 0)
29
Access to field 'pr_proto' results in a dereference of a null pointer (loaded from variable 'tp')
393 errx(1, "no protocol handler for protocol %s",
394 tp->pr_name);
395 else
396 proto = tp->pr_proto;
397 }
398
399 protopr(kvmd, pcbaddr, tableid, proto);
400 exit(0);
401}
402
403/*
404 * Read kernel memory, return 0 on success.
405 */
406int
407kread(u_long addr, void *buf, int size)
408{
409
410 if (kvm_read(kvmd, addr, buf, size) != size) {
411 (void)fprintf(stderr(&__sF[2]), "%s: %s\n", __progname,
412 kvm_geterr(kvmd));
413 return (-1);
414 }
415 return (0);
416}
417
418char *
419plural(u_int64_t n)
420{
421 return (n != 1 ? "s" : "");
422}
423
424char *
425plurales(u_int64_t n)
426{
427 return (n != 1 ? "es" : "");
428}
429
430char *
431pluralys(u_int64_t n)
432{
433 return (n != 1 ? "ies" : "y");
434}
435
436/*
437 * Find the protox for the given "well-known" name.
438 */
439static struct protox *
440knownname(char *name)
441{
442 struct protox **tpp, *tp;
443
444 for (tpp = protoprotox; *tpp; tpp++)
445 for (tp = *tpp; tp->pr_name; tp++)
446 if (strcmp(tp->pr_name, name) == 0)
447 return (tp);
448 return (NULL((void *)0));
449}
450
451/*
452 * Find the protox corresponding to name.
453 */
454static struct protox *
455name2protox(char *name)
456{
457 struct protox *tp;
458 char **alias; /* alias from p->aliases */
459 struct protoent *p;
460
461 /*
462 * Try to find the name in the list of "well-known" names. If that
463 * fails, check if name is an alias for an Internet protocol.
464 */
465 if ((tp = knownname(name)))
466 return (tp);
467
468 setprotoent(1); /* make protocol lookup cheaper */
469 while ((p = getprotoent())) {
470 /* assert: name not same as p->name */
471 for (alias = p->p_aliases; *alias; alias++)
472 if (strcmp(name, *alias) == 0) {
473 endprotoent();
474 return (knownname(p->p_name));
475 }
476 }
477 endprotoent();
478 return (NULL((void *)0));
479}
480
481static void
482usage(void)
483{
484 (void)fprintf(stderr(&__sF[2]),
485 "usage: netstat [-AaBln] [-M core] [-N system] [-p protocol] [-T rtable]\n"
486 " netstat -W interface\n"
487 " netstat -m\n"
488 " netstat -I interface | -i [-bdehnqt]\n"
489 " netstat -w wait [-bdehnqt] [-c count] [-I interface]\n"
490 " netstat -s [-gru] [-f address_family] [-p protocol]\n"
491 " netstat -g [-lnu] [-f address_family]\n"
492 " netstat -R\n"
493 " netstat -r [-AFu] [-f address_family] [-M core] [-N system] [-p protocol]\n"
494 " [-T rtable]\n"
495 " netstat -P pcbaddr [-v] [-M core] [-N system]\n");
496 exit(1);
497}
498
499void
500gettable(u_int tableid)
501{
502 struct rt_tableinfo info;
503 int mib[6];
504 size_t len;
505
506 mib[0] = CTL_NET4;
507 mib[1] = PF_ROUTE17;
508 mib[2] = 0;
509 mib[3] = 0;
510 mib[4] = NET_RT_TABLE5;
511 mib[5] = tableid;
512
513 len = sizeof(info);
514 if (sysctl(mib, 6, &info, &len, NULL((void *)0), 0) == -1)
515 err(1, "routing table %d", tableid);
516}