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