Bug Summary

File:src/usr.sbin/sasyncd/pfkey.c
Warning:line 489, column 14
Result of 'calloc' is converted to a pointer of type 'u_int8_t', which is incompatible with sizeof operand type 'u_int64_t'

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 pfkey.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/sasyncd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/sasyncd -I /usr/src/usr.sbin/sasyncd/../../sbin/iked -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/sasyncd/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/sasyncd/pfkey.c
1/* $OpenBSD: pfkey.c,v 1.29 2018/06/28 02:37:26 gsoares Exp $ */
2
3/*
4 * Copyright (c) 2005 Håkan Olsson. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * This code was written under funding by Multicom Security AB.
30 */
31
32
33#include <sys/types.h>
34#include <sys/ioctl.h>
35#include <sys/select.h>
36#include <sys/socket.h>
37#include <sys/queue.h>
38#include <sys/sysctl.h>
39#include <net/pfkeyv2.h>
40#include <netinet/ip_ipsp.h>
41
42#include <errno(*__errno()).h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47
48#include "sasyncd.h"
49#include "monitor.h"
50#include "net.h"
51
52struct pfkey_msg
53{
54 SIMPLEQ_ENTRY(pfkey_msg)struct { struct pfkey_msg *sqe_next; } next;
55
56 u_int8_t *buf;
57 u_int32_t len;
58};
59
60SIMPLEQ_HEAD(, pfkey_msg)struct { struct pfkey_msg *sqh_first; struct pfkey_msg **sqh_last
; }
pfkey_msglist;
61
62static const char *msgtypes[] = {
63 "RESERVED", "GETSPI", "UPDATE", "ADD", "DELETE", "GET", "ACQUIRE",
64 "REGISTER", "EXPIRE", "FLUSH", "DUMP", "X_PROMISC", "X_ADDFLOW",
65 "X_DELFLOW", "X_GRPSPIS", "X_ASKPOLICY", "X_SPDDUMP"
66};
67
68#define CHUNKsizeof(u_int64_t) sizeof(u_int64_t)
69
70static const char *pfkey_print_type(struct sadb_msg *);
71
72static int
73pfkey_write(u_int8_t *buf, ssize_t len)
74{
75 struct sadb_msg *msg = (struct sadb_msg *)buf;
76 ssize_t n;
77
78 if (cfgstate.pfkey_socket == -1)
79 return 0;
80
81 do {
82 n = write(cfgstate.pfkey_socket, buf, len);
83 } while (n == -1 && (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4));
84 if (n == -1) {
85 log_err("pfkey: msg %s write() failed on socket %d",
86 pfkey_print_type(msg), cfgstate.pfkey_socket);
87 return -1;
88 }
89
90 return 0;
91}
92
93int
94pfkey_set_promisc(void)
95{
96 struct sadb_msg msg;
97 static u_int32_t seq = 1;
98
99 memset(&msg, 0, sizeof msg);
100 msg.sadb_msg_version = PF_KEY_V22;
101 msg.sadb_msg_seq = seq++;
102 msg.sadb_msg_satype = 1; /* Special; 1 to enable, 0 to disable */
103 msg.sadb_msg_type = SADB_X_PROMISC11;
104 msg.sadb_msg_pid = getpid();
105 msg.sadb_msg_len = sizeof msg / CHUNKsizeof(u_int64_t);
106
107 return pfkey_write((u_int8_t *)&msg, sizeof msg);
108}
109
110/* Send a SADB_FLUSH PFKEY message to peer 'p' */
111static void
112pfkey_send_flush(struct syncpeer *p)
113{
114 struct sadb_msg *m = calloc(1, sizeof *m);
115 static u_int32_t seq = 1;
116
117 if (m) {
118 m->sadb_msg_version = PF_KEY_V22;
119 m->sadb_msg_seq = seq++;
120 m->sadb_msg_type = SADB_FLUSH9;
121 m->sadb_msg_satype = SADB_SATYPE_UNSPEC0;
122 m->sadb_msg_pid = getpid();
123 m->sadb_msg_len = sizeof *m / CHUNKsizeof(u_int64_t);
124
125 log_msg(2, "pfkey_send_flush: sending FLUSH to peer %s",
126 p->name);
127 net_queue(p, MSG_PFKEYDATA1, (u_int8_t *)m, sizeof *m);
128 }
129}
130
131static const char *
132pfkey_print_type(struct sadb_msg *msg)
133{
134 static char uk[20];
135
136 if (msg->sadb_msg_type < sizeof msgtypes / sizeof msgtypes[0])
137 return msgtypes[msg->sadb_msg_type];
138 else {
139 snprintf(uk, sizeof uk, "<unknown(%d)>", msg->sadb_msg_type);
140 return uk;
141 }
142}
143
144static struct sadb_ext *
145pfkey_find_ext(struct sadb_msg *msg, u_int16_t type)
146{
147 struct sadb_ext *ext;
148 u_int8_t *e;
149
150 for (e = (u_int8_t *)msg + sizeof *msg;
151 e < (u_int8_t *)msg + msg->sadb_msg_len * CHUNKsizeof(u_int64_t);
152 e += ext->sadb_ext_len * CHUNKsizeof(u_int64_t)) {
153 ext = (struct sadb_ext *)e;
154 if (ext->sadb_ext_len == 0)
155 break;
156 if (ext->sadb_ext_type != type)
157 continue;
158 return ext;
159 }
160 return NULL((void *)0);
161}
162
163/* Return: 0 means ok to sync msg, 1 means to skip it */
164static int
165pfkey_msg_filter(struct sadb_msg *msg)
166{
167 struct sockaddr *src = 0, *dst = 0;
168 struct syncpeer *p;
169 struct sadb_ext *ext;
170 u_int8_t *max;
171
172 switch (msg->sadb_msg_type) {
173 case SADB_X_PROMISC11:
174 case SADB_DUMP10:
175 case SADB_GET5:
176 case SADB_GETSPI1:
177 case SADB_ACQUIRE6:
178 case SADB_X_ASKPOLICY15:
179 case SADB_REGISTER7:
180 /* Some messages should not be synced. */
181 return 1;
182
183 case SADB_ADD3:
184 /* No point in syncing LARVAL SAs */
185 if (pfkey_find_ext(msg, SADB_EXT_KEY_ENCRYPT9) == 0)
186 return 1;
187 case SADB_DELETE4:
188 case SADB_X_ADDFLOW12:
189 case SADB_X_DELFLOW13:
190 case SADB_EXPIRE8:
191 /* Continue below */
192 break;
193 case SADB_FLUSH9:
194 if ((cfgstate.flags & FM_MASK0x0003) == FM_NEVER0x0001)
195 return 1;
196 break;
197 default:
198 return 0;
199 }
200
201 if ((cfgstate.flags & SKIP_LOCAL_SAS0x0004) == 0)
202 return 0;
203
204 /* SRC or DST address of this msg must not be one of our peers. */
205 ext = pfkey_find_ext(msg, SADB_EXT_ADDRESS_SRC5);
206 if (ext)
207 src = (struct sockaddr *)((struct sadb_address *)ext + 1);
208 ext = pfkey_find_ext(msg, SADB_EXT_ADDRESS_DST6);
209 if (ext)
210 dst = (struct sockaddr *)((struct sadb_address *)ext + 1);
211 if (!src && !dst)
212 return 0;
213
214 max = (u_int8_t *)msg + msg->sadb_msg_len * CHUNKsizeof(u_int64_t);
215 if (src && ((u_int8_t *)src + src->sa_len) > max)
216 return 1;
217 if (dst && ((u_int8_t *)dst + dst->sa_len) > max)
218 return 1;
219
220 /* Found SRC or DST, check it against our peers */
221 for (p = LIST_FIRST(&cfgstate.peerlist)((&cfgstate.peerlist)->lh_first); p; p = LIST_NEXT(p, link)((p)->link.le_next)) {
222 if (p->socket < 0 || p->sa->sa_family !=
223 (src ? src->sa_family : dst->sa_family))
224 continue;
225
226 switch (p->sa->sa_family) {
227 case AF_INET2:
228 if (src && memcmp(
229 &((struct sockaddr_in *)p->sa)->sin_addr.s_addr,
230 &((struct sockaddr_in *)src)->sin_addr.s_addr,
231 sizeof(struct in_addr)) == 0)
232 return 1;
233 if (dst && memcmp(
234 &((struct sockaddr_in *)p->sa)->sin_addr.s_addr,
235 &((struct sockaddr_in *)dst)->sin_addr.s_addr,
236 sizeof(struct in_addr)) == 0)
237 return 1;
238 break;
239 case AF_INET624:
240 if (src &&
241 memcmp(&((struct sockaddr_in6 *)p->sa)->sin6_addr,
242 &((struct sockaddr_in6 *)src)->sin6_addr,
243 sizeof(struct in_addr)) == 0)
244 return 1;
245 if (dst &&
246 memcmp(&((struct sockaddr_in6 *)p->sa)->sin6_addr,
247 &((struct sockaddr_in6 *)dst)->sin6_addr,
248 sizeof(struct in_addr)) == 0)
249 return 1;
250 break;
251 }
252 }
253 return 0;
254}
255
256static int
257pfkey_handle_message(struct sadb_msg *m)
258{
259 struct sadb_msg *msg = m;
260
261 /*
262 * Report errors, but ignore for DELETE (both isakmpd and kernel will
263 * expire the SA, if the kernel is first, DELETE returns failure).
264 */
265 if (msg->sadb_msg_errno && msg->sadb_msg_type != SADB_DELETE4 &&
266 msg->sadb_msg_pid == (u_int32_t)getpid()) {
267 errno(*__errno()) = msg->sadb_msg_errno;
268 log_msg(1, "pfkey error (%s)", pfkey_print_type(msg));
269 }
270
271 /* We only want promiscuous messages here, skip all others. */
272 if (msg->sadb_msg_type != SADB_X_PROMISC11 ||
273 (msg->sadb_msg_len * CHUNKsizeof(u_int64_t)) < 2 * sizeof *msg) {
274 free(m);
275 return 0;
276 }
277 /* Move next msg to start of the buffer. */
278 msg++;
279
280 /*
281 * We should not listen to PFKEY messages when we are not running
282 * as MASTER, or the pid is our own.
283 */
284 if (cfgstate.runstate != MASTER ||
285 msg->sadb_msg_pid == (u_int32_t)getpid()) {
286 free(m);
287 return 0;
288 }
289
290 if (pfkey_msg_filter(msg)) {
291 free(m);
292 return 0;
293 }
294
295 switch (msg->sadb_msg_type) {
296 case SADB_UPDATE2:
297 /*
298 * Tweak -- the peers do not have a larval SA to update, so
299 * instead we ADD it here.
300 */
301 msg->sadb_msg_type = SADB_ADD3;
302 /* FALLTHROUGH */
303
304 default:
305 /* Pass the rest along to our peers. */
306 memmove(m, msg, msg->sadb_msg_len * CHUNKsizeof(u_int64_t)); /* for realloc */
307 return net_queue(NULL((void *)0), MSG_PFKEYDATA1, (u_int8_t *)m,
308 m->sadb_msg_len * CHUNKsizeof(u_int64_t));
309 }
310
311 return 0;
312}
313
314static int
315pfkey_read(void)
316{
317 struct sadb_msg hdr, *msg;
318 u_int8_t *data;
319 ssize_t datalen;
320 int fd = cfgstate.pfkey_socket;
321
322 if (recv(fd, &hdr, sizeof hdr, MSG_PEEK0x2) != sizeof hdr) {
323 log_err("pfkey_read: recv() failed");
324 return -1;
325 }
326 datalen = hdr.sadb_msg_len * CHUNKsizeof(u_int64_t);
327 data = reallocarray(NULL((void *)0), hdr.sadb_msg_len, CHUNKsizeof(u_int64_t));
328 if (!data) {
329 log_err("pfkey_read: malloc(%lu) failed", datalen);
330 return -1;
331 }
332 msg = (struct sadb_msg *)data;
333
334 if (read(fd, data, datalen) != datalen) {
335 log_err("pfkey_read: read() failed, %lu bytes", datalen);
336 free(data);
337 return -1;
338 }
339
340 return pfkey_handle_message(msg);
341}
342
343int
344pfkey_init(int reinit)
345{
346 int fd;
347
348 fd = socket(PF_KEY30, SOCK_RAW3, PF_KEY_V22);
349 if (fd == -1) {
350 perror("failed to open PF_KEY socket");
351 return -1;
352 }
353 cfgstate.pfkey_socket = fd;
354
355 if (cfgstate.runstate == MASTER)
356 pfkey_set_promisc();
357
358 if (reinit)
359 return (fd > -1 ? 0 : -1);
360
361 SIMPLEQ_INIT(&pfkey_msglist)do { (&pfkey_msglist)->sqh_first = ((void *)0); (&
pfkey_msglist)->sqh_last = &(&pfkey_msglist)->sqh_first
; } while (0)
;
362 return 0;
363}
364
365void
366pfkey_set_rfd(fd_set *fds)
367{
368 if (cfgstate.pfkey_socket != -1)
369 FD_SET(cfgstate.pfkey_socket, fds)__fd_set((cfgstate.pfkey_socket), (fds));
370}
371
372void
373pfkey_set_pending_wfd(fd_set *fds)
374{
375 if (cfgstate.pfkey_socket != -1 && SIMPLEQ_FIRST(&pfkey_msglist)((&pfkey_msglist)->sqh_first))
376 FD_SET(cfgstate.pfkey_socket, fds)__fd_set((cfgstate.pfkey_socket), (fds));
377}
378
379void
380pfkey_read_message(fd_set *fds)
381{
382 if (cfgstate.pfkey_socket != -1)
383 if (FD_ISSET(cfgstate.pfkey_socket, fds)__fd_isset((cfgstate.pfkey_socket), (fds)))
384 (void)pfkey_read();
385}
386
387void
388pfkey_send_message(fd_set *fds)
389{
390 struct pfkey_msg *pmsg = SIMPLEQ_FIRST(&pfkey_msglist)((&pfkey_msglist)->sqh_first);
391
392 if (!pmsg || !FD_ISSET(cfgstate.pfkey_socket, fds)__fd_isset((cfgstate.pfkey_socket), (fds)))
393 return;
394
395 if (cfgstate.pfkey_socket == -1)
396 if (pfkey_init(1)) /* Reinit socket */
397 return;
398
399 (void)pfkey_write(pmsg->buf, pmsg->len);
400
401 SIMPLEQ_REMOVE_HEAD(&pfkey_msglist, next)do { if (((&pfkey_msglist)->sqh_first = (&pfkey_msglist
)->sqh_first->next.sqe_next) == ((void *)0)) (&pfkey_msglist
)->sqh_last = &(&pfkey_msglist)->sqh_first; } while
(0)
;
402 free(pmsg->buf);
403 free(pmsg);
404
405 return;
406}
407
408int
409pfkey_queue_message(u_int8_t *data, u_int32_t datalen)
410{
411 struct pfkey_msg *pmsg;
412 struct sadb_msg *sadb = (struct sadb_msg *)data;
413 static u_int32_t seq = 1;
414
415 pmsg = malloc(sizeof *pmsg);
416 if (!pmsg) {
417 log_err("malloc()");
418 return -1;
419 }
420 memset(pmsg, 0, sizeof *pmsg);
421
422 pmsg->buf = data;
423 pmsg->len = datalen;
424
425 sadb->sadb_msg_pid = getpid();
426 sadb->sadb_msg_seq = seq++;
427 log_msg(2, "pfkey_queue_message: pfkey %s len %zu seq %u",
428 pfkey_print_type(sadb), sadb->sadb_msg_len * CHUNKsizeof(u_int64_t),
429 sadb->sadb_msg_seq);
430
431 SIMPLEQ_INSERT_TAIL(&pfkey_msglist, pmsg, next)do { (pmsg)->next.sqe_next = ((void *)0); *(&pfkey_msglist
)->sqh_last = (pmsg); (&pfkey_msglist)->sqh_last = &
(pmsg)->next.sqe_next; } while (0)
;
432 return 0;
433}
434
435void
436pfkey_shutdown(void)
437{
438 struct pfkey_msg *p = SIMPLEQ_FIRST(&pfkey_msglist)((&pfkey_msglist)->sqh_first);
439
440 while ((p = SIMPLEQ_FIRST(&pfkey_msglist)((&pfkey_msglist)->sqh_first))) {
441 SIMPLEQ_REMOVE_HEAD(&pfkey_msglist, next)do { if (((&pfkey_msglist)->sqh_first = (&pfkey_msglist
)->sqh_first->next.sqe_next) == ((void *)0)) (&pfkey_msglist
)->sqh_last = &(&pfkey_msglist)->sqh_first; } while
(0)
;
442 free(p->buf);
443 free(p);
444 }
445
446 if (cfgstate.pfkey_socket > -1)
447 close(cfgstate.pfkey_socket);
448}
449
450/* ------------------------------------------------------------------------- */
451
452void
453pfkey_snapshot(void *v)
454{
455 struct syncpeer *p = (struct syncpeer *)v;
456 struct sadb_msg *m;
457 u_int8_t *sadb, *spd, *max, *next, *sendbuf;
458 u_int32_t sadbsz, spdsz;
459
460 if (!p)
461 return;
462
463 if (monitor_get_pfkey_snap(&sadb, &sadbsz, &spd, &spdsz)) {
464 log_msg(0, "pfkey_snapshot: failed to get pfkey snapshot");
465 return;
466 }
467
468 /* XXX needs moving if snapshot is called more than once per peer */
469 if ((cfgstate.flags & FM_MASK0x0003) == FM_STARTUP0x0000)
470 pfkey_send_flush(p);
471
472 /* Parse SADB data */
473 if (sadbsz && sadb) {
474 dump_buf(2, sadb, sadbsz, "pfkey_snapshot: SADB data");
475 max = sadb + sadbsz;
476 for (next = sadb; next < max;
477 next += m->sadb_msg_len * CHUNKsizeof(u_int64_t)) {
478 m = (struct sadb_msg *)next;
479 if (m->sadb_msg_len == 0)
480 break;
481
482 /* Tweak and send this SA to the peer. */
483 m->sadb_msg_type = SADB_ADD3;
484
485 if (pfkey_msg_filter(m))
486 continue;
487
488 /* Allocate msgbuffer, net_queue() will free it. */
489 sendbuf = calloc(m->sadb_msg_len, CHUNKsizeof(u_int64_t));
Result of 'calloc' is converted to a pointer of type 'u_int8_t', which is incompatible with sizeof operand type 'u_int64_t'
490 if (sendbuf) {
491 memcpy(sendbuf, m, m->sadb_msg_len * CHUNKsizeof(u_int64_t));
492 net_queue(p, MSG_PFKEYDATA1, sendbuf,
493 m->sadb_msg_len * CHUNKsizeof(u_int64_t));
494 log_msg(2, "pfkey_snapshot: sync SA %p len %zu "
495 "to peer %s", m,
496 m->sadb_msg_len * CHUNKsizeof(u_int64_t), p->name);
497 }
498 }
499 freezero(sadb, sadbsz);
500 }
501
502 /* Parse SPD data */
503 if (spdsz && spd) {
504 dump_buf(2, spd, spdsz, "pfkey_snapshot: SPD data");
505 max = spd + spdsz;
506 for (next = spd; next < max; next += m->sadb_msg_len * CHUNKsizeof(u_int64_t)) {
507 m = (struct sadb_msg *)next;
508 if (m->sadb_msg_len == 0)
509 break;
510
511 /* Tweak msg type. */
512 m->sadb_msg_type = SADB_X_ADDFLOW12;
513
514 if (pfkey_msg_filter(m))
515 continue;
516
517 /* Allocate msgbuffer, freed by net_queue(). */
518 sendbuf = calloc(m->sadb_msg_len, CHUNKsizeof(u_int64_t));
519 if (sendbuf) {
520 memcpy(sendbuf, m, m->sadb_msg_len * CHUNKsizeof(u_int64_t));
521 net_queue(p, MSG_PFKEYDATA1, sendbuf,
522 m->sadb_msg_len * CHUNKsizeof(u_int64_t));
523 log_msg(2, "pfkey_snapshot: sync FLOW %p len "
524 "%zu to peer %s", m,
525 m->sadb_msg_len * CHUNKsizeof(u_int64_t), p->name);
526 }
527 }
528 /* Cleanup. */
529 freezero(spd, spdsz);
530 }
531
532 net_ctl_send_endsnap(p);
533 return;
534}