Bug Summary

File:src/sbin/isakmpd/util.c
Warning:line 589, column 3
Potential leak of memory pointed to by 'tmp'

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 util.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/sbin/isakmpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/isakmpd -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/isakmpd/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/sbin/isakmpd/util.c
1/* $OpenBSD: util.c,v 1.72 2019/06/28 13:32:44 deraadt Exp $ */
2/* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */
3
4/*
5 * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved.
6 * Copyright (c) 2000, 2001, 2004 Håkan Olsson. 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 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * This code was written under funding by Ericsson Radio Systems.
31 */
32
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/stat.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <limits.h>
39#include <netdb.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include <errno(*__errno()).h>
44#include <ifaddrs.h>
45#include <net/route.h>
46#include <net/if.h>
47
48#include "log.h"
49#include "message.h"
50#include "monitor.h"
51#include "transport.h"
52#include "util.h"
53
54/*
55 * Set if -N is given, allowing name lookups to be done, possibly stalling
56 * the daemon for quite a while.
57 */
58int allow_name_lookups = 0;
59
60/*
61 * XXX These might be turned into inlines or macros, maybe even
62 * machine-dependent ones, for performance reasons.
63 */
64u_int16_t
65decode_16(u_int8_t *cp)
66{
67 return cp[0] << 8 | cp[1];
68}
69
70u_int32_t
71decode_32(u_int8_t *cp)
72{
73 return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3];
74}
75
76void
77encode_16(u_int8_t *cp, u_int16_t x)
78{
79 *cp++ = x >> 8;
80 *cp = x & 0xff;
81}
82
83void
84encode_32(u_int8_t *cp, u_int32_t x)
85{
86 *cp++ = x >> 24;
87 *cp++ = (x >> 16) & 0xff;
88 *cp++ = (x >> 8) & 0xff;
89 *cp = x & 0xff;
90}
91
92/* Check a buffer for all zeroes. */
93int
94zero_test(const u_int8_t *p, size_t sz)
95{
96 while (sz-- > 0)
97 if (*p++ != 0)
98 return 0;
99 return 1;
100}
101
102static __inline int
103hex2nibble(char c)
104{
105 if (c >= '0' && c <= '9')
106 return c - '0';
107 if (c >= 'a' && c <= 'f')
108 return c - 'a' + 10;
109 if (c >= 'A' && c <= 'F')
110 return c - 'A' + 10;
111 return -1;
112}
113
114/*
115 * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ
116 * bytes. Return 0 if everything is OK, -1 otherwise.
117 */
118int
119hex2raw(char *s, u_int8_t *buf, size_t sz)
120{
121 u_int8_t *bp;
122 char *p;
123 int tmp;
124
125 if (strlen(s) > sz * 2)
126 return -1;
127 for (p = s + strlen(s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--) {
128 *bp = 0;
129 if (p >= s) {
130 tmp = hex2nibble(*p--);
131 if (tmp == -1)
132 return -1;
133 *bp = tmp;
134 }
135 if (p >= s) {
136 tmp = hex2nibble(*p--);
137 if (tmp == -1)
138 return -1;
139 *bp |= tmp << 4;
140 }
141 }
142 return 0;
143}
144
145/*
146 * Convert raw binary buffer to a newly allocated hexadecimal string. Returns
147 * NULL if an error occurred. It is the caller's responsibility to free the
148 * returned string.
149 */
150char *
151raw2hex(u_int8_t *buf, size_t sz)
152{
153 char *s;
154 size_t i;
155
156 if ((s = malloc(sz * 2 + 1)) == NULL((void *)0)) {
157 log_error("raw2hex: malloc (%lu) failed", (unsigned long)sz * 2 + 1);
158 return NULL((void *)0);
159 }
160
161 for (i = 0; i < sz; i++)
162 snprintf(s + (2 * i), 2 * (sz - i) + 1, "%02x", buf[i]);
163
164 s[sz * 2] = '\0';
165 return s;
166}
167
168in_port_t
169text2port(char *port_str)
170{
171 char *port_str_end;
172 long port_long;
173 struct servent *service;
174
175 port_long = strtol(port_str, &port_str_end, 0);
176 if (port_str == port_str_end) {
177 service = getservbyname(port_str, "udp");
178 if (!service) {
179 log_print("text2port: service \"%s\" unknown",
180 port_str);
181 return 0;
182 }
183 return ntohs(service->s_port)(__uint16_t)(__builtin_constant_p(service->s_port) ? (__uint16_t
)(((__uint16_t)(service->s_port) & 0xffU) << 8 |
((__uint16_t)(service->s_port) & 0xff00U) >> 8)
: __swap16md(service->s_port))
;
184 } else if (port_long < 1 || port_long > (long)USHRT_MAX(32767 *2 +1)) {
185 log_print("text2port: port %ld out of range", port_long);
186 return 0;
187 }
188 return port_long;
189}
190
191int
192text2sockaddr(char *address, char *port, struct sockaddr **sa, sa_family_t af,
193 int netmask)
194{
195 struct addrinfo *ai, hints;
196 struct sockaddr_storage tmp_sas;
197 struct ifaddrs *ifap, *ifa = NULL((void *)0), *llifa = NULL((void *)0);
198 char *np = address;
199 char ifname[IFNAMSIZ16];
200 u_char buf[BUFSIZ1024];
201 struct rt_msghdr *rtm;
202 struct sockaddr *sa2;
203 struct sockaddr_in *sin;
204 struct sockaddr_in6 *sin6;
205 int fd = 0, seq, len, b;
206 pid_t pid;
207
208 bzero(&hints, sizeof hints);
209 if (!allow_name_lookups)
210 hints.ai_flags = AI_NUMERICHOST4;
211 hints.ai_family = PF_UNSPEC0;
212 hints.ai_socktype = SOCK_DGRAM2;
213 hints.ai_protocol = IPPROTO_UDP17;
214
215 if (getaddrinfo(address, port, &hints, &ai)) {
216 /*
217 * If the 'default' keyword is used, do a route lookup for
218 * the default route, and use the interface associated with
219 * it to select a source address.
220 */
221 if (!strcmp(address, "default")) {
222 fd = socket(AF_ROUTE17, SOCK_RAW3, af);
223
224 bzero(buf, sizeof(buf));
225
226 rtm = (struct rt_msghdr *)buf;
227 rtm->rtm_version = RTM_VERSION5;
228 rtm->rtm_type = RTM_GET0x4;
229 rtm->rtm_flags = RTF_UP0x1;
230 rtm->rtm_addrs = RTA_DST0x1;
231 rtm->rtm_seq = seq = arc4random();
232
233 /* default destination */
234 sa2 = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
235 switch (af) {
236 case AF_INET2: {
237 sin = (struct sockaddr_in *)sa2;
238 sin->sin_len = sizeof(*sin);
239 sin->sin_family = af;
240 break;
241 }
242 case AF_INET624: {
243 sin6 = (struct sockaddr_in6 *)sa2;
244 sin6->sin6_len = sizeof(*sin6);
245 sin6->sin6_family = af;
246 break;
247 }
248 default:
249 close(fd);
250 return -1;
251 }
252 rtm->rtm_addrs |= RTA_NETMASK0x4|RTA_IFP0x10|RTA_IFA0x20;
253 rtm->rtm_msglen = sizeof(*rtm) + sizeof(*sa2);
254
255 if ((b = write(fd, buf, rtm->rtm_msglen)) == -1) {
256 close(fd);
257 return -1;
258 }
259
260 pid = getpid();
261
262 while ((len = read(fd, buf, sizeof(buf))) > 0) {
263 if (len < sizeof(*rtm)) {
264 close(fd);
265 return -1;
266 }
267 if (rtm->rtm_version != RTM_VERSION5)
268 continue;
269
270 if (rtm->rtm_type == RTM_GET0x4 &&
271 rtm->rtm_pid == pid &&
272 rtm->rtm_seq == seq) {
273 if (rtm->rtm_errno) {
274 close(fd);
275 return -1;
276 }
277 break;
278 }
279 }
280 close(fd);
281
282 if ((rtm->rtm_addrs & (RTA_DST0x1|RTA_GATEWAY0x2)) ==
283 (RTA_DST0x1|RTA_GATEWAY0x2)) {
284 np = if_indextoname(rtm->rtm_index, ifname);
285 if (np == NULL((void *)0))
286 return -1;
287 }
288 }
289
290 if (getifaddrs(&ifap) != 0)
291 return -1;
292
293 switch (af) {
294 default:
295 case AF_INET2:
296 for (ifa = ifap; ifa; ifa = ifa->ifa_next)
297 if (!strcmp(ifa->ifa_name, np) &&
298 ifa->ifa_addr != NULL((void *)0) &&
299 ifa->ifa_addr->sa_family == AF_INET2)
300 break;
301 break;
302 case AF_INET624:
303 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
304 if (!strcmp(ifa->ifa_name, np) &&
305 ifa->ifa_addr != NULL((void *)0) &&
306 ifa->ifa_addr->sa_family == AF_INET624) {
307 if (IN6_IS_ADDR_LINKLOCAL((((&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr
)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&((struct
sockaddr_in6 *) ifa->ifa_addr)->sin6_addr)->__u6_addr
.__u6_addr8[1] & 0xc0) == 0x80))
308 &((struct sockaddr_in6 *)(((&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr
)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&((struct
sockaddr_in6 *) ifa->ifa_addr)->sin6_addr)->__u6_addr
.__u6_addr8[1] & 0xc0) == 0x80))
309 ifa->ifa_addr)->sin6_addr)(((&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr
)->__u6_addr.__u6_addr8[0] == 0xfe) && (((&((struct
sockaddr_in6 *) ifa->ifa_addr)->sin6_addr)->__u6_addr
.__u6_addr8[1] & 0xc0) == 0x80))
&&
310 llifa == NULL((void *)0))
311 llifa = ifa;
312 else
313 break;
314 }
315 }
316 if (ifa == NULL((void *)0)) {
317 ifa = llifa;
318 }
319 break;
320 }
321
322 if (ifa) {
323 if (netmask)
324 memcpy(&tmp_sas, ifa->ifa_netmask,
325 SA_LEN(ifa->ifa_netmask)((ifa->ifa_netmask)->sa_len));
326 else
327 memcpy(&tmp_sas, ifa->ifa_addr,
328 SA_LEN(ifa->ifa_addr)((ifa->ifa_addr)->sa_len));
329 freeifaddrs(ifap);
330 } else {
331 freeifaddrs(ifap);
332 return -1;
333 }
334 } else {
335 memcpy(&tmp_sas, ai->ai_addr, SA_LEN(ai->ai_addr)((ai->ai_addr)->sa_len));
336 freeaddrinfo(ai);
337 }
338
339 *sa = malloc(SA_LEN((struct sockaddr *)&tmp_sas)(((struct sockaddr *)&tmp_sas)->sa_len));
340 if (!*sa)
341 return -1;
342
343 memcpy(*sa, &tmp_sas, SA_LEN((struct sockaddr *)&tmp_sas)(((struct sockaddr *)&tmp_sas)->sa_len));
344 return 0;
345}
346
347/*
348 * Convert a sockaddr to text. With zflag non-zero fill out with zeroes,
349 * i.e 10.0.0.10 --> "010.000.000.010"
350 */
351int
352sockaddr2text(struct sockaddr *sa, char **address, int zflag)
353{
354 char buf[NI_MAXHOST256], *token, *bstart, *ep;
355 int addrlen, i, j;
356 long val;
357
358 if (getnameinfo(sa, SA_LEN(sa)((sa)->sa_len), buf, sizeof buf, 0, 0,
359 allow_name_lookups ? 0 : NI_NUMERICHOST1))
360 return -1;
361
362 if (zflag == 0) {
363 *address = strdup(buf);
364 if (!*address)
365 return -1;
366 } else
367 switch (sa->sa_family) {
368 case AF_INET2:
369 addrlen = sizeof "000.000.000.000";
370 *address = malloc(addrlen);
371 if (!*address)
372 return -1;
373 buf[addrlen] = '\0';
374 bstart = buf;
375 **address = '\0';
376 while ((token = strsep(&bstart, ".")) != NULL((void *)0)) {
377 if (strlen(*address) > 12) {
378 free(*address);
379 return -1;
380 }
381 val = strtol(token, &ep, 10);
382 if (ep == token || val < (long)0 ||
383 val > (long)UCHAR_MAX(127*2 +1)) {
384 free(*address);
385 return -1;
386 }
387 snprintf(*address + strlen(*address),
388 addrlen - strlen(*address), "%03ld", val);
389 if (bstart)
390 strlcat(*address, ".", addrlen);
391 }
392 break;
393
394 case AF_INET624:
395 /*
396 * XXX In the algorithm below there are some magic
397 * numbers we probably could give explaining names.
398 */
399 addrlen =
400 sizeof "0000:0000:0000:0000:0000:0000:0000:0000";
401 *address = malloc(addrlen);
402 if (!*address)
403 return -1;
404
405 for (i = 0, j = 0; i < 8; i++) {
406 snprintf((*address) + j, addrlen - j,
407 "%02x%02x",
408 ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr__u6_addr.__u6_addr8[2*i],
409 ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr__u6_addr.__u6_addr8[2*i + 1]);
410 j += 4;
411 (*address)[j] =
412 (j < (addrlen - 1)) ? ':' : '\0';
413 j++;
414 }
415 break;
416
417 default:
418 *address = strdup("<error>");
419 if (!*address)
420 return -1;
421 }
422
423 return 0;
424}
425
426/*
427 * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info
428 * depending on address family. Useful to keep other code shorter(/clearer?).
429 */
430int
431sockaddr_addrlen(struct sockaddr *sa)
432{
433 switch (sa->sa_family) {
434 case AF_INET624:
435 return sizeof((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr__u6_addr.__u6_addr8;
436 case AF_INET2:
437 return sizeof((struct sockaddr_in *)sa)->sin_addr.s_addr;
438 default:
439 log_print("sockaddr_addrlen: unsupported protocol family %d",
440 sa->sa_family);
441 return 0;
442 }
443}
444
445u_int8_t *
446sockaddr_addrdata(struct sockaddr *sa)
447{
448 switch (sa->sa_family) {
449 case AF_INET624:
450 return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr__u6_addr.__u6_addr8;
451 case AF_INET2:
452 return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr;
453 default:
454 log_print("sockaddr_addrdata: unsupported protocol family %d",
455 sa->sa_family);
456 return 0;
457 }
458}
459
460in_port_t
461sockaddr_port(struct sockaddr *sa)
462{
463 switch (sa->sa_family) {
464 case AF_INET624:
465 return ((struct sockaddr_in6 *)sa)->sin6_port;
466 case AF_INET2:
467 return ((struct sockaddr_in *)sa)->sin_port;
468 default:
469 log_print("sockaddr_port: unsupported protocol family %d",
470 sa->sa_family);
471 return 0;
472 }
473}
474
475/* Utility function used to set the port of a sockaddr. */
476void
477sockaddr_set_port(struct sockaddr *sa, in_port_t port)
478{
479 switch (sa->sa_family) {
480 case AF_INET2:
481 ((struct sockaddr_in *)sa)->sin_port = htons (port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
482 break;
483
484 case AF_INET624:
485 ((struct sockaddr_in6 *)sa)->sin6_port = htons (port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
486 break;
487 }
488}
489
490/*
491 * Convert network address to text. The network address does not need
492 * to be properly aligned.
493 */
494void
495util_ntoa(char **buf, int af, u_int8_t *addr)
496{
497 struct sockaddr_storage from;
498 struct sockaddr *sfrom = (struct sockaddr *) & from;
499 socklen_t fromlen = sizeof from;
500
501 bzero(&from, fromlen);
502 sfrom->sa_family = af;
503
504 switch (af) {
505 case AF_INET2:
506 sfrom->sa_len = sizeof(struct sockaddr_in);
507 break;
508 case AF_INET624:
509 sfrom->sa_len = sizeof(struct sockaddr_in6);
510 break;
511 }
512
513 memcpy(sockaddr_addrdata(sfrom), addr, sockaddr_addrlen(sfrom));
514
515 if (sockaddr2text(sfrom, buf, 0)) {
516 log_print("util_ntoa: could not make printable address out "
517 "of sockaddr %p", sfrom);
518 *buf = 0;
519 }
520}
521
522/*
523 * Perform sanity check on files containing secret information.
524 * Returns -1 on failure, 0 otherwise.
525 * Also, if FILE_SIZE is a not a null pointer, store file size here.
526 */
527
528int
529check_file_secrecy_fd(int fd, char *name, size_t *file_size)
530{
531 struct stat st;
532
533 if (fstat(fd, &st) == -1) {
534 log_error("check_file_secrecy: stat (\"%s\") failed", name);
535 return -1;
536 }
537 if (st.st_uid != 0 && st.st_uid != getuid()) {
538 log_print("check_file_secrecy_fd: "
539 "not loading %s - file owner is not process user", name);
540 errno(*__errno()) = EPERM1;
541 return -1;
542 }
543 if ((st.st_mode & (S_IRWXG0000070 | S_IRWXO0000007)) != 0) {
544 log_print("check_file_secrecy_fd: not loading %s - too open "
545 "permissions", name);
546 errno(*__errno()) = EPERM1;
547 return -1;
548 }
549 if (file_size)
550 *file_size = (size_t)st.st_size;
551
552 return 0;
553}
554
555/* Calculate timeout. Returns -1 on error. */
556long
557get_timeout(struct timespec *timeout)
558{
559 struct timespec now, result;
560
561 if (clock_gettime(CLOCK_MONOTONIC3, &now) == -1)
562 return -1;
563 timespecsub(timeout, &now, &result)do { (&result)->tv_sec = (timeout)->tv_sec - (&
now)->tv_sec; (&result)->tv_nsec = (timeout)->tv_nsec
- (&now)->tv_nsec; if ((&result)->tv_nsec <
0) { (&result)->tv_sec--; (&result)->tv_nsec +=
1000000000L; } } while (0)
;
564 return result.tv_sec;
565}
566
567int
568expand_string(char *label, size_t len, const char *srch, const char *repl)
569{
570 char *tmp;
571 char *p, *q;
572
573 if ((tmp = calloc(1, len)) == NULL((void *)0)) {
1
Memory is allocated
2
Assuming the condition is false
3
Taking false branch
574 log_error("expand_string: calloc");
575 return (-1);
576 }
577 p = q = label;
578 while ((q = strstr(p, srch)) != NULL((void *)0)) {
4
Assuming the condition is false
5
Loop condition is false. Execution continues on line 588
579 *q = '\0';
580 if ((strlcat(tmp, p, len) >= len) ||
581 (strlcat(tmp, repl, len) >= len)) {
582 log_print("expand_string: string too long");
583 return (-1);
584 }
585 q += strlen(srch);
586 p = q;
587 }
588 if (strlcat(tmp, p, len) >= len) {
6
Assuming the condition is true
7
Taking true branch
589 log_print("expand_string: string too long");
8
Potential leak of memory pointed to by 'tmp'
590 return (-1);
591 }
592 strlcpy(label, tmp, len); /* always fits */
593 free(tmp);
594
595 return (0);
596}