Bug Summary

File:src/usr.bin/file/file.c
Warning:line 680, column 3
Value stored to 'stop' is never read

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 file.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.bin/file/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/file/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.bin/file/file.c
1/* $OpenBSD: file.c,v 1.69 2019/11/30 14:01:45 mestre Exp $ */
2
3/*
4 * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/mman.h>
22#include <sys/queue.h>
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/uio.h>
26#include <sys/wait.h>
27
28#include <err.h>
29#include <errno(*__errno()).h>
30#include <fcntl.h>
31#include <getopt.h>
32#include <imsg.h>
33#include <libgen.h>
34#include <limits.h>
35#include <pwd.h>
36#include <stdlib.h>
37#include <string.h>
38#include <time.h>
39#include <unistd.h>
40
41#include "file.h"
42#include "magic.h"
43#include "xmalloc.h"
44
45struct input_msg {
46 int idx;
47
48 struct stat sb;
49 int error;
50
51 char link_path[PATH_MAX1024];
52 int link_error;
53 int link_target;
54};
55
56struct input_ack {
57 int idx;
58};
59
60struct input_file {
61 struct magic *m;
62 struct input_msg *msg;
63
64 const char *path;
65 int fd;
66
67 void *base;
68 size_t size;
69 int mapped;
70 char *result;
71};
72
73extern char *__progname;
74
75__dead__attribute__((__noreturn__)) void usage(void);
76
77static int prepare_message(struct input_msg *, int, const char *);
78static void send_message(struct imsgbuf *, void *, size_t, int);
79static int read_message(struct imsgbuf *, struct imsg *, pid_t);
80
81static void read_link(struct input_msg *, const char *);
82
83static __dead__attribute__((__noreturn__)) void child(int, pid_t, int, char **);
84
85static void test_file(struct input_file *, size_t);
86
87static int try_stat(struct input_file *);
88static int try_empty(struct input_file *);
89static int try_access(struct input_file *);
90static int try_text(struct input_file *);
91static int try_magic(struct input_file *);
92static int try_unknown(struct input_file *);
93
94static int bflag;
95static int cflag;
96static int iflag;
97static int Lflag;
98static int sflag;
99static int Wflag;
100
101static char *magicpath;
102static FILE *magicfp;
103
104static struct option longopts[] = {
105 { "brief", no_argument0, NULL((void *)0), 'b' },
106 { "dereference", no_argument0, NULL((void *)0), 'L' },
107 { "mime", no_argument0, NULL((void *)0), 'i' },
108 { "mime-type", no_argument0, NULL((void *)0), 'i' },
109 { NULL((void *)0), 0, NULL((void *)0), 0 }
110};
111
112__dead__attribute__((__noreturn__)) void
113usage(void)
114{
115 fprintf(stderr(&__sF[2]), "usage: %s [-bchiLsW] file ...\n", __progname);
116 exit(1);
117}
118
119int
120main(int argc, char **argv)
121{
122 int opt, pair[2], fd, idx;
123 char *home;
124 struct passwd *pw;
125 struct imsgbuf ibuf;
126 struct imsg imsg;
127 struct input_msg msg;
128 struct input_ack *ack;
129 pid_t pid, parent;
130
131 tzset();
132
133 for (;;) {
134 opt = getopt_long(argc, argv, "bchiLsW", longopts, NULL((void *)0));
135 if (opt == -1)
136 break;
137 switch (opt) {
138 case 'b':
139 bflag = 1;
140 break;
141 case 'c':
142 cflag = 1;
143 break;
144 case 'h':
145 Lflag = 0;
146 break;
147 case 'i':
148 iflag = 1;
149 break;
150 case 'L':
151 Lflag = 1;
152 break;
153 case 's':
154 sflag = 1;
155 break;
156 case 'W':
157 Wflag = 1;
158 break;
159 default:
160 usage();
161 }
162 }
163 argc -= optind;
164 argv += optind;
165 if (cflag) {
166 if (argc != 0)
167 usage();
168 } else if (argc == 0)
169 usage();
170
171 if (pledge("stdio rpath getpw recvfd sendfd id proc", NULL((void *)0)) == -1)
172 err(1, "pledge");
173
174 magicfp = NULL((void *)0);
175 if (geteuid() != 0 && !issetugid()) {
176 home = getenv("HOME");
177 if (home == NULL((void *)0) || *home == '\0') {
178 pw = getpwuid(getuid());
179 if (pw != NULL((void *)0))
180 home = pw->pw_dir;
181 else
182 home = NULL((void *)0);
183 }
184 if (home != NULL((void *)0)) {
185 xasprintf(&magicpath, "%s/.magic", home);
186 magicfp = fopen(magicpath, "r");
187 if (magicfp == NULL((void *)0))
188 free(magicpath);
189 }
190 }
191 if (magicfp == NULL((void *)0)) {
192 magicpath = xstrdup("/etc/magic");
193 magicfp = fopen(magicpath, "r");
194 }
195 if (magicfp == NULL((void *)0))
196 err(1, "%s", magicpath);
197
198 parent = getpid();
199 if (socketpair(AF_UNIX1, SOCK_STREAM1, PF_UNSPEC0, pair) != 0)
200 err(1, "socketpair");
201 switch (pid = fork()) {
202 case -1:
203 err(1, "fork");
204 case 0:
205 close(pair[0]);
206 child(pair[1], parent, argc, argv);
207 }
208 close(pair[1]);
209
210 if (pledge("stdio rpath sendfd", NULL((void *)0)) == -1)
211 err(1, "pledge");
212
213 fclose(magicfp);
214 magicfp = NULL((void *)0);
215
216 if (cflag)
217 goto wait_for_child;
218
219 imsg_init(&ibuf, pair[0]);
220 for (idx = 0; idx < argc; idx++) {
221 fd = prepare_message(&msg, idx, argv[idx]);
222 send_message(&ibuf, &msg, sizeof msg, fd);
223
224 if (read_message(&ibuf, &imsg, pid) == 0)
225 break;
226 if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof *ack)
227 errx(1, "message too small");
228 ack = imsg.data;
229 if (ack->idx != idx)
230 errx(1, "index not expected");
231 imsg_free(&imsg);
232 }
233
234wait_for_child:
235 close(pair[0]);
236 while (wait(NULL((void *)0)) == -1 && errno(*__errno()) != ECHILD10) {
237 if (errno(*__errno()) != EINTR4)
238 err(1, "wait");
239 }
240 _exit(0); /* let the child flush */
241}
242
243static int
244prepare_message(struct input_msg *msg, int idx, const char *path)
245{
246 int fd, mode, error;
247
248 memset(msg, 0, sizeof *msg);
249 msg->idx = idx;
250
251 if (strcmp(path, "-") == 0) {
252 if (fstat(STDIN_FILENO0, &msg->sb) == -1) {
253 msg->error = errno(*__errno());
254 return (-1);
255 }
256 return (STDIN_FILENO0);
257 }
258
259 if (Lflag)
260 error = stat(path, &msg->sb);
261 else
262 error = lstat(path, &msg->sb);
263 if (error == -1) {
264 msg->error = errno(*__errno());
265 return (-1);
266 }
267
268 /*
269 * pledge(2) doesn't let us pass directory file descriptors around -
270 * but in fact we don't need them, so just don't open directories or
271 * symlinks (which could be to directories).
272 */
273 mode = msg->sb.st_mode;
274 if (!S_ISDIR(mode)((mode & 0170000) == 0040000) && !S_ISLNK(mode)((mode & 0170000) == 0120000)) {
275 fd = open(path, O_RDONLY0x0000|O_NONBLOCK0x0004);
276 if (fd == -1 && (errno(*__errno()) == ENFILE23 || errno(*__errno()) == EMFILE24))
277 err(1, "open");
278 } else
279 fd = -1;
280 if (S_ISLNK(mode)((mode & 0170000) == 0120000))
281 read_link(msg, path);
282 return (fd);
283
284}
285
286static void
287send_message(struct imsgbuf *ibuf, void *msg, size_t msglen, int fd)
288{
289 if (imsg_compose(ibuf, -1, -1, 0, fd, msg, msglen) != 1)
290 err(1, "imsg_compose");
291 if (imsg_flush(ibuf) != 0)
292 err(1, "imsg_flush");
293}
294
295static int
296read_message(struct imsgbuf *ibuf, struct imsg *imsg, pid_t from)
297{
298 int n;
299
300 while ((n = imsg_read(ibuf)) == -1 && errno(*__errno()) == EAGAIN35)
301 /* nothing */ ;
302 if (n == -1)
303 err(1, "imsg_read");
304 if (n == 0)
305 return (0);
306
307 if ((n = imsg_get(ibuf, imsg)) == -1)
308 err(1, "imsg_get");
309 if (n == 0)
310 return (0);
311
312 if ((pid_t)imsg->hdr.pid != from)
313 errx(1, "PIDs don't match");
314
315 return (n);
316
317}
318
319static void
320read_link(struct input_msg *msg, const char *path)
321{
322 struct stat sb;
323 char lpath[PATH_MAX1024];
324 char *copy, *root;
325 int used;
326 ssize_t size;
327
328 size = readlink(path, lpath, sizeof lpath - 1);
329 if (size == -1) {
330 msg->link_error = errno(*__errno());
331 return;
332 }
333 lpath[size] = '\0';
334
335 if (*lpath == '/')
336 strlcpy(msg->link_path, lpath, sizeof msg->link_path);
337 else {
338 copy = xstrdup(path);
339
340 root = dirname(copy);
341 if (*root == '\0' || strcmp(root, ".") == 0 ||
342 strcmp (root, "/") == 0)
343 strlcpy(msg->link_path, lpath, sizeof msg->link_path);
344 else {
345 used = snprintf(msg->link_path, sizeof msg->link_path,
346 "%s/%s", root, lpath);
347 if (used < 0 || (size_t)used >= sizeof msg->link_path) {
348 msg->link_error = ENAMETOOLONG63;
349 free(copy);
350 return;
351 }
352 }
353
354 free(copy);
355 }
356
357 if (!Lflag && stat(path, &sb) == -1)
358 msg->link_target = errno(*__errno());
359}
360
361static __dead__attribute__((__noreturn__)) void
362child(int fd, pid_t parent, int argc, char **argv)
363{
364 struct passwd *pw;
365 struct magic *m;
366 struct imsgbuf ibuf;
367 struct imsg imsg;
368 struct input_msg *msg;
369 struct input_ack ack;
370 struct input_file inf;
371 int i, idx;
372 size_t len, width = 0;
373
374 if (pledge("stdio getpw recvfd id", NULL((void *)0)) == -1)
375 err(1, "pledge");
376
377 if (geteuid() == 0) {
378 pw = getpwnam(FILE_USER"_file");
379 if (pw == NULL((void *)0))
380 errx(1, "unknown user %s", FILE_USER"_file");
381 if (setgroups(1, &pw->pw_gid) != 0)
382 err(1, "setgroups");
383 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
384 err(1, "setresgid");
385 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
386 err(1, "setresuid");
387 }
388
389 if (pledge("stdio recvfd", NULL((void *)0)) == -1)
390 err(1, "pledge");
391
392 m = magic_load(magicfp, magicpath, cflag || Wflag);
393 if (cflag) {
394 magic_dump(m);
395 exit(0);
396 }
397
398 for (i = 0; i < argc; i++) {
399 len = strlen(argv[i]) + 1;
400 if (len > width)
401 width = len;
402 }
403
404 imsg_init(&ibuf, fd);
405 for (;;) {
406 if (read_message(&ibuf, &imsg, parent) == 0)
407 break;
408 if (imsg.hdr.len != IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + sizeof *msg)
409 errx(1, "message too small");
410 msg = imsg.data;
411
412 idx = msg->idx;
413 if (idx < 0 || idx >= argc)
414 errx(1, "index out of range");
415
416 memset(&inf, 0, sizeof inf);
417 inf.m = m;
418 inf.msg = msg;
419
420 inf.path = argv[idx];
421 inf.fd = imsg.fd;
422
423 test_file(&inf, width);
424
425 if (imsg.fd != -1)
426 close(imsg.fd);
427 imsg_free(&imsg);
428
429 ack.idx = idx;
430 send_message(&ibuf, &ack, sizeof ack, -1);
431 }
432 exit(0);
433}
434
435static void *
436fill_buffer(int fd, size_t size, size_t *used)
437{
438 static void *buffer;
439 ssize_t got;
440 size_t left;
441 void *next;
442
443 if (buffer == NULL((void *)0))
444 buffer = xmalloc(FILE_READ_SIZE(256 * 1024));
445
446 next = buffer;
447 left = size;
448 while (left != 0) {
449 got = read(fd, next, left);
450 if (got == -1) {
451 if (errno(*__errno()) == EINTR4)
452 continue;
453 return (NULL((void *)0));
454 }
455 if (got == 0)
456 break;
457 next = (char *)next + got;
458 left -= got;
459 }
460 *used = size - left;
461 return (buffer);
462}
463
464static int
465load_file(struct input_file *inf)
466{
467 size_t used;
468
469 if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode)((inf->msg->sb.st_mode & 0170000) == 0100000))
470 return (0); /* empty file */
471 if (inf->msg->sb.st_size == 0 || inf->msg->sb.st_size > FILE_READ_SIZE(256 * 1024))
472 inf->size = FILE_READ_SIZE(256 * 1024);
473 else
474 inf->size = inf->msg->sb.st_size;
475
476 if (!S_ISREG(inf->msg->sb.st_mode)((inf->msg->sb.st_mode & 0170000) == 0100000))
477 goto try_read;
478
479 inf->base = mmap(NULL((void *)0), inf->size, PROT_READ0x01, MAP_PRIVATE0x0002, inf->fd, 0);
480 if (inf->base == MAP_FAILED((void *)-1))
481 goto try_read;
482 inf->mapped = 1;
483 return (0);
484
485try_read:
486 inf->base = fill_buffer(inf->fd, inf->size, &used);
487 if (inf->base == NULL((void *)0)) {
488 xasprintf(&inf->result, "cannot read '%s' (%s)", inf->path,
489 strerror(errno(*__errno())));
490 return (1);
491 }
492 inf->size = used;
493 return (0);
494}
495
496static int
497try_stat(struct input_file *inf)
498{
499 if (inf->msg->error != 0) {
500 xasprintf(&inf->result, "cannot stat '%s' (%s)", inf->path,
501 strerror(inf->msg->error));
502 return (1);
503 }
504 if (sflag || strcmp(inf->path, "-") == 0) {
505 switch (inf->msg->sb.st_mode & S_IFMT0170000) {
506 case S_IFIFO0010000:
507 if (strcmp(inf->path, "-") != 0)
508 break;
509 case S_IFBLK0060000:
510 case S_IFCHR0020000:
511 case S_IFREG0100000:
512 return (0);
513 }
514 }
515
516 if (iflag && (inf->msg->sb.st_mode & S_IFMT0170000) != S_IFREG0100000) {
517 xasprintf(&inf->result, "application/x-not-regular-file");
518 return (1);
519 }
520
521 switch (inf->msg->sb.st_mode & S_IFMT0170000) {
522 case S_IFDIR0040000:
523 xasprintf(&inf->result, "directory");
524 return (1);
525 case S_IFLNK0120000:
526 if (inf->msg->link_error != 0) {
527 xasprintf(&inf->result, "unreadable symlink '%s' (%s)",
528 inf->path, strerror(inf->msg->link_error));
529 return (1);
530 }
531 if (inf->msg->link_target == ELOOP62)
532 xasprintf(&inf->result, "symbolic link in a loop");
533 else if (inf->msg->link_target != 0) {
534 xasprintf(&inf->result, "broken symbolic link to '%s'",
535 inf->msg->link_path);
536 } else {
537 xasprintf(&inf->result, "symbolic link to '%s'",
538 inf->msg->link_path);
539 }
540 return (1);
541 case S_IFSOCK0140000:
542 xasprintf(&inf->result, "socket");
543 return (1);
544 case S_IFBLK0060000:
545 xasprintf(&inf->result, "block special (%lu/%lu)",
546 (long)major(inf->msg->sb.st_rdev)(((unsigned)(inf->msg->sb.st_rdev) >> 8) & 0xff
)
,
547 (long)minor(inf->msg->sb.st_rdev)((unsigned)((inf->msg->sb.st_rdev) & 0xff) | (((inf
->msg->sb.st_rdev) & 0xffff0000) >> 8))
);
548 return (1);
549 case S_IFCHR0020000:
550 xasprintf(&inf->result, "character special (%lu/%lu)",
551 (long)major(inf->msg->sb.st_rdev)(((unsigned)(inf->msg->sb.st_rdev) >> 8) & 0xff
)
,
552 (long)minor(inf->msg->sb.st_rdev)((unsigned)((inf->msg->sb.st_rdev) & 0xff) | (((inf
->msg->sb.st_rdev) & 0xffff0000) >> 8))
);
553 return (1);
554 case S_IFIFO0010000:
555 xasprintf(&inf->result, "fifo (named pipe)");
556 return (1);
557 }
558 return (0);
559}
560
561static int
562try_empty(struct input_file *inf)
563{
564 if (inf->size != 0)
565 return (0);
566
567 if (iflag)
568 xasprintf(&inf->result, "application/x-empty");
569 else
570 xasprintf(&inf->result, "empty");
571 return (1);
572}
573
574static int
575try_access(struct input_file *inf)
576{
577 char tmp[256] = "";
578
579 if (inf->msg->sb.st_size == 0 && S_ISREG(inf->msg->sb.st_mode)((inf->msg->sb.st_mode & 0170000) == 0100000))
580 return (0); /* empty file */
581 if (inf->fd != -1)
582 return (0);
583
584 if (inf->msg->sb.st_mode & (S_IWUSR0000200|S_IWGRP0000020|S_IWOTH0000002))
585 strlcat(tmp, "writable, ", sizeof tmp);
586 if (inf->msg->sb.st_mode & (S_IXUSR0000100|S_IXGRP0000010|S_IXOTH0000001))
587 strlcat(tmp, "executable, ", sizeof tmp);
588 if (S_ISREG(inf->msg->sb.st_mode)((inf->msg->sb.st_mode & 0170000) == 0100000))
589 strlcat(tmp, "regular file, ", sizeof tmp);
590 strlcat(tmp, "no read permission", sizeof tmp);
591
592 inf->result = xstrdup(tmp);
593 return (1);
594}
595
596static int
597try_text(struct input_file *inf)
598{
599 const char *type, *s;
600 int flags;
601
602 flags = MAGIC_TEST_TEXT0x1;
603 if (iflag)
604 flags |= MAGIC_TEST_MIME0x2;
605
606 type = text_get_type(inf->base, inf->size);
607 if (type == NULL((void *)0))
608 return (0);
609
610 s = magic_test(inf->m, inf->base, inf->size, flags);
611 if (s != NULL((void *)0)) {
612 inf->result = xstrdup(s);
613 return (1);
614 }
615
616 s = text_try_words(inf->base, inf->size, flags);
617 if (s != NULL((void *)0)) {
618 if (iflag)
619 inf->result = xstrdup(s);
620 else
621 xasprintf(&inf->result, "%s %s text", type, s);
622 return (1);
623 }
624
625 if (iflag)
626 inf->result = xstrdup("text/plain");
627 else
628 xasprintf(&inf->result, "%s text", type);
629 return (1);
630}
631
632static int
633try_magic(struct input_file *inf)
634{
635 const char *s;
636 int flags;
637
638 flags = 0;
639 if (iflag)
640 flags |= MAGIC_TEST_MIME0x2;
641
642 s = magic_test(inf->m, inf->base, inf->size, flags);
643 if (s != NULL((void *)0)) {
644 inf->result = xstrdup(s);
645 return (1);
646 }
647 return (0);
648}
649
650static int
651try_unknown(struct input_file *inf)
652{
653 if (iflag)
654 xasprintf(&inf->result, "application/octet-stream");
655 else
656 xasprintf(&inf->result, "data");
657 return (1);
658}
659
660static void
661test_file(struct input_file *inf, size_t width)
662{
663 char *label;
664 int stop;
665
666 stop = 0;
667 if (!stop)
668 stop = try_stat(inf);
669 if (!stop)
670 stop = try_access(inf);
671 if (!stop)
672 stop = load_file(inf);
673 if (!stop)
674 stop = try_empty(inf);
675 if (!stop)
676 stop = try_magic(inf);
677 if (!stop)
678 stop = try_text(inf);
679 if (!stop)
680 stop = try_unknown(inf);
Value stored to 'stop' is never read
681
682 if (bflag)
683 printf("%s\n", inf->result);
684 else {
685 if (strcmp(inf->path, "-") == 0)
686 xasprintf(&label, "/dev/stdin:");
687 else
688 xasprintf(&label, "%s:", inf->path);
689 printf("%-*s %s\n", (int)width, label, inf->result);
690 free(label);
691 }
692 free(inf->result);
693
694 if (inf->mapped && inf->base != NULL((void *)0))
695 munmap(inf->base, inf->size);
696}