Bug Summary

File:src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/boot/cmd.c
Warning:line 371, column 2
2nd function call argument is an uninitialized value

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 cmd.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 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -disable-red-zone -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/stand/efiboot/bootx64/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/efi/include/amd64 -D EFIBOOT -D FWRANDOM -D NEEDS_HEAP_H -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/.. -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/efi/include -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/boot -D SOFTRAID -D _STANDALONE -D MDRANDOM -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/efi/include/amd64 -D EFIBOOT -D FWRANDOM -D NEEDS_HEAP_H -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/.. -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/efi/include -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/boot -D SOFTRAID -D _STANDALONE -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../.. -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../libsa -I . -I /usr/src/sys/arch/amd64/stand/efiboot/bootx64 -D SMALL -D SLOW -D NOBYFOUR -D __INTERNAL_LIBSA_CREAD -D HEAP_LIMIT=0xc00000 -D HIBERNATE -Oz -Wno-pointer-sign -std=gnu99 -fdebug-compilation-dir=/usr/src/sys/arch/amd64/stand/efiboot/bootx64/obj -ferror-limit 19 -fwrapv -fno-builtin -fwchar-type=short -fno-signed-wchar -fgnuc-version=4.2.1 -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 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sys/arch/amd64/stand/efiboot/bootx64/../../../../../stand/boot/cmd.c
1/* $OpenBSD: cmd.c,v 1.68 2021/10/24 17:49:19 deraadt Exp $ */
2
3/*
4 * Copyright (c) 1997-1999 Michael Shalayeff
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/reboot.h>
31
32#include <libsa.h>
33#include <lib/libkern/funcs.h>
34
35#include "cmd.h"
36
37#define CTRL(c)((c)&0x1f) ((c)&0x1f)
38
39static int Xboot(void);
40static int Xecho(void);
41static int Xhelp(void);
42static int Xhexdump(void);
43static int Xls(void);
44static int Xnop(void);
45static int Xreboot(void);
46static int Xstty(void);
47static int Xtime(void);
48#ifdef MACHINE_CMDcmd_machine
49static int Xmachine(void);
50extern const struct cmd_table MACHINE_CMDcmd_machine[];
51#endif
52extern int Xset(void);
53extern int Xenv(void);
54
55#ifdef CHECK_SKIP_CONFcheck_skip_conf
56extern int CHECK_SKIP_CONFcheck_skip_conf(void);
57#endif
58
59extern const struct cmd_table cmd_set[];
60const struct cmd_table cmd_table[] = {
61 {"#", CMDT_CMD0, Xnop}, /* XXX must be first */
62 {"boot", CMDT_CMD0, Xboot},
63 {"echo", CMDT_CMD0, Xecho},
64 {"env", CMDT_CMD0, Xenv},
65 {"help", CMDT_CMD0, Xhelp},
66 {"hexdump",CMDT_CMD0, Xhexdump},
67 {"ls", CMDT_CMD0, Xls},
68#ifdef MACHINE_CMDcmd_machine
69 {"machine",CMDT_MDC3, Xmachine},
70#endif
71 {"reboot", CMDT_CMD0, Xreboot},
72 {"set", CMDT_SET2, Xset},
73 {"stty", CMDT_CMD0, Xstty},
74 {"time", CMDT_CMD0, Xtime},
75 {NULL((void *)0), 0},
76};
77
78static void ls(char *, struct stat *);
79static int readline(char *, size_t, int);
80char *nextword(char *);
81static char *whatcmd(const struct cmd_table **ct, char *);
82static char *qualify(char *);
83
84char cmd_buf[CMD_BUFF_SIZE133];
85
86int
87getcmd(void)
88{
89 cmd.cmd = NULL((void *)0);
90
91 if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout))
92 cmd.cmd = cmd_table;
93
94 return docmd();
95}
96
97int
98read_conf(void)
99{
100#ifndef INSECURE
101 struct stat sb;
102#endif
103 int fd, rc = 0;
104
105#ifdef CHECK_SKIP_CONFcheck_skip_conf
106 if (CHECK_SKIP_CONFcheck_skip_conf()) {
107 printf("boot.conf processing skipped at operator request\n");
108 cmd.timeout = 0;
109 return -1; /* Pretend file wasn't found */
110 }
111#endif
112
113 if ((fd = open(qualify(cmd.conf), O_RDONLY0x0000)) < 0) {
114 if (errno != ENOENT2 && errno != ENXIO6) {
115 printf("open(%s): %s\n", cmd.path, strerror(errno));
116 return 0;
117 }
118 return -1;
119 }
120
121#ifndef INSECURE
122 (void) fstat(fd, &sb);
123 if (sb.st_uid || (sb.st_mode & 2)) {
124 printf("non-secure %s, will not proceed\n", cmd.path);
125 close(fd);
126 return -1;
127 }
128#endif
129
130 do {
131 char *p = cmd_buf;
132
133 cmd.cmd = NULL((void *)0);
134 do {
135 rc = read(fd, p, 1);
136 } while (rc > 0 && *p++ != '\n' &&
137 (p-cmd_buf) < sizeof(cmd_buf));
138
139 if (rc < 0) { /* Error from read() */
140 printf("%s: %s\n", cmd.path, strerror(errno));
141 break;
142 }
143
144 if (rc == 0) { /* eof from read() */
145 if (p != cmd_buf) { /* Line w/o trailing \n */
146 *p = '\0';
147 rc = docmd();
148 break;
149 }
150 } else { /* rc > 0, read a char */
151 p--; /* Get back to last character */
152
153 if (*p != '\n') { /* Line was too long */
154 printf("%s: line too long\n", cmd.path);
155
156 /* Don't want to run the truncated command */
157 rc = -1;
158 }
159 *p = '\0';
160 }
161 } while (rc > 0 && !(rc = docmd()));
162
163 close(fd);
164 return rc;
165}
166
167int
168docmd(void)
169{
170 char *p = NULL((void *)0);
171 const struct cmd_table *ct = cmd_table, *cs;
172
173 cmd.argc = 1;
174 if (cmd.cmd == NULL((void *)0)) {
175
176 /* command */
177 for (p = cmd_buf; *p == ' ' || *p == '\t'; p++)
178 ;
179 if (*p == '#' || *p == '\0') { /* comment or empty string */
180#ifdef DEBUG
181 printf("rem\n");
182#endif
183 return 0;
184 }
185 ct = cmd_table;
186 cs = NULL((void *)0);
187 cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */
188 p = whatcmd(&ct, p);
189 if (ct == NULL((void *)0)) {
190 cmd.argc++;
191 ct = cmd_table;
192 } else if (ct->cmd_type == CMDT_SET2 && p != NULL((void *)0)) {
193 cs = cmd_set;
194#ifdef MACHINE_CMDcmd_machine
195 } else if (ct->cmd_type == CMDT_MDC3 && p != NULL((void *)0)) {
196 cs = MACHINE_CMDcmd_machine;
197#endif
198 }
199
200 if (cs != NULL((void *)0)) {
201 p = whatcmd(&cs, p);
202 if (cs == NULL((void *)0)) {
203 printf("%s: syntax error\n", ct->cmd_name);
204 return 0;
205 }
206 ct = cs;
207 }
208 cmd.cmd = ct;
209 }
210
211 cmd.argv[0] = ct->cmd_name;
212 while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) {
213 cmd.argv[cmd.argc++] = p;
214 p = nextword(p);
215 }
216 cmd.argv[cmd.argc] = NULL((void *)0);
217
218 return (*cmd.cmd->cmd_exec)();
219}
220
221static char *
222whatcmd(const struct cmd_table **ct, char *p)
223{
224 char *q;
225 int l;
226
227 q = nextword(p);
228
229 for (l = 0; p[l]; l++)
230 ;
231
232 while ((*ct)->cmd_name != NULL((void *)0) && strncmp(p, (*ct)->cmd_name, l))
233 (*ct)++;
234
235 if ((*ct)->cmd_name == NULL((void *)0))
236 *ct = NULL((void *)0);
237
238 return q;
239}
240
241static int
242readline(char *buf, size_t n, int to)
243{
244#ifdef DEBUG
245 extern int debug;
246#endif
247 char *p = buf, ch;
248
249 /* Only do timeout if greater than 0 */
250 if (to > 0) {
251 u_long i = 0;
252 time_t tt = getsecs() + to;
253#ifdef DEBUG
254 if (debug > 2)
255 printf ("readline: timeout(%d) at %u\n", to, tt);
256#endif
257 /* check for timeout expiration less often
258 (for some very constrained archs) */
259 while (!cnischar())
260 if (!(i++ % 1000) && (getsecs() >= tt))
261 break;
262
263 if (!cnischar()) {
264 strlcpy(buf, "boot", 5);
265 putchar('\n');
266 return strlen(buf);
267 }
268 } else
269 while (!cnischar())
270 ;
271
272 /* User has typed something. Turn off timeouts. */
273 cmd.timeout = 0;
274
275 while (1) {
276 switch ((ch = getchar())) {
277 case CTRL('u')(('u')&0x1f):
278 while (p > buf) {
279 putchar('\177');
280 p--;
281 }
282 continue;
283 case '\n':
284 case '\r':
285 *p = '\0';
286 break;
287 case '\b':
288 case '\177':
289 if (p > buf) {
290 putchar('\177');
291 p--;
292 }
293 continue;
294 default:
295 if (ch >= ' ' && ch < '\177') {
296 if (p - buf < n-1)
297 *p++ = ch;
298 else {
299 putchar('\007');
300 putchar('\177');
301 }
302 }
303 continue;
304 }
305 break;
306 }
307
308 return p - buf;
309}
310
311/*
312 * Search for spaces/tabs after the current word. If found, \0 the
313 * first one. Then pass a pointer to the first character of the
314 * next word, or NULL if there is no next word.
315 */
316char *
317nextword(char *p)
318{
319 /* skip blanks */
320 while (*p && *p != '\t' && *p != ' ')
321 p++;
322 if (*p) {
323 *p++ = '\0';
324 while (*p == '\t' || *p == ' ')
325 p++;
326 }
327 if (*p == '\0')
328 p = NULL((void *)0);
329 return p;
330}
331
332static void
333print_help(const struct cmd_table *ct)
334{
335 for (; ct->cmd_name != NULL((void *)0); ct++)
336 printf(" %s", ct->cmd_name);
337 putchar('\n');
338}
339
340static int
341Xhelp(void)
342{
343 printf("commands:");
344 print_help(cmd_table);
345#ifdef MACHINE_CMDcmd_machine
346 return Xmachine();
347#else
348 return 0;
349#endif
350}
351
352static int
353Xhexdump(void)
354{
355 long long val[2];
356 char *ep;
357 int i;
358
359 if (cmd.argc != 3) {
1
Assuming field 'argc' is equal to 3
2
Taking false branch
360 printf("hexdump addr size\n");
361 return 0;
362 }
363
364 for (i = 1; i < cmd.argc; i++) {
3
Loop condition is true. Entering loop body
7
Assuming 'i' is >= field 'argc'
8
Loop condition is false. Execution continues on line 371
365 val[i-1] = strtoll(cmd.argv[i], &ep, 0);
366 if (cmd.argv[i][0] == '\0' || *ep != '\0') {
4
Assuming the condition is false
5
Assuming the condition is false
6
Taking false branch
367 printf("bad '%c' in \"%s\"\n", *ep, cmd.argv[i]);
368 return 0;
369 }
370 }
371 hexdump((void *)(unsigned long)val[0], val[1]);
9
2nd function call argument is an uninitialized value
372 return 0;
373}
374
375#ifdef MACHINE_CMDcmd_machine
376static int
377Xmachine(void)
378{
379 printf("machine:");
380 print_help(MACHINE_CMDcmd_machine);
381 return 0;
382}
383#endif
384
385static int
386Xecho(void)
387{
388 int i;
389
390 for (i = 1; i < cmd.argc; i++)
391 printf("%s ", cmd.argv[i]);
392 putchar('\n');
393 return 0;
394}
395
396static int
397Xstty(void)
398{
399 int sp;
400 char *cp;
401 dev_t dev;
402
403 if (cmd.argc == 1) {
404 printf("%s speed is %d\n", ttyname(0), cnspeed(0, -1));
405 return 0;
406 }
407 dev = ttydev(cmd.argv[1]);
408 if (dev == NODEV(dev_t)(-1)) {
409 printf("%s not a console device\n", cmd.argv[1]);
410 return 0;
411 }
412
413 if (cmd.argc == 2)
414 printf("%s speed is %d\n", cmd.argv[1],
415 cnspeed(dev, -1));
416 else {
417 sp = 0;
418 for (cp = cmd.argv[2]; isdigit(*cp)((*cp) >= '0' && (*cp) <= '9'); cp++)
419 sp = sp * 10 + (*cp - '0');
420 cnspeed(dev, sp);
421 }
422 return 0;
423}
424
425static int
426Xtime(void)
427{
428 time_t tt = getsecs();
429
430 if (cmd.argc == 1)
431 printf(ctime(&tt));
432
433 return 0;
434}
435
436static int
437Xls(void)
438{
439 struct stat sb;
440 char *p;
441 int fd;
442
443 if (stat(qualify((cmd.argv[1]? cmd.argv[1]: "/.")), &sb) < 0) {
444 printf("stat(%s): %s\n", cmd.path, strerror(errno));
445 return 0;
446 }
447
448 if ((sb.st_mode & S_IFMT0170000) != S_IFDIR0040000)
449 ls(cmd.path, &sb);
450 else {
451 if ((fd = opendir(cmd.path)) < 0) {
452 printf("opendir(%s): %s\n", cmd.path,
453 strerror(errno));
454 return 0;
455 }
456
457 /* no strlen in lib !!! */
458 for (p = cmd.path; *p; p++)
459 ;
460 *p++ = '/';
461 *p = '\0';
462
463 while (readdir(fd, p) >= 0) {
464 if (stat(cmd.path, &sb) < 0)
465 printf("stat(%s): %s\n", cmd.path,
466 strerror(errno));
467 else
468 ls(p, &sb);
469 }
470 closedir (fd);
471 }
472 return 0;
473}
474
475#define lsrwx(mode,s) \
476 putchar ((mode) & S_IROTH0000004? 'r' : '-'); \
477 putchar ((mode) & S_IWOTH0000002? 'w' : '-'); \
478 putchar ((mode) & S_IXOTH0000001? *(s): (s)[1]);
479
480static void
481ls(char *name, struct stat *sb)
482{
483 putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT0170000) >> 12]);
484 lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID0004000? "sS" : "x-"));
485 lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID0002000? "sS" : "x-"));
486 lsrwx(sb->st_mode , (sb->st_mode & S_ISTXT0001000? "tT" : "x-"));
487
488 printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid,
489 (u_long)sb->st_size, name);
490}
491#undef lsrwx
492
493int doboot = 1;
494
495static int
496Xnop(void)
497{
498 if (doboot) {
499 doboot = 0;
500 return (Xboot());
501 }
502
503 return 0;
504}
505
506static int
507Xboot(void)
508{
509 if (cmd.argc > 1 && cmd.argv[1][0] != '-') {
510 qualify((cmd.argv[1]? cmd.argv[1]: cmd.image));
511 if (bootparse(2))
512 return 0;
513 } else {
514 if (bootparse(1))
515 return 0;
516 snprintf(cmd.path, sizeof cmd.path, "%s:%s",
517 cmd.bootdev, cmd.image);
518 }
519
520 return 1;
521}
522
523/*
524 * Qualifies the path adding necessary dev
525 */
526
527static char *
528qualify(char *name)
529{
530 char *p;
531
532 for (p = name; *p; p++)
533 if (*p == ':')
534 break;
535 if (*p == ':')
536 strlcpy(cmd.path, name, sizeof(cmd.path));
537 else
538 snprintf(cmd.path, sizeof cmd.path, "%s:%s",
539 cmd.bootdev, name);
540 return cmd.path;
541}
542
543static int
544Xreboot(void)
545{
546 printf("Rebooting...\n");
547 exit();
548 return 0; /* just in case */
549}
550
551int
552upgrade(void)
553{
554 struct stat sb;
555
556 if (stat(qualify(("/bsd.upgrade")), &sb) < 0)
557 return 0;
558 if ((sb.st_mode & S_IXUSR0000100) == 0) {
559 printf("/bsd.upgrade is not u+x\n");
560 return 0;
561 }
562 return 1;
563}