Bug Summary

File:src/libexec/ld.so/ldconfig/ldconfig.c
Warning:line 342, column 61
Division by zero

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 ldconfig.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/libexec/ld.so/ldconfig/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/libexec/ld.so/ldconfig -I /usr/src/libexec/ld.so/ldconfig/.. -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/libexec/ld.so/ldconfig/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/libexec/ld.so/ldconfig/ldconfig.c
1/* $OpenBSD: ldconfig.c,v 1.39 2021/10/24 21:24:20 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1993,1995 Paul Kranenburg
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Paul Kranenburg.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/mman.h>
36
37#include <dirent.h>
38#include <err.h>
39#include <errno(*__errno()).h>
40#include <fcntl.h>
41#include <ar.h>
42#include <ranlib.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47#include <limits.h>
48
49#include "ld.h"
50
51#undef majordewey[0]
52#undef minordewey[1]
53
54extern char *__progname;
55
56int verbose;
57static int nostd;
58static int justread;
59int merge;
60static int rescan;
61static int unconfig;
62
63struct shlib_list {
64 /* Internal list of shared libraries found */
65 char *name;
66 char *path;
67 int dewey[MAXDEWEY8];
68 int ndewey;
69#define majordewey[0] dewey[0]
70#define minordewey[1] dewey[1]
71 struct shlib_list *next;
72};
73
74static struct shlib_list *shlib_head = NULL((void *)0), **shlib_tail = &shlib_head;
75static char *dir_list;
76
77static void enter(char *, char *, char *, int *, int);
78static int dodir(char *, int);
79static int buildhints(void);
80static int readhints(void);
81static void listhints(void);
82
83static void
84usage(void)
85{
86 fprintf(stderr(&__sF[2]),
87 "usage: %s [-mRrsUv] [path ...]\n", __progname);
88 exit(1);
89}
90
91int
92main(int argc, char *argv[])
93{
94 int i, c;
95 int rval = 0;
96
97 if (pledge("stdio rpath wpath cpath tmppath fattr", NULL((void *)0)) == -1)
1
Assuming the condition is false
2
Taking false branch
98 err(1, "pledge");
99
100 while ((c = getopt(argc, argv, "DmPrRsSUv")) != -1) {
3
Assuming the condition is false
4
Loop condition is false. Execution continues on line 126
101 switch (c) {
102 case 'R':
103 rescan = 1;
104 break;
105 case 'U':
106 rescan = unconfig = 1;
107 break;
108 case 'm':
109 merge = 1;
110 break;
111 case 'r':
112 justread = 1;
113 break;
114 case 's':
115 nostd = 1;
116 break;
117 case 'v':
118 verbose = 1;
119 break;
120 default:
121 usage();
122 break;
123 }
124 }
125
126 if (unconfig && merge)
5
Assuming 'unconfig' is 0
127 errx(1, "cannot use -U with -m");
128
129 dir_list = xmalloc(1);
130 *dir_list = '\0';
131
132 if (justread || merge || rescan) {
6
Assuming 'justread' is 0
7
Assuming 'merge' is 0
8
Assuming 'rescan' is 0
9
Taking false branch
133 if ((rval = readhints()) != 0)
134 return rval;
135 if (justread) {
136 listhints();
137 return 0;
138 }
139 add_search_path(dir_list);
140 dir_list = xrealloc(dir_list, 1);
141 *dir_list = '\0';
142 } else if (!nostd)
10
Assuming 'nostd' is not equal to 0
11
Taking false branch
143 std_search_path();
144
145 if (unconfig) {
12
Assuming 'unconfig' is 0
13
Taking false branch
146 if (optind < argc)
147 for (i = optind; i < argc; i++)
148 remove_search_dir(argv[i]);
149 else {
150 i = 0;
151 while (i < n_search_dirs) {
152 if (access(search_dirs[i], R_OK0x04) < 0)
153 remove_search_dir(search_dirs[i]);
154 else
155 i++;
156 }
157 }
158 } else
159 for (i = optind; i < argc; i++)
14
Assuming 'i' is >= 'argc'
15
Loop condition is false. Execution continues on line 162
160 add_search_dir(argv[i]);
161
162 for (i = 0; i < n_search_dirs; i++) {
16
Assuming 'i' is < 'n_search_dirs'
17
Loop condition is true. Entering loop body
19
Assuming 'i' is >= 'n_search_dirs'
20
Loop condition is false. Execution continues on line 170
163 char *cp = concat(dir_list, *dir_list?":":"", search_dirs[i]);
18
'?' condition is false
164
165 free(dir_list);
166 dir_list = cp;
167 rval |= dodir(search_dirs[i], 0);
168 }
169
170 rval |= buildhints();
21
Calling 'buildhints'
171
172 return rval;
173}
174
175int
176dodir(char *dir, int silent)
177{
178 DIR *dd;
179 struct dirent *dp;
180 char name[PATH_MAX1024];
181 int dewey[MAXDEWEY8], ndewey;
182
183 if ((dd = opendir(dir)) == NULL((void *)0)) {
184 if (!silent || errno(*__errno()) != ENOENT2)
185 warn("%s", dir);
186 return -1;
187 }
188
189 while ((dp = readdir(dd)) != NULL((void *)0)) {
190 size_t n;
191 char *cp;
192
193 /* Check for `lib' prefix */
194 if (dp->d_name[0] != 'l' ||
195 dp->d_name[1] != 'i' ||
196 dp->d_name[2] != 'b')
197 continue;
198
199 /* Copy the entry minus prefix */
200 (void)strlcpy(name, dp->d_name + 3, sizeof name);
201 n = strlen(name);
202 if (n < 4)
203 continue;
204
205 /* Find ".so." in name */
206 for (cp = name + n - 4; cp > name; --cp) {
207 if (cp[0] == '.' &&
208 cp[1] == 's' &&
209 cp[2] == 'o' &&
210 cp[3] == '.')
211 break;
212 }
213 if (cp <= name)
214 continue;
215
216 *cp = '\0';
217
218 bzero((caddr_t)dewey, sizeof(dewey));
219 ndewey = getdewey(dewey, cp + 3);
220 if (ndewey > 0)
221 enter(dir, dp->d_name, name, dewey, ndewey);
222 }
223 closedir(dd);
224 return 0;
225}
226
227static void
228enter(char *dir, char *file, char *name, int dewey[], int ndewey)
229{
230 struct shlib_list *shp;
231
232 for (shp = shlib_head; shp; shp = shp->next) {
233 if (strcmp(name, shp->name) != 0 || majordewey[0] != shp->majordewey[0])
234 continue;
235
236 /* Name matches existing entry */
237 if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
238
239 /* Update this entry with higher versioned lib */
240 if (verbose)
241 printf("Updating lib%s.%d.%d to %s/%s\n",
242 shp->name, shp->majordewey[0], shp->minordewey[1],
243 dir, file);
244
245 free(shp->name);
246 shp->name = xstrdup(name);
247 free(shp->path);
248 shp->path = concat(dir, "/", file);
249 bcopy(dewey, shp->dewey, sizeof(shp->dewey));
250 shp->ndewey = ndewey;
251 }
252 break;
253 }
254
255 if (shp)
256 /* Name exists: older version or just updated */
257 return;
258
259 /* Allocate new list element */
260 if (verbose)
261 printf("Adding %s/%s\n", dir, file);
262
263 shp = (struct shlib_list *)xmalloc(sizeof *shp);
264 shp->name = xstrdup(name);
265 shp->path = concat(dir, "/", file);
266 bcopy(dewey, shp->dewey, sizeof(shp->dewey));
267 shp->ndewey = ndewey;
268 shp->next = NULL((void *)0);
269
270 *shlib_tail = shp;
271 shlib_tail = &shp->next;
272}
273
274
275#if DEBUG
276/* test */
277#undef _PATH_LD_HINTS"/var/run/ld.so.hints"
278#define _PATH_LD_HINTS"/var/run/ld.so.hints" "./ld.so.hints"
279#endif
280
281static int
282hinthash(char *cp, int vmajor, int vminor)
283{
284 int k = 0;
285
286 while (*cp)
287 k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
288
289 k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
290#if 0
291 k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
292#endif
293
294 return k;
295}
296
297int
298buildhints(void)
299{
300 int strtab_sz = 0, nhints = 0, fd = -1, i, ret = -1, str_index = 0;
301 struct hints_bucket *blist;
302 struct hints_header hdr;
303 struct shlib_list *shp;
304 char *strtab, *tmpfilenam;
305 size_t n;
306
307 for (shp = shlib_head; shp; shp = shp->next) {
22
Loop condition is false. Execution continues on line 314
308 strtab_sz += 1 + strlen(shp->name);
309 strtab_sz += 1 + strlen(shp->path);
310 nhints++;
311 }
312
313 /* Fill hints file header */
314 hdr.hh_magic = HH_MAGIC011421044151;
315 hdr.hh_version = LD_HINTS_VERSION_22;
316 hdr.hh_nbucket = 1 * nhints;
23
The value 0 is assigned to 'hdr.hh_nbucket'
317 n = hdr.hh_nbucket * sizeof(struct hints_bucket);
318 hdr.hh_hashtab = sizeof(struct hints_header);
319 hdr.hh_strtab = hdr.hh_hashtab + n;
320 hdr.hh_dirlist = strtab_sz;
321 strtab_sz += 1 + strlen(dir_list);
322 hdr.hh_strtab_sz = strtab_sz;
323 hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
324
325 if (verbose)
24
Assuming 'verbose' is 0
25
Taking false branch
326 printf("Totals: entries %d, buckets %ld, string size %d\n",
327 nhints, hdr.hh_nbucket, strtab_sz);
328
329 /* Allocate buckets and string table */
330 blist = (struct hints_bucket *)xmalloc(n);
331 bzero(blist, n);
332 for (i = 0; i < hdr.hh_nbucket; i++)
26
Loop condition is false. Execution continues on line 336
333 /* Empty all buckets */
334 blist[i].hi_next = -1;
335
336 strtab = xmalloc(strtab_sz);
337
338 /* Enter all */
339 for (shp = shlib_head; shp; shp = shp->next) {
27
Loop condition is true. Entering loop body
340 struct hints_bucket *bp;
341
342 bp = blist + (hinthash(shp->name, shp->majordewey[0], shp->minordewey[1]) %
28
Division by zero
343 hdr.hh_nbucket);
344
345 if (bp->hi_pathx) {
346 int j;
347
348 for (j = 0; j < hdr.hh_nbucket; j++) {
349 if (blist[j].hi_pathx == 0)
350 break;
351 }
352 if (j == hdr.hh_nbucket) {
353 warnx("Bummer!");
354 goto out;
355 }
356 while (bp->hi_next != -1)
357 bp = &blist[bp->hi_next];
358 bp->hi_next = j;
359 bp = blist + j;
360 }
361
362 /* Insert strings in string table */
363 bp->hi_namex = str_index;
364 strlcpy(strtab + str_index, shp->name, strtab_sz - str_index);
365 str_index += 1 + strlen(shp->name);
366
367 bp->hi_pathx = str_index;
368 strlcpy(strtab + str_index, shp->path, strtab_sz - str_index);
369 str_index += 1 + strlen(shp->path);
370
371 /* Copy versions */
372 bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
373 bp->hi_ndewey = shp->ndewey;
374 }
375
376 /* Copy search directories */
377 strlcpy(strtab + str_index, dir_list, strtab_sz - str_index);
378 str_index += 1 + strlen(dir_list);
379
380 /* Sanity check */
381 if (str_index != strtab_sz)
382 errx(1, "str_index(%d) != strtab_sz(%d)", str_index, strtab_sz);
383
384 tmpfilenam = concat(_PATH_LD_HINTS"/var/run/ld.so.hints", ".XXXXXXXXXX", "");
385 if ((fd = mkstemp(tmpfilenam)) == -1) {
386 warn("%s", tmpfilenam);
387 goto out;
388 }
389 if (fchmod(fd, 0444) == -1) {
390 warn("%s: failed to change mode", tmpfilenam);
391 goto out;
392 }
393
394 if (write(fd, &hdr, sizeof(struct hints_header)) !=
395 sizeof(struct hints_header)) {
396 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
397 goto out;
398 }
399 if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) !=
400 hdr.hh_nbucket * sizeof(struct hints_bucket)) {
401 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
402 goto out;
403 }
404 if (write(fd, strtab, strtab_sz) != strtab_sz) {
405 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
406 goto out;
407 }
408
409 if (rename(tmpfilenam, _PATH_LD_HINTS"/var/run/ld.so.hints") != 0) {
410 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
411 goto out;
412 }
413
414 ret = 0;
415out:
416 if (fd != -1)
417 close(fd);
418 free(blist);
419 free(strtab);
420 return (ret);
421}
422
423static int
424readhints(void)
425{
426 struct stat sb;
427 struct hints_bucket *blist;
428 struct hints_header *hdr;
429 struct shlib_list *shp;
430 caddr_t addr;
431 char *strtab;
432 long msize;
433 int fd, i;
434
435 if ((fd = open(_PATH_LD_HINTS"/var/run/ld.so.hints", O_RDONLY0x0000)) == -1) {
436 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
437 return -1;
438 }
439 if (fstat(fd, &sb) != 0 || !S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000) ||
440 sb.st_size < sizeof(struct hints_header) || sb.st_size > LONG_MAX9223372036854775807L) {
441 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
442 return -1;
443 }
444
445 msize = (long)sb.st_size;
446 addr = mmap(0, msize, PROT_READ0x01, MAP_PRIVATE0x0002, fd, 0);
447
448 if (addr == MAP_FAILED((void *)-1)) {
449 warn("%s", _PATH_LD_HINTS"/var/run/ld.so.hints");
450 return -1;
451 }
452
453 hdr = (struct hints_header *)addr;
454 if (HH_BADMAG(*hdr)((*hdr).hh_magic != 011421044151)) {
455 warnx("%s: Bad magic: %lo",
456 _PATH_LD_HINTS"/var/run/ld.so.hints", hdr->hh_magic);
457 return -1;
458 }
459
460 if (hdr->hh_ehints > msize) {
461 warnx("%s: hintsize greater than filesize: 0x%lx > 0x%lx ",
462 _PATH_LD_HINTS"/var/run/ld.so.hints", hdr->hh_ehints, msize);
463 return -1;
464 }
465
466 if (hdr->hh_version != LD_HINTS_VERSION_22) {
467 warnx("Unsupported version: %ld", hdr->hh_version);
468 return -1;
469 }
470
471 close(fd);
472
473 blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
474 strtab = (char *)(addr + hdr->hh_strtab);
475
476 dir_list = xstrdup(strtab + hdr->hh_dirlist);
477
478 if (rescan)
479 return (0);
480
481 for (i = 0; i < hdr->hh_nbucket; i++) {
482 struct hints_bucket *bp = &blist[i];
483
484 /* Sanity check */
485 if (bp->hi_namex >= hdr->hh_strtab_sz) {
486 warnx("Bad name index: %#x", bp->hi_namex);
487 return -1;
488 }
489 if (bp->hi_pathx >= hdr->hh_strtab_sz) {
490 warnx("Bad path index: %#x", bp->hi_pathx);
491 return -1;
492 }
493
494 /* Allocate new list element */
495 shp = (struct shlib_list *)xmalloc(sizeof *shp);
496 shp->name = xstrdup(strtab + bp->hi_namex);
497 shp->path = xstrdup(strtab + bp->hi_pathx);
498 bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey));
499 shp->ndewey = bp->hi_ndewey;
500 shp->next = NULL((void *)0);
501
502 *shlib_tail = shp;
503 shlib_tail = &shp->next;
504 }
505 return 0;
506}
507
508static void
509listhints(void)
510{
511 struct shlib_list *shp;
512 int i;
513
514 printf("%s:\n", _PATH_LD_HINTS"/var/run/ld.so.hints");
515 printf("\tsearch directories: %s\n", dir_list);
516
517 for (i = 0, shp = shlib_head; shp; i++, shp = shp->next)
518 printf("\t%d:-l%s.%d.%d => %s\n",
519 i, shp->name, shp->majordewey[0], shp->minordewey[1], shp->path);
520}