clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name radish.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/npppd/npppd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/npppd/npppd/../common -I /usr/src/usr.sbin/npppd/npppd -I /usr/src/usr.sbin/npppd/npppd/../pptp -I /usr/src/usr.sbin/npppd/npppd/../l2tp -I /usr/src/usr.sbin/npppd/npppd/../pppoe -D USE_NPPPD_PPTP -D USE_NPPPD_L2TP -D USE_NPPPD_PPPOE -D __COPYRIGHT(x)= -D __RCSID(x)= -D NPPPD_MAX_IFACE=8 -D NPPPD_MAX_POOL=8 -D USE_NPPPD_MPPE -D USE_NPPPD_PIPEX -D USE_NPPPD_RADIUS -D USE_SA_COOKIE -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/npppd/npppd/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/npppd/npppd/../common/radish.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | #include <sys/types.h> |
43 | #include <sys/socket.h> |
44 | #include <string.h> |
45 | #include <stdlib.h> |
46 | #include <errno.h> |
47 | |
48 | #include "radish.h" |
49 | |
50 | #include <netinet/in.h> |
51 | #include <string.h> |
52 | #include <strings.h> |
53 | #include <stdlib.h> |
54 | #include <stdio.h> |
55 | |
56 | #define FATAL(x) \ |
57 | do { \ |
58 | fputs(x, stderr); \ |
59 | abort(); \ |
60 | } while (0/* CONSTCOND */) |
61 | |
62 | static u_char rd_bmask [] = { |
63 | 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, |
64 | }; |
65 | |
66 | static u_char rd_btest [] = { |
67 | 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, |
68 | }; |
69 | |
70 | u_char rd_deleted_km[1024]; |
71 | |
72 | |
73 | |
74 | |
75 | |
76 | int |
77 | rd_inithead(void **headp, int family, int slen, int off, int alen, |
78 | int (*match)(void *, void *)) |
79 | { |
80 | struct radish_head *head; |
81 | struct radish *new; |
82 | struct sockaddr *masks; |
83 | u_char *m; |
84 | int num = alen * 8 + 1, i, j, q, r; |
85 | int len = sizeof(*head) + sizeof(*new) + slen * num; |
86 | |
87 | if (*headp) return (1); |
88 | R_Malloc(head, struct radish_head *, len); |
89 | if (head == NULL) |
90 | return 0; |
91 | Bzero(head, len); |
92 | new = (struct radish *)(head + 1); |
93 | masks = (struct sockaddr *)(new +1); |
94 | *headp = head; |
95 | |
96 | |
97 | |
98 | |
99 | m = (u_char *)masks; |
100 | for (i = 0; i < num; i++, m += slen) { |
101 | *m = slen; |
102 | *(m + 1) = family; |
103 | q = i >> 3; |
104 | r = i & 7; |
105 | for(j = 0; j < q; j++) |
106 | *(m + off + j) = 0xff; |
107 | *(m + off + j) = rd_bmask[r]; |
108 | } |
109 | |
110 | head->rdh_slen = slen; |
111 | head->rdh_offset = off; |
112 | head->rdh_alen = alen; |
113 | head->rdh_masks = masks; |
114 | head->rdh_match = match; |
115 | head->rdh_top = new; |
116 | |
117 | new->rd_route = masks; |
118 | new->rd_mask = masks; |
119 | new->rd_btest = rd_btest[0]; |
120 | |
121 | |
122 | return(1); |
123 | } |
124 | |
125 | struct sockaddr * |
126 | rd_mask(struct sockaddr *m_arg, struct radish_head *head, int *maskp) |
127 | { |
128 | u_char *mp, *masks = (u_char *)head->rdh_masks; |
129 | int off = head->rdh_offset; |
130 | int slen = head->rdh_slen; |
131 | int alen = head->rdh_alen; |
132 | int i = 0, masklen = 0; |
133 | |
134 | if (m_arg == NULL) { |
135 | masklen = alen * 8; |
136 | *maskp = masklen; |
137 | return((struct sockaddr *)(masks + slen * masklen)); |
138 | } |
139 | mp = (u_char *)m_arg + off; |
140 | while ((i < alen) && (mp[i] == 0xff)) { |
141 | masklen += 8; |
142 | i++; |
143 | } |
144 | if (i < alen) |
145 | switch (mp[i]) { |
146 | case 0xfe: masklen += 7; break; |
147 | case 0xfc: masklen += 6; break; |
148 | case 0xf8: masklen += 5; break; |
149 | case 0xf0: masklen += 4; break; |
150 | case 0xe0: masklen += 3; break; |
151 | case 0xc0: masklen += 2; break; |
152 | case 0x80: masklen += 1; break; |
153 | case 0x00: break; |
154 | } |
155 | *maskp = masklen; |
156 | return((struct sockaddr *)(masks + slen * masklen)); |
157 | } |
158 | |
159 | int |
160 | rd_insert(struct sockaddr *d_arg, struct sockaddr *m_arg, |
161 | struct radish_head *head, void *rt) |
162 | { |
163 | struct radish *cur = head->rdh_top, *parent, *new; |
164 | int off = head->rdh_offset; |
165 | int slen = head->rdh_slen; |
166 | int alen = head->rdh_alen; |
167 | int i, lim, q, r, masklen; |
168 | u_char *dp, *np, *rp; |
169 | struct sockaddr *mask; |
170 | |
171 | mask = rd_mask(m_arg, head, &masklen); |
172 | q = masklen >> 3; |
173 | r = masklen & 7; |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | R_Malloc(new, struct radish *, sizeof(*new) + slen); |
182 | if (new == NULL) |
183 | return ENOBUFS; |
184 | Bzero(new, sizeof(*new) + slen); |
185 | new->rd_route = (struct sockaddr *)(new + 1); |
186 | new->rd_mask = mask; |
187 | new->rd_masklen = masklen; |
188 | new->rd_masklim = q; |
189 | new->rd_bmask = rd_bmask[r]; |
190 | new->rd_btest = rd_btest[r]; |
191 | new->rd_rtent = rt; |
192 | |
193 | |
194 | np = (u_char *)new->rd_route; |
195 | dp = (u_char *)d_arg; |
196 | *np = *dp; |
197 | np[1] = dp[1]; |
198 | dp += off; |
199 | np += off; |
200 | i = 0; |
201 | while (i < q) { |
202 | np[i] = dp[i]; |
203 | i++; |
204 | } |
205 | np[i] = dp[i] & rd_bmask[r]; |
206 | |
207 | while (cur) { |
208 | if (masklen == cur->rd_masklen) { |
209 | rp = (u_char *)cur->rd_route + off; |
210 | for (i = 0; i < alen; i++) |
211 | if (np[i] != rp[i]) { |
212 | |
213 | |
214 | |
215 | |
216 | return rd_glue(cur, new, i, head); |
217 | } |
218 | |
219 | |
220 | |
221 | |
222 | Free(new); |
223 | if (cur->rd_rtent != NULL) |
224 | return EEXIST; |
225 | cur->rd_rtent = rt; |
226 | return 0; |
227 | } |
228 | |
229 | |
230 | |
231 | if (masklen > cur->rd_masklen) { |
232 | |
233 | |
234 | |
235 | |
236 | rp = (u_char *)cur->rd_route + off; |
237 | lim = cur->rd_masklim; |
238 | |
239 | |
240 | for (i = 0; i < lim; i++) |
241 | if(np[i] != rp[i]) { |
242 | |
243 | |
244 | |
245 | |
246 | return rd_glue(cur, new, i, head); |
247 | } |
248 | if (cur->rd_bmask) |
249 | if ((np[lim] & cur->rd_bmask) != rp[lim]) { |
250 | |
251 | |
252 | |
253 | |
254 | return rd_glue(cur, new, lim, head); |
255 | } |
256 | |
257 | |
258 | |
259 | |
260 | if (cur->rd_btest & np[cur->rd_masklim]) { |
261 | if (cur->rd_r != NULL) { |
262 | cur = cur->rd_r; |
263 | continue; |
264 | } |
265 | cur->rd_r = new; |
266 | new->rd_p = cur; |
267 | return 0; |
268 | } else { |
269 | if (cur->rd_l != NULL) { |
270 | cur = cur->rd_l; |
271 | continue; |
272 | } |
273 | cur->rd_l = new; |
274 | new->rd_p = cur; |
275 | return 0; |
276 | } |
277 | } |
278 | |
279 | |
280 | |
281 | |
282 | |
283 | |
284 | |
285 | rp = (u_char *)cur->rd_route + off; |
286 | lim = new->rd_masklim; |
287 | |
288 | |
289 | for (i = 0; i < lim; i++) |
290 | if(np[i] != rp[i]) { |
291 | |
292 | |
293 | |
294 | |
295 | return rd_glue(cur, new, i, head); |
296 | } |
297 | if (new->rd_bmask) |
298 | if (np[lim] != (rp[lim] & new->rd_bmask)) { |
299 | |
300 | |
301 | |
302 | |
303 | return rd_glue(cur, new, lim, head); |
304 | } |
305 | |
306 | |
307 | |
308 | |
309 | |
310 | |
311 | parent = cur->rd_p; |
312 | new->rd_p = parent; |
313 | if (parent->rd_l == cur) |
314 | parent->rd_l = new; |
315 | else if (parent->rd_r == cur) |
316 | parent->rd_r = new; |
317 | else |
318 | FATAL("rd_insert"); |
319 | if (new->rd_btest & rp[new->rd_masklim]) |
320 | new->rd_r = cur; |
321 | else |
322 | new->rd_l = cur; |
323 | |
324 | cur->rd_p = new; |
325 | return 0; |
326 | } |
327 | return 1; |
328 | } |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | int |
336 | rd_glue(struct radish *cur, struct radish *new, int misbyte, |
337 | struct radish_head *head) |
338 | { |
339 | struct radish *parent = cur->rd_p, *glue; |
340 | u_char *cp = (u_char *)cur->rd_route; |
341 | u_char *np = (u_char *)new->rd_route; |
342 | u_char *gp; |
343 | int off = head->rdh_offset, slen = head->rdh_slen; |
344 | int maskb, xor, i; |
345 | |
346 | |
347 | |
348 | |
349 | R_Malloc(glue, struct radish *, sizeof(*glue) + slen); |
350 | if (glue == NULL) { |
351 | Free (new); |
352 | return ENOBUFS; |
353 | } |
354 | Bzero(glue, sizeof(*glue) + slen); |
355 | |
356 | |
357 | xor = (*(cp + off + misbyte) ^ *(np + off + misbyte)) & 0xff; |
358 | maskb = 8; |
359 | while(xor) { |
360 | xor >>= 1; |
361 | maskb--; |
362 | } |
363 | |
364 | glue->rd_route = (struct sockaddr *)(glue + 1); |
365 | glue->rd_masklen = 8 * misbyte + maskb; |
366 | glue->rd_masklim = misbyte; |
367 | glue->rd_bmask = rd_bmask[maskb]; |
368 | glue->rd_btest = rd_btest[maskb]; |
369 | glue->rd_rtent = NULL; |
370 | glue->rd_p = parent; |
371 | glue->rd_mask = (struct sockaddr *) |
372 | ((u_char *)head->rdh_masks + slen * glue->rd_masklen); |
373 | |
374 | |
375 | gp = (u_char *)glue->rd_route; |
376 | *gp = *cp; |
377 | *(gp + 1) = *(cp + 1); |
378 | cp += off; |
379 | gp += off; |
380 | for(i = 0; i < misbyte; i++) |
381 | gp[i] = cp[i]; |
382 | gp[misbyte] = cp[misbyte] & glue->rd_bmask; |
383 | |
384 | if (glue->rd_btest & cp[misbyte]) { |
385 | glue->rd_r = cur; |
386 | glue->rd_l = new; |
387 | } else { |
388 | glue->rd_r = new; |
389 | glue->rd_l = cur; |
390 | } |
391 | |
392 | |
393 | |
394 | |
395 | new->rd_p = cur->rd_p = glue; |
396 | |
397 | |
398 | |
399 | |
400 | if (parent->rd_l == cur) |
401 | parent->rd_l = glue; |
402 | else if (parent->rd_r == cur) |
403 | parent->rd_r = glue; |
404 | else |
405 | FATAL("rd_insert"); |
406 | return 0; |
407 | } |
408 | |
409 | |
410 | |
411 | |
412 | |
413 | |
414 | int |
415 | rd_match(struct sockaddr *d_arg, struct radish_head *head, struct radish **rdp) |
416 | { |
417 | return rd_match_next(d_arg, head, rdp, NULL); |
418 | } |
419 | |
420 | int |
421 | rd_match_next(struct sockaddr *d_arg, struct radish_head *head, |
422 | struct radish **rdp, struct radish *cur) |
423 | { |
424 | struct radish *target = NULL; |
425 | int off = head->rdh_offset, i, lim; |
426 | u_char *dp = (u_char *)d_arg + off, *cp; |
427 | |
428 | if (cur == NULL) { |
429 | cur = head->rdh_top; |
430 | while (cur) { |
431 | target = cur; |
432 | if (cur->rd_btest & *(dp + cur->rd_masklim)) |
433 | cur = cur->rd_r; |
434 | else |
435 | cur = cur->rd_l; |
436 | } |
437 | } else { |
438 | target = cur->rd_p; |
439 | if (target == NULL) { |
440 | *rdp = NULL; |
441 | return 0; |
442 | } |
443 | } |
444 | |
445 | |
446 | |
447 | do { |
448 | |
449 | |
450 | if (target->rd_rtent != NULL) { |
451 | cp = (u_char *)target->rd_route + off; |
452 | lim = target->rd_masklim; |
453 | |
454 | |
455 | if (target->rd_bmask) |
456 | if ((*(dp + lim) & target->rd_bmask) |
457 | != *(cp + lim)){ |
458 | nextparent: |
459 | continue; |
460 | } |
461 | |
462 | |
463 | for (i = 0; i < lim; i++) |
464 | if(dp[i] != cp[i]) |
465 | |
466 | goto nextparent; |
467 | |
468 | *rdp = target; |
469 | return 1; |
470 | } |
471 | } while ((target = target->rd_p)); |
472 | *rdp = NULL; |
473 | return 0; |
474 | } |
475 | |
476 | |
477 | |
478 | |
479 | |
480 | |
481 | void * |
482 | rd_lookup(struct sockaddr *d_arg, struct sockaddr *m_arg, |
483 | struct radish_head *head) |
484 | { |
485 | struct radish *cur = head->rdh_top; |
486 | int off = head->rdh_offset, i, lim, olim = 0, masklen; |
487 | u_char *dp = (u_char *)d_arg + off, *cp; |
488 | |
489 | rd_mask(m_arg, head, &masklen); |
490 | |
491 | |
492 | while (cur) { |
493 | |
494 | if (cur->rd_rtent != NULL) { |
495 | cp = (u_char *)(cur->rd_route) + off; |
496 | lim = cur->rd_masklim; |
497 | |
498 | if (cur->rd_bmask) |
499 | if ((*(dp + lim) & cur->rd_bmask) |
500 | != *(cp + lim)) |
501 | return NULL; |
502 | |
503 | for (i = olim; i < lim; i++) |
504 | if(dp[i] != cp[i]) |
505 | return NULL; |
506 | if (masklen == cur->rd_masklen) |
507 | return cur->rd_rtent; |
508 | olim = lim; |
509 | } |
510 | if (cur->rd_btest & *(dp + cur->rd_masklim)) |
511 | cur = cur->rd_r; |
512 | else |
513 | cur = cur->rd_l; |
514 | } |
515 | return NULL; |
516 | } |
517 | |
518 | |
519 | |
520 | |
521 | |
522 | |
523 | |
524 | |
525 | int |
526 | rd_delete(struct sockaddr *d_arg, struct sockaddr *m_arg, |
527 | struct radish_head *head, void **item) |
528 | { |
529 | struct radish *cur = head->rdh_top; |
530 | int off = head->rdh_offset, i, lim, masklen; |
531 | u_char *dp = (u_char *)d_arg + off, *cp; |
532 | |
533 | rd_mask(m_arg, head, &masklen); |
534 | *item = NULL; |
535 | |
536 | while (cur) { |
537 | |
538 | |
539 | |
540 | cp = (u_char *)cur->rd_route + off; |
541 | |
542 | if (cur->rd_bmask) |
543 | if ((*(dp + cur->rd_masklim) & cur->rd_bmask) |
544 | != *(cp + cur->rd_masklim)) |
545 | return ENOENT; |
546 | |
547 | lim = cur->rd_masklim; |
548 | for (i = 0; i < lim; i++) |
549 | if(dp[i] != cp[i]) |
550 | return ENOENT; |
551 | |
552 | |
553 | |
554 | |
555 | if (cur->rd_masklen != masklen) |
556 | goto next; |
557 | |
558 | cp = (u_char *)cur->rd_route + off; |
559 | lim = head->rdh_alen; |
560 | for (i = 0; i < lim; i++) |
561 | if (dp[i] != cp[i]) |
562 | goto next; |
563 | |
564 | |
565 | |
566 | if (cur->rd_rtent == NULL) { |
567 | |
568 | |
569 | |
570 | |
571 | |
572 | return EFAULT; |
573 | } |
574 | *item = cur->rd_rtent; |
575 | { |
576 | |
577 | u_char rl = cur->rd_route->sa_len; |
578 | u_char ml = cur->rd_mask->sa_len; |
579 | |
580 | bcopy(cur->rd_route, rd_deleted_km, rl); |
581 | bcopy(cur->rd_mask, rd_deleted_km + rl, ml); |
582 | } |
583 | if (cur->rd_l && cur->rd_r) { |
584 | |
585 | cur->rd_rtent = NULL; |
586 | return 0; |
587 | } |
588 | |
589 | |
590 | |
591 | rd_unlink(cur, head->rdh_top); |
592 | return 0; |
593 | |
594 | next: |
595 | |
596 | if (cur->rd_btest & *(dp + cur->rd_masklim)) { |
597 | if (cur->rd_r) { |
598 | cur = cur->rd_r; |
599 | continue; |
600 | } else |
601 | break; |
602 | } else { |
603 | if (cur->rd_l) { |
604 | cur = cur->rd_l; |
605 | continue; |
606 | } else |
607 | break; |
608 | } |
609 | } |
610 | return ENOENT; |
611 | } |
612 | |
613 | |
614 | |
615 | |
616 | |
617 | |
618 | |
619 | void |
620 | rd_unlink(struct radish *cur, struct radish *top) |
621 | { |
622 | struct radish *parent, *child; |
623 | |
624 | if (cur == top) { |
625 | cur->rd_rtent = NULL; |
626 | return; |
627 | } |
628 | |
629 | if ((cur->rd_l == 0) && (cur->rd_r == 0)) { |
630 | |
631 | parent = cur->rd_p; |
632 | if (parent->rd_l == cur) { |
633 | parent->rd_l = NULL; |
634 | Free(cur); |
635 | } else if (parent->rd_r == cur) { |
636 | parent->rd_r = NULL; |
637 | Free(cur); |
638 | } else |
639 | FATAL("rd_unlink"); |
640 | if (parent->rd_rtent == NULL && parent != top) |
641 | |
642 | rd_unlink(parent, top); |
643 | } else { |
644 | |
645 | |
646 | |
647 | |
648 | if (cur->rd_l) |
649 | child = cur->rd_l; |
650 | else |
651 | child = cur->rd_r; |
652 | parent = cur->rd_p; |
653 | child->rd_p = parent; |
654 | if (parent->rd_l == cur) { |
655 | parent->rd_l = child; |
656 | Free(cur); |
657 | } else if (parent->rd_r == cur) { |
658 | parent->rd_r = child; |
659 | Free(cur); |
660 | } else |
661 | FATAL("rd_unlink"); |
662 | } |
663 | } |
664 | |
665 | int |
666 | rd_walktree(struct radish_head *h, register int (*f)(struct radish *, void *), |
667 | void *w) |
668 | { |
669 | int error = 0; |
670 | struct radish *par = NULL, *cur, *top = h->rdh_top; |
| 1 | 'par' initialized to a null pointer value | |
|
671 | |
672 | cur = top; |
673 | for (;;) { |
| 2 | | Loop condition is true. Entering loop body | |
|
674 | while (cur) { |
| 3 | | Loop condition is false. Execution continues on line 681 | |
|
675 | if (cur->rd_rtent != NULL) |
676 | if ((error = (*f)(cur, w))) |
677 | return error; |
678 | par = cur; |
679 | cur = cur->rd_l; |
680 | } |
681 | cur = par; |
| 4 | | Null pointer value stored to 'cur' | |
|
682 | while (cur->rd_r == NULL || par == cur->rd_r) { |
| 5 | | Access to field 'rd_r' results in a dereference of a null pointer (loaded from variable 'cur') |
|
683 | par = cur; |
684 | cur = cur->rd_p; |
685 | if (cur == NULL) return 0; |
686 | } |
687 | par = cur; |
688 | cur = cur->rd_r; |
689 | } |
690 | } |
691 | |
692 | |
693 | |
694 | |
695 | |
696 | int |
697 | rd_refines(void *m_arg, void *n_arg) |
698 | { |
699 | register caddr_t m = m_arg, n = n_arg; |
700 | register caddr_t lim, lim2 = lim = n + *(u_char *)n; |
701 | int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); |
702 | int masks_are_equal = 1; |
703 | |
704 | if (longer > 0) |
705 | lim -= longer; |
706 | while (n < lim) { |
707 | if (*n & ~(*m)) |
708 | return 0; |
709 | if (*n++ != *m++) |
710 | masks_are_equal = 0; |
711 | |
712 | } |
713 | while (n < lim2) |
714 | if (*n++) |
715 | return 0; |
716 | if (masks_are_equal && (longer < 0)) |
717 | for (lim2 = m - longer; m < lim2; ) |
718 | if (*m++) |
719 | return 1; |
720 | return (!masks_are_equal); |
721 | } |