Bug Summary

File:src/usr.sbin/installboot/i386_installboot.c
Warning:line 627, column 10
Assigned value is garbage or undefined

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 i386_installboot.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/installboot/obj -resource-dir /usr/local/lib/clang/13.0.0 -D SOFTRAID -I /usr/src/usr.sbin/installboot -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/installboot/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/installboot/i386_installboot.c
1/* $OpenBSD: i386_installboot.c,v 1.40 2021/07/20 14:51:56 kettenis Exp $ */
2/* $NetBSD: installboot.c,v 1.5 1995/11/17 23:23:50 gwr Exp $ */
3
4/*
5 * Copyright (c) 2013 Pedro Martelletto
6 * Copyright (c) 2011 Joel Sing <jsing@openbsd.org>
7 * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
8 * Copyright (c) 1997 Michael Shalayeff
9 * Copyright (c) 1994 Paul Kranenburg
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by Paul Kranenburg.
23 * 4. The name of the author may not be used to endorse or promote products
24 * derived from this software without specific prior written permission
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#define ELFSIZE32 32
39
40#include <sys/param.h> /* DEV_BSIZE */
41#include <sys/disklabel.h>
42#include <sys/dkio.h>
43#include <sys/ioctl.h>
44#include <sys/mount.h>
45#include <sys/reboot.h>
46#include <sys/stat.h>
47#include <sys/sysctl.h>
48#include <sys/time.h>
49
50#include <ufs/ufs/dinode.h>
51#include <ufs/ufs/dir.h>
52#include <ufs/ffs/fs.h>
53
54#include <machine/cpu.h>
55#include <machine/biosvar.h>
56
57#include <elf.h>
58#include <err.h>
59#include <errno(*__errno()).h>
60#include <fcntl.h>
61#include <nlist.h>
62#include <stdlib.h>
63#include <stdio.h>
64#include <stdint.h>
65#include <string.h>
66#include <unistd.h>
67#include <util.h>
68#include <uuid.h>
69
70#include "installboot.h"
71#include "i386_installboot.h"
72
73char *bootldr;
74
75char *blkstore;
76size_t blksize;
77
78struct sym_data pbr_symbols[] = {
79 {"_fs_bsize_p", 2},
80 {"_fs_bsize_s", 2},
81 {"_fsbtodb", 1},
82 {"_p_offset", 4},
83 {"_inodeblk", 4},
84 {"_inodedbl", 4},
85 {"_nblocks", 2},
86 {"_blkincr", 1},
87 {NULL((void *)0)}
88};
89
90static void devread(int, void *, daddr_t, size_t, char *);
91static u_int findopenbsd(int, struct disklabel *);
92static int getbootparams(char *, int, struct disklabel *);
93static char *loadproto(char *, long *);
94static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
95static int sbchk(struct fs *, daddr_t);
96static void sbread(int, daddr_t, struct fs **, char *);
97
98static const daddr_t sbtry[] = SBLOCKSEARCH{ 65536, 8192, 262144, -1 };
99
100/*
101 * Read information about /boot's inode and filesystem parameters, then
102 * put biosboot (partition boot record) on the target drive with these
103 * parameters patched in.
104 */
105
106void
107md_init(void)
108{
109 stages = 2;
110 stage1 = "/usr/mdec/biosboot";
111 stage2 = "/usr/mdec/boot";
112
113 bootldr = "/boot";
114}
115
116void
117md_loadboot(void)
118{
119 /* Load prototype boot blocks. */
120 if ((blkstore = loadproto(stage1, &blksize)) == NULL((void *)0))
121 exit(1);
122
123 /* XXX - Paranoia: Make sure size is aligned! */
124 if (blksize & (DEV_BSIZE(1 << 9) - 1))
125 errx(1, "proto %s bad size=%ld", stage1, blksize);
126
127 if (blksize > SBSIZE8192 - DEV_BSIZE(1 << 9))
128 errx(1, "proto bootblocks too big");
129}
130
131void
132md_prepareboot(int devfd, char *dev)
133{
134 struct disklabel dl;
135 int part;
136
137 /* Get and check disklabel. */
138 if (ioctl(devfd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) &
0x1fff) << 16) | ((('d')) << 8) | ((101)))
, &dl) == -1)
139 err(1, "disklabel: %s", dev);
140 if (dl.d_magic != DISKMAGIC((u_int32_t)0x82564557))
141 errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
142
143 /* Warn on unknown disklabel types. */
144 if (dl.d_type == 0)
145 warnx("disklabel type unknown");
146
147 part = findgptefisys(devfd, &dl);
148 if (part != -1) {
149 create_filesystem(&dl, (char)part);
150 return;
151 }
152}
153
154void
155md_installboot(int devfd, char *dev)
156{
157 struct disklabel dl;
158 int part;
159
160 /* Get and check disklabel. */
161 if (ioctl(devfd, DIOCGDINFO((unsigned long)0x40000000 | ((sizeof(struct disklabel) &
0x1fff) << 16) | ((('d')) << 8) | ((101)))
, &dl) == -1
)
1
Assuming the condition is false
2
Taking false branch
162 err(1, "disklabel: %s", dev);
163 if (dl.d_magic != DISKMAGIC((u_int32_t)0x82564557))
3
Assuming field 'd_magic' is equal to DISKMAGIC
4
Taking false branch
164 errx(1, "bad disklabel magic=0x%08x", dl.d_magic);
165
166 /* Warn on unknown disklabel types. */
167 if (dl.d_type == 0)
5
Assuming field 'd_type' is not equal to 0
6
Taking false branch
168 warnx("disklabel type unknown");
169
170 part = findgptefisys(devfd, &dl);
7
Calling 'findgptefisys'
171 if (part != -1) {
172 write_filesystem(&dl, (char)part);
173 return;
174 }
175
176 bootldr = fileprefix(root, bootldr);
177 if (bootldr == NULL((void *)0))
178 exit(1);
179 if (verbose)
180 fprintf(stderr(&__sF[2]), "%s %s to %s\n",
181 (nowrite ? "would copy" : "copying"), stage2, bootldr);
182 if (!nowrite)
183 if (filecopy(stage2, bootldr) == -1)
184 exit(1);
185
186 /* Get bootstrap parameters to patch into proto. */
187 if (getbootparams(bootldr, devfd, &dl) != 0)
188 exit(1);
189
190 /* Write boot blocks to device. */
191 write_bootblocks(devfd, dev, &dl);
192}
193
194void
195write_bootblocks(int devfd, char *dev, struct disklabel *dl)
196{
197 struct stat sb;
198 u_int8_t *secbuf;
199 u_int start = 0;
200
201 /* Write patched proto bootblock(s) into the superblock. */
202 if (fstat(devfd, &sb) == -1)
203 err(1, "fstat: %s", dev);
204
205 if (!S_ISCHR(sb.st_mode)((sb.st_mode & 0170000) == 0020000))
206 errx(1, "%s: not a character device", dev);
207
208 /* Patch the parameters into the proto bootstrap sector. */
209 pbr_set_symbols(stage1, blkstore, pbr_symbols);
210
211 if (!nowrite) {
212 /* Sync filesystems (to clean in-memory superblock?). */
213 sync(); sleep(1);
214 }
215
216 /*
217 * Find OpenBSD partition. Floppies are special, getting an
218 * everything-in-one /boot starting at sector 0.
219 */
220 if (dl->d_type != DTYPE_FLOPPY10) {
221 start = findopenbsd(devfd, dl);
222 if (start == (u_int)-1)
223 errx(1, "no OpenBSD partition");
224 }
225
226 if (verbose)
227 fprintf(stderr(&__sF[2]), "%s will be written at sector %u\n",
228 stage1, start);
229
230 if (start + (blksize / dl->d_secsize) > BOOTBIOS_MAXSEC((1 << 28) - 1))
231 warnx("%s extends beyond sector %u. OpenBSD might not boot.",
232 stage1, BOOTBIOS_MAXSEC((1 << 28) - 1));
233
234 if (!nowrite) {
235 secbuf = calloc(1, dl->d_secsize);
236 if (pread(devfd, secbuf, dl->d_secsize, (off_t)start *
237 dl->d_secsize) != dl->d_secsize)
238 err(1, "pread boot sector");
239 bcopy(blkstore, secbuf, blksize);
240 if (pwrite(devfd, secbuf, dl->d_secsize, (off_t)start *
241 dl->d_secsize) != dl->d_secsize)
242 err(1, "pwrite bootstrap");
243 free(secbuf);
244 }
245}
246
247int
248create_filesystem(struct disklabel *dl, char part)
249{
250 static char *newfsfmt ="/sbin/newfs_msdos %s >/dev/null";
251 struct msdosfs_args args;
252 char cmd[60];
253 int rslt;
254
255 /* Mount <duid>.<part> as msdos filesystem. */
256 memset(&args, 0, sizeof(args));
257 rslt = asprintf(&args.fspec,
258 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
259 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
260 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
261 part);
262 if (rslt == -1) {
263 warn("bad special device");
264 return rslt;
265 }
266
267 rslt = snprintf(cmd, sizeof(cmd), newfsfmt, args.fspec);
268 if (rslt >= sizeof(cmd)) {
269 warnx("can't build newfs command");
270 rslt = -1;
271 return rslt;
272 }
273
274 if (verbose)
275 fprintf(stderr(&__sF[2]), "%s %s\n",
276 (nowrite ? "would newfs" : "newfsing"), args.fspec);
277 if (!nowrite) {
278 rslt = system(cmd);
279 if (rslt == -1) {
280 warn("system('%s') failed", cmd);
281 return rslt;
282 }
283 }
284
285 return 0;
286}
287
288void
289write_filesystem(struct disklabel *dl, char part)
290{
291 static char *fsckfmt = "/sbin/fsck_msdos %s >/dev/null";
292 struct msdosfs_args args;
293 char cmd[60];
294 char dst[PATH_MAX1024];
295 char *src;
296 size_t mntlen, pathlen, srclen;
297 int rslt;
298
299 src = NULL((void *)0);
300
301 /* Create directory for temporary mount point. */
302 strlcpy(dst, "/tmp/installboot.XXXXXXXXXX", sizeof(dst));
303 if (mkdtemp(dst) == NULL((void *)0))
304 err(1, "mkdtemp('%s') failed", dst);
305 mntlen = strlen(dst);
306
307 /* Mount <duid>.<part> as msdos filesystem. */
308 memset(&args, 0, sizeof(args));
309 rslt = asprintf(&args.fspec,
310 "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx.%c",
311 dl->d_uid[0], dl->d_uid[1], dl->d_uid[2], dl->d_uid[3],
312 dl->d_uid[4], dl->d_uid[5], dl->d_uid[6], dl->d_uid[7],
313 part);
314 if (rslt == -1) {
315 warn("bad special device");
316 goto rmdir;
317 }
318
319 args.export_info.ex_root = -2; /* unchecked anyway on DOS fs */
320 args.export_info.ex_flags = 0;
321 args.flags = MSDOSFSMNT_LONGNAME0x02;
322
323 if (mount(MOUNT_MSDOS"msdos", dst, 0, &args) == -1) {
324 /* Try fsck'ing it. */
325 rslt = snprintf(cmd, sizeof(cmd), fsckfmt, args.fspec);
326 if (rslt >= sizeof(cmd)) {
327 warnx("can't build fsck command");
328 rslt = -1;
329 goto rmdir;
330 }
331 rslt = system(cmd);
332 if (rslt == -1) {
333 warn("system('%s') failed", cmd);
334 goto rmdir;
335 }
336 if (mount(MOUNT_MSDOS"msdos", dst, 0, &args) == -1) {
337 /* Try newfs'ing it. */
338 rslt = create_filesystem(dl, part);
339 if (rslt == -1)
340 goto rmdir;
341 rslt = mount(MOUNT_MSDOS"msdos", dst, 0, &args);
342 if (rslt == -1) {
343 warn("unable to mount EFI System partition");
344 goto rmdir;
345 }
346 }
347 }
348
349 /* Create "/efi/BOOT" directory in <duid>.<part>. */
350 if (strlcat(dst, "/efi", sizeof(dst)) >= sizeof(dst)) {
351 rslt = -1;
352 warn("unable to build /efi directory");
353 goto umount;
354 }
355 rslt = mkdir(dst, 0);
356 if (rslt == -1 && errno(*__errno()) != EEXIST17) {
357 warn("mkdir('%s') failed", dst);
358 goto umount;
359 }
360 if (strlcat(dst, "/BOOT", sizeof(dst)) >= sizeof(dst)) {
361 rslt = -1;
362 warn("unable to build /BOOT directory");
363 goto umount;
364 }
365 rslt = mkdir(dst, 0);
366 if (rslt == -1 && errno(*__errno()) != EEXIST17) {
367 warn("mkdir('%s') failed", dst);
368 goto umount;
369 }
370
371 /*
372 * Copy BOOTIA32.EFI and BOOTX64.EFI to /efi/BOOT/.
373 *
374 * N.B.: BOOTIA32.EFI is longer than BOOTX64.EFI, so src can be reused!
375 */
376 pathlen = strlen(dst);
377 if (strlcat(dst, "/BOOTIA32.EFI", sizeof(dst)) >= sizeof(dst)) {
378 rslt = -1;
379 warn("unable to build /BOOTIA32.EFI path");
380 goto umount;
381 }
382 src = fileprefix(root, "/usr/mdec/BOOTIA32.EFI");
383 if (src == NULL((void *)0)) {
384 rslt = -1;
385 goto umount;
386 }
387 srclen = strlen(src);
388 if (verbose)
389 fprintf(stderr(&__sF[2]), "%s %s to %s\n",
390 (nowrite ? "would copy" : "copying"), src, dst);
391 if (!nowrite) {
392 rslt = filecopy(src, dst);
393 if (rslt == -1)
394 goto umount;
395 }
396 src[srclen - strlen("/BOOTIA32.EFI")] = '\0';
397
398 dst[pathlen] = '\0';
399 if (strlcat(dst, "/BOOTX64.EFI", sizeof(dst)) >= sizeof(dst)) {
400 rslt = -1;
401 warn("unable to build /BOOTX64.EFI dst path");
402 goto umount;
403 }
404 if (strlcat(src, "/BOOTX64.EFI", srclen+1) >= srclen+1) {
405 rslt = -1;
406 warn("unable to build /BOOTX64.EFI src path");
407 goto umount;
408 }
409 if (verbose)
410 fprintf(stderr(&__sF[2]), "%s %s to %s\n",
411 (nowrite ? "would copy" : "copying"), src, dst);
412 if (!nowrite) {
413 rslt = filecopy(src, dst);
414 if (rslt == -1)
415 goto umount;
416 }
417
418 rslt = 0;
419
420umount:
421 dst[mntlen] = '\0';
422 if (unmount(dst, MNT_FORCE0x00080000) == -1)
423 err(1, "unmount('%s') failed", dst);
424
425rmdir:
426 free(args.fspec);
427 dst[mntlen] = '\0';
428 if (rmdir(dst) == -1)
429 err(1, "rmdir('%s') failed", dst);
430
431 free(src);
432
433 if (rslt == -1)
434 exit(1);
435}
436
437u_int
438findopenbsd(int devfd, struct disklabel *dl)
439{
440 struct dos_mbr mbr;
441 u_int mbroff = DOSBBSECTOR0;
442 u_int mbr_eoff = DOSBBSECTOR0; /* Offset of extended part. */
443 struct dos_partition *dp;
444 u_int8_t *secbuf;
445 u_int maxebr = DOS_MAXEBR256, nextebr;
446 int i;
447
448again:
449 if (!maxebr--) {
450 if (verbose)
451 fprintf(stderr(&__sF[2]), "Traversed more than %d Extended Boot "
452 "Records (EBRs)\n", DOS_MAXEBR256);
453 return ((u_int)-1);
454 }
455
456 if (verbose)
457 fprintf(stderr(&__sF[2]), "%s boot record (%cBR) at sector %u\n",
458 (mbroff == DOSBBSECTOR0) ? "master" : "extended",
459 (mbroff == DOSBBSECTOR0) ? 'M' : 'E', mbroff);
460
461 if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0))
462 err(1, NULL((void *)0));
463 if (pread(devfd, secbuf, dl->d_secsize, (off_t)mbroff * dl->d_secsize)
464 < (ssize_t)sizeof(mbr))
465 err(4, "can't pread boot record");
466 bcopy(secbuf, &mbr, sizeof(mbr));
467 free(secbuf);
468
469 if (mbr.dmbr_sign != DOSMBR_SIGNATURE(0xaa55))
470 errx(1, "invalid boot record signature (0x%04X) @ sector %u",
471 mbr.dmbr_sign, mbroff);
472
473 nextebr = 0;
474 for (i = 0; i < NDOSPART4; i++) {
475 dp = &mbr.dmbr_parts[i];
476 if (!dp->dp_size)
477 continue;
478
479 if (verbose)
480 fprintf(stderr(&__sF[2]),
481 "\tpartition %d: type 0x%02X offset %u size %u\n",
482 i, dp->dp_typ, dp->dp_start, dp->dp_size);
483
484 if (dp->dp_typ == DOSPTYP_OPENBSD0xa6) {
485 if (dp->dp_start > (dp->dp_start + mbroff))
486 continue;
487 return (dp->dp_start + mbroff);
488 }
489
490 if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND0x05 ||
491 dp->dp_typ == DOSPTYP_EXTENDL0x0f)) {
492 nextebr = dp->dp_start + mbr_eoff;
493 if (nextebr < dp->dp_start)
494 nextebr = (u_int)-1;
495 if (mbr_eoff == DOSBBSECTOR0)
496 mbr_eoff = dp->dp_start;
497 }
498 }
499
500 if (nextebr && nextebr != (u_int)-1) {
501 mbroff = nextebr;
502 goto again;
503 }
504
505 return ((u_int)-1);
506}
507
508/*
509 * Returns 0 if the MBR with the provided partition array is a GPT protective
510 * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
511 * one MBR partition, an EFI partition that either covers the whole disk or as
512 * much of it as is possible with a 32bit size field.
513 *
514 * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
515 */
516static int
517gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
518{
519 struct dos_partition *dp2;
520 int efi, found, i;
521 u_int32_t psize;
522
523 found = efi = 0;
524 for (dp2=dp, i=0; i < NDOSPART4; i++, dp2++) {
525 if (dp2->dp_typ == DOSPTYP_UNUSED0x00)
526 continue;
527 found++;
528 if (dp2->dp_typ != DOSPTYP_EFI0xee)
529 continue;
530 if (letoh32(dp2->dp_start)((__uint32_t)(dp2->dp_start)) != GPTSECTOR1)
531 continue;
532 psize = letoh32(dp2->dp_size)((__uint32_t)(dp2->dp_size));
533 if (psize <= (dsize - GPTSECTOR1) || psize == UINT32_MAX0xffffffffU)
534 efi++;
535 }
536 if (found == 1 && efi == 1)
537 return (0);
538
539 return (1);
540}
541
542int
543findgptefisys(int devfd, struct disklabel *dl)
544{
545 struct gpt_partition gp[NGPTPARTITIONS128];
546 struct gpt_header gh;
547 struct dos_partition dp[NDOSPART4];
548 struct uuid efisys_uuid;
549 const char efisys_uuid_code[] = GPT_UUID_EFI_SYSTEM{ 0xc1, 0x2a, 0x73, 0x28, 0xf8, 0x1f, 0x11, 0xd2, 0xba, 0x4b,
0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b }
;
550 off_t off;
551 ssize_t len;
552 u_int64_t start;
553 int i;
554 uint32_t orig_csum, new_csum;
555 uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec;
556 u_int8_t *secbuf;
557
558 /* Prepare EFI System UUID */
559 uuid_dec_be(efisys_uuid_code, &efisys_uuid);
560
561 if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0))
8
Assuming the condition is false
9
Taking false branch
562 err(1, NULL((void *)0));
563
564 /* Check that there is a protective MBR. */
565 len = pread(devfd, secbuf, dl->d_secsize, 0);
566 if (len != dl->d_secsize)
10
Assuming 'len' is equal to field 'd_secsize'
11
Taking false branch
567 err(4, "can't read mbr");
568 memcpy(dp, &secbuf[DOSPARTOFF446], sizeof(dp));
569 if (gpt_chk_mbr(dp, DL_GETDSIZE(dl)(((u_int64_t)(dl)->d_secperunith << 32) + (dl)->d_secperunit
)
)
) {
12
Assuming the condition is false
13
Taking false branch
570 free(secbuf);
571 return (-1);
572 }
573
574 /* Check GPT Header. */
575 off = dl->d_secsize; /* Read header from sector 1. */
576 len = pread(devfd, secbuf, dl->d_secsize, off);
577 if (len != dl->d_secsize)
14
Assuming 'len' is equal to field 'd_secsize'
15
Taking false branch
578 err(4, "can't pread gpt header");
579
580 memcpy(&gh, secbuf, sizeof(gh));
581 free(secbuf);
582
583 /* Check signature */
584 if (letoh64(gh.gh_sig)((__uint64_t)(gh.gh_sig)) != GPTSIGNATURE0x5452415020494645LL)
16
Assuming field 'gh_sig' is equal to GPTSIGNATURE
17
Taking false branch
585 return (-1);
586
587 if (letoh32(gh.gh_rev)((__uint32_t)(gh.gh_rev)) != GPTREVISION0x10000)
18
Assuming field 'gh_rev' is equal to GPTREVISION
19
Taking false branch
588 return (-1);
589
590 ghsize = letoh32(gh.gh_size)((__uint32_t)(gh.gh_size));
591 if (ghsize < GPTMINHDRSIZE92 || ghsize > sizeof(struct gpt_header))
20
Assuming 'ghsize' is >= GPTMINHDRSIZE
21
Assuming the condition is false
22
Taking false branch
592 return (-1);
593
594 /* Check checksum */
595 orig_csum = gh.gh_csum;
596 gh.gh_csum = 0;
597 new_csum = crc32((unsigned char *)&gh, ghsize);
598 gh.gh_csum = orig_csum;
599 if (letoh32(orig_csum)((__uint32_t)(orig_csum)) != new_csum)
23
Assuming 'orig_csum' is equal to 'new_csum'
24
Taking false branch
600 return (-1);
601
602 off = letoh64(gh.gh_part_lba)((__uint64_t)(gh.gh_part_lba)) * dl->d_secsize;
603 ghpartsize = letoh32(gh.gh_part_size)((__uint32_t)(gh.gh_part_size));
604 ghpartspersec = dl->d_secsize / ghpartsize;
605 ghpartnum = letoh32(gh.gh_part_num)((__uint32_t)(gh.gh_part_num));
606 if ((secbuf = malloc(dl->d_secsize)) == NULL((void *)0))
25
Assuming the condition is false
26
Taking false branch
607 err(1, NULL((void *)0));
608 for (i = 0; i < (ghpartnum + ghpartspersec - 1) / ghpartspersec; i++) {
27
Assuming the condition is false
28
Loop condition is false. Execution continues on line 618
609 len = pread(devfd, secbuf, dl->d_secsize, off);
610 if (len != dl->d_secsize) {
611 free(secbuf);
612 return (-1);
613 }
614 memcpy(gp + i * ghpartspersec, secbuf,
615 ghpartspersec * sizeof(struct gpt_partition));
616 off += dl->d_secsize;
617 }
618 free(secbuf);
619 new_csum = crc32((unsigned char *)&gp, ghpartnum * ghpartsize);
620 if (new_csum != letoh32(gh.gh_part_csum)((__uint32_t)(gh.gh_part_csum)))
29
Assuming 'new_csum' is equal to field 'gh_part_csum'
30
Taking false branch
621 return (-1);
622
623 start = 0;
624 for (i = 0; i < ghpartnum && start == 0; i++) {
31
Assuming 'i' is < 'ghpartnum'
32
Loop condition is true. Entering loop body
625 if (memcmp(&gp[i].gp_type, &efisys_uuid,
33
Assuming the condition is true
34
Taking true branch
626 sizeof(struct uuid)) == 0)
627 start = letoh64(gp[i].gp_lba_start)((__uint64_t)(gp[i].gp_lba_start));
35
Assigned value is garbage or undefined
628 }
629
630 if (start) {
631 for (i = 0; i < MAXPARTITIONS16; i++) {
632 if (DL_GETPSIZE(&dl->d_partitions[i])(((u_int64_t)(&dl->d_partitions[i])->p_sizeh <<
32) + (&dl->d_partitions[i])->p_size)
> 0 &&
633 DL_GETPOFFSET(&dl->d_partitions[i])(((u_int64_t)(&dl->d_partitions[i])->p_offseth <<
32) + (&dl->d_partitions[i])->p_offset)
== start)
634 return ('a' + i);
635 }
636 }
637
638 return (-1);
639}
640
641/*
642 * Load the prototype boot sector (biosboot) into memory.
643 */
644static char *
645loadproto(char *fname, long *size)
646{
647 int fd;
648 size_t tdsize; /* text+data size */
649 char *bp;
650 Elf_EhdrElf32_Ehdr eh;
651 Elf_WordElf32_Word phsize;
652 Elf_PhdrElf32_Phdr *ph;
653
654 if ((fd = open(fname, O_RDONLY0x0000)) == -1)
655 err(1, "%s", fname);
656
657 if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
658 errx(1, "%s: read failed", fname);
659
660 if (!IS_ELF(eh)((eh).e_ident[0] == 0x7f && (eh).e_ident[1] == 'E' &&
(eh).e_ident[2] == 'L' && (eh).e_ident[3] == 'F')
)
661 errx(1, "%s: bad magic: 0x%02x%02x%02x%02x", fname,
662 eh.e_ident[EI_MAG00], eh.e_ident[EI_MAG11],
663 eh.e_ident[EI_MAG22], eh.e_ident[EI_MAG33]);
664
665 /*
666 * We have to include the exec header in the beginning of
667 * the buffer, and leave extra space at the end in case
668 * the actual write to disk wants to skip the header.
669 */
670
671 /* Program load header. */
672 if (eh.e_phnum != 1)
673 errx(1, "%s: %u ELF load sections (only support 1)",
674 fname, eh.e_phnum);
675
676 ph = reallocarray(NULL((void *)0), eh.e_phnum, sizeof(Elf_PhdrElf32_Phdr));
677 if (ph == NULL((void *)0))
678 err(1, NULL((void *)0));
679 phsize = eh.e_phnum * sizeof(Elf_PhdrElf32_Phdr);
680
681 if (pread(fd, ph, phsize, eh.e_phoff) != phsize)
682 errx(1, "%s: can't pread header", fname);
683
684 tdsize = ph->p_filesz;
685
686 /*
687 * Allocate extra space here because the caller may copy
688 * the boot block starting at the end of the exec header.
689 * This prevents reading beyond the end of the buffer.
690 */
691 if ((bp = calloc(tdsize, 1)) == NULL((void *)0))
692 err(1, NULL((void *)0));
693
694 /* Read the rest of the file. */
695 if (pread(fd, bp, tdsize, ph->p_offset) != (ssize_t)tdsize)
696 errx(1, "%s: pread failed", fname);
697
698 *size = tdsize; /* not aligned to DEV_BSIZE */
699
700 close(fd);
701 return bp;
702}
703
704static void
705devread(int fd, void *buf, daddr_t blk, size_t size, char *msg)
706{
707 if (pread(fd, buf, size, dbtob((off_t)blk)(((off_t)blk) << 9)) != (ssize_t)size)
708 err(1, "%s: devread: pread", msg);
709}
710
711/*
712 * Read information about /boot's inode, then put this and filesystem
713 * parameters from the superblock into pbr_symbols.
714 */
715static int
716getbootparams(char *boot, int devfd, struct disklabel *dl)
717{
718 int fd;
719 struct stat dsb, fsb;
720 struct statfs fssb;
721 struct partition *pp;
722 struct fs *fs;
723 char *sblock, *buf;
724 u_int blk, *ap;
725 int ndb;
726 int mib[3];
727 size_t size;
728 dev_t dev;
729 int incr;
730
731 /*
732 * Open 2nd-level boot program and record enough details about
733 * where it is on the filesystem represented by `devfd'
734 * (inode block, offset within that block, and various filesystem
735 * parameters essentially taken from the superblock) for biosboot
736 * to be able to load it later.
737 */
738
739 /* Make sure the (probably new) boot file is on disk. */
740 sync(); sleep(1);
741
742 if ((fd = open(boot, O_RDONLY0x0000)) == -1)
743 err(1, "open: %s", boot);
744
745 if (fstatfs(fd, &fssb) == -1)
746 err(1, "statfs: %s", boot);
747
748 if (strncmp(fssb.f_fstypename, "ffs", MFSNAMELEN16) &&
749 strncmp(fssb.f_fstypename, "ufs", MFSNAMELEN16) )
750 errx(1, "%s: not on an FFS filesystem", boot);
751
752#if 0
753 if (read(fd, &eh, sizeof(eh)) != sizeof(eh))
754 errx(1, "read: %s", boot);
755
756 if (!IS_ELF(eh)((eh).e_ident[0] == 0x7f && (eh).e_ident[1] == 'E' &&
(eh).e_ident[2] == 'L' && (eh).e_ident[3] == 'F')
) {
757 errx(1, "%s: bad magic: 0x%02x%02x%02x%02x",
758 boot,
759 eh.e_ident[EI_MAG00], eh.e_ident[EI_MAG11],
760 eh.e_ident[EI_MAG22], eh.e_ident[EI_MAG33]);
761 }
762#endif
763
764 if (fsync(fd) != 0)
765 err(1, "fsync: %s", boot);
766
767 if (fstat(fd, &fsb) != 0)
768 err(1, "fstat: %s", boot);
769
770 if (fstat(devfd, &dsb) != 0)
771 err(1, "fstat: %d", devfd);
772
773 /* Check devices. */
774 mib[0] = CTL_MACHDEP7;
775 mib[1] = CPU_CHR2BLK4;
776 mib[2] = dsb.st_rdev;
777 size = sizeof(dev);
778 if (sysctl(mib, 3, &dev, &size, NULL((void *)0), 0) >= 0) {
779 if (fsb.st_dev / MAXPARTITIONS16 != dev / MAXPARTITIONS16)
780 errx(1, "cross-device install");
781 }
782
783 pp = &dl->d_partitions[DISKPART(fsb.st_dev)(((unsigned)((fsb.st_dev) & 0xff) | (((fsb.st_dev) & 0xffff0000
) >> 8)) % 16)
];
784 close(fd);
785
786 if ((sblock = malloc(SBSIZE8192)) == NULL((void *)0))
787 err(1, NULL((void *)0));
788
789 sbread(devfd, DL_SECTOBLK(dl, pp->p_offset)((pp->p_offset) * ((dl)->d_secsize / (1 << 9))), &fs, sblock);
790
791 /* Read inode. */
792 if ((buf = malloc(fs->fs_bsize)) == NULL((void *)0))
793 err(1, NULL((void *)0));
794
795 blk = fsbtodb(fs, ino_to_fsba(fs, fsb.st_ino))((((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((fsb.st_ino) / (
fs)->fs_ipg))) + (fs)->fs_cgoffset * ((((fsb.st_ino) / (
fs)->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno
) + ((((((fsb.st_ino) % (fs)->fs_ipg) / ((fs)->fs_inopb
))) << ((fs))->fs_fragshift))))) << (fs)->fs_fsbtodb
)
;
796
797 /*
798 * Have the inode. Figure out how many filesystem blocks (not disk
799 * sectors) there are for biosboot to load.
800 */
801 devread(devfd, buf, DL_SECTOBLK(dl, pp->p_offset)((pp->p_offset) * ((dl)->d_secsize / (1 << 9))) + blk,
802 fs->fs_bsize, "inode");
803 if (fs->fs_magic == FS_UFS2_MAGIC0x19540119) {
804 struct ufs2_dinode *ip2 = (struct ufs2_dinode *)(buf) +
805 ino_to_fsbo(fs, fsb.st_ino)((fsb.st_ino) % ((fs)->fs_inopb));
806 ndb = howmany(ip2->di_size, fs->fs_bsize)(((ip2->di_size) + ((fs->fs_bsize) - 1)) / (fs->fs_bsize
))
;
807 ap = (u_int *)ip2->di_db;
808 incr = sizeof(u_int32_t);
809 } else {
810 struct ufs1_dinode *ip1 = (struct ufs1_dinode *)(buf) +
811 ino_to_fsbo(fs, fsb.st_ino)((fsb.st_ino) % ((fs)->fs_inopb));
812 ndb = howmany(ip1->di_size, fs->fs_bsize)(((ip1->di_size) + ((fs->fs_bsize) - 1)) / (fs->fs_bsize
))
;
813 ap = (u_int *)ip1->di_db;
814 incr = 0;
815 }
816
817 if (ndb <= 0)
818 errx(1, "No blocks to load");
819
820 /*
821 * Now set the values that will need to go into biosboot
822 * (the partition boot record, a.k.a. the PBR).
823 */
824 sym_set_value(pbr_symbols, "_fs_bsize_p", (fs->fs_bsize / 16));
825 sym_set_value(pbr_symbols, "_fs_bsize_s", (fs->fs_bsize /
826 dl->d_secsize));
827
828 /*
829 * fs_fsbtodb is the shift to convert fs_fsize to DEV_BSIZE. The
830 * ino_to_fsba() return value is the number of fs_fsize units.
831 * Calculate the shift to convert fs_fsize into physical sectors,
832 * which are added to p_offset to get the sector address BIOS
833 * will use.
834 *
835 * N.B.: ASSUMES fs_fsize is a power of 2 of d_secsize.
836 */
837 sym_set_value(pbr_symbols, "_fsbtodb",
838 ffs(fs->fs_fsize / dl->d_secsize) - 1);
839
840 sym_set_value(pbr_symbols, "_p_offset", pp->p_offset);
841 sym_set_value(pbr_symbols, "_inodeblk",
842 ino_to_fsba(fs, fsb.st_ino)((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((fsb.st_ino) / (fs
)->fs_ipg))) + (fs)->fs_cgoffset * ((((fsb.st_ino) / (fs
)->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno
) + ((((((fsb.st_ino) % (fs)->fs_ipg) / ((fs)->fs_inopb
))) << ((fs))->fs_fragshift))))
);
843 sym_set_value(pbr_symbols, "_inodedbl",
844 ((((char *)ap) - buf) + INODEOFF((0x07e0 -0x07c0) << 4)));
845 sym_set_value(pbr_symbols, "_nblocks", ndb);
846 sym_set_value(pbr_symbols, "_blkincr", incr);
847
848 if (verbose) {
849 fprintf(stderr(&__sF[2]), "%s is %d blocks x %d bytes\n",
850 boot, ndb, fs->fs_bsize);
851 fprintf(stderr(&__sF[2]), "fs block shift %u; part offset %u; "
852 "inode block %lld, offset %u\n",
853 ffs(fs->fs_fsize / dl->d_secsize) - 1,
854 pp->p_offset,
855 ino_to_fsba(fs, fsb.st_ino)((daddr_t)(((((daddr_t)(fs)->fs_fpg * (((fsb.st_ino) / (fs
)->fs_ipg))) + (fs)->fs_cgoffset * ((((fsb.st_ino) / (fs
)->fs_ipg)) & ~((fs)->fs_cgmask))) + (fs)->fs_iblkno
) + ((((((fsb.st_ino) % (fs)->fs_ipg) / ((fs)->fs_inopb
))) << ((fs))->fs_fragshift))))
,
856 (unsigned int)((((char *)ap) - buf) + INODEOFF((0x07e0 -0x07c0) << 4)));
857 fprintf(stderr(&__sF[2]), "expecting %d-bit fs blocks (incr %d)\n",
858 incr ? 64 : 32, incr);
859 }
860
861 free (sblock);
862 free (buf);
863
864 return 0;
865}
866
867void
868sym_set_value(struct sym_data *sym_list, char *sym, u_int32_t value)
869{
870 struct sym_data *p;
871
872 for (p = sym_list; p->sym_name != NULL((void *)0); p++) {
873 if (strcmp(p->sym_name, sym) == 0)
874 break;
875 }
876
877 if (p->sym_name == NULL((void *)0))
878 errx(1, "%s: no such symbol", sym);
879
880 p->sym_value = value;
881 p->sym_set = 1;
882}
883
884/*
885 * Write the parameters stored in sym_list into the in-memory copy of
886 * the prototype biosboot (proto), ready for it to be written to disk.
887 */
888void
889pbr_set_symbols(char *fname, char *proto, struct sym_data *sym_list)
890{
891 struct sym_data *sym;
892 struct nlist *nl;
893 char *vp;
894 u_int32_t *lp;
895 u_int16_t *wp;
896 u_int8_t *bp;
897
898 for (sym = sym_list; sym->sym_name != NULL((void *)0); sym++) {
899 if (!sym->sym_set)
900 errx(1, "%s not set", sym->sym_name);
901
902 /* Allocate space for 2; second is null-terminator for list. */
903 nl = calloc(2, sizeof(struct nlist));
904 if (nl == NULL((void *)0))
905 err(1, NULL((void *)0));
906
907 nl->n_name = sym->sym_name;
908
909 if (nlist_elf32(fname, nl) != 0)
910 errx(1, "%s: symbol %s not found",
911 fname, sym->sym_name);
912
913 if (nl->n_type != (N_TEXT0x04))
914 errx(1, "%s: %s: wrong type (%x)",
915 fname, sym->sym_name, nl->n_type);
916
917 /* Get a pointer to where the symbol's value needs to go. */
918 vp = proto + nl->n_value;
919
920 switch (sym->sym_size) {
921 case 4: /* u_int32_t */
922 lp = (u_int32_t *) vp;
923 *lp = sym->sym_value;
924 break;
925 case 2: /* u_int16_t */
926 if (sym->sym_value >= 0x10000) /* out of range */
927 errx(1, "%s: symbol out of range (%u)",
928 sym->sym_name, sym->sym_value);
929 wp = (u_int16_t *) vp;
930 *wp = (u_int16_t) sym->sym_value;
931 break;
932 case 1: /* u_int16_t */
933 if (sym->sym_value >= 0x100) /* out of range */
934 errx(1, "%s: symbol out of range (%u)",
935 sym->sym_name, sym->sym_value);
936 bp = (u_int8_t *) vp;
937 *bp = (u_int8_t) sym->sym_value;
938 break;
939 default:
940 errx(1, "%s: bad symbol size %d",
941 sym->sym_name, sym->sym_size);
942 /* NOTREACHED */
943 }
944
945 free(nl);
946 }
947}
948
949static int
950sbchk(struct fs *fs, daddr_t sbloc)
951{
952 if (verbose)
953 fprintf(stderr(&__sF[2]), "looking for superblock at %lld\n", sbloc);
954
955 if (fs->fs_magic != FS_UFS2_MAGIC0x19540119 && fs->fs_magic != FS_UFS1_MAGIC0x011954) {
956 if (verbose)
957 fprintf(stderr(&__sF[2]), "bad superblock magic 0x%x\n",
958 fs->fs_magic);
959 return (0);
960 }
961
962 /*
963 * Looking for an FFS1 file system at SBLOCK_UFS2 will find the
964 * wrong superblock for file systems with 64k block size.
965 */
966 if (fs->fs_magic == FS_UFS1_MAGIC0x011954 && sbloc == SBLOCK_UFS265536) {
967 if (verbose)
968 fprintf(stderr(&__sF[2]), "skipping ffs1 superblock at %lld\n",
969 sbloc);
970 return (0);
971 }
972
973 if (fs->fs_bsize <= 0 || fs->fs_bsize < sizeof(struct fs) ||
974 fs->fs_bsize > MAXBSIZE(64 * 1024)) {
975 if (verbose)
976 fprintf(stderr(&__sF[2]), "invalid superblock block size %d\n",
977 fs->fs_bsize);
978 return (0);
979 }
980
981 if (fs->fs_sbsize <= 0 || fs->fs_sbsize > SBSIZE8192) {
982 if (verbose)
983 fprintf(stderr(&__sF[2]), "invalid superblock size %d\n",
984 fs->fs_sbsize);
985 return (0);
986 }
987
988 if (fs->fs_inopb <= 0) {
989 if (verbose)
990 fprintf(stderr(&__sF[2]), "invalid superblock inodes/block %d\n",
991 fs->fs_inopb);
992 return (0);
993 }
994
995 if (verbose)
996 fprintf(stderr(&__sF[2]), "found valid %s superblock\n",
997 fs->fs_magic == FS_UFS2_MAGIC0x19540119 ? "ffs2" : "ffs1");
998
999 return (1);
1000}
1001
1002static void
1003sbread(int fd, daddr_t poffset, struct fs **fs, char *sblock)
1004{
1005 int i;
1006 daddr_t sboff;
1007
1008 for (i = 0; sbtry[i] != -1; i++) {
1009 sboff = sbtry[i] / DEV_BSIZE(1 << 9);
1010 devread(fd, sblock, poffset + sboff, SBSIZE8192, "superblock");
1011 *fs = (struct fs *)sblock;
1012 if (sbchk(*fs, sbtry[i]))
1013 break;
1014 }
1015
1016 if (sbtry[i] == -1)
1017 errx(1, "couldn't find ffs superblock");
1018}