Make installboot on landisk aware of a possible MBR on the disk, and in this
authormiod <miod@openbsd.org>
Wed, 31 Aug 2022 18:46:06 +0000 (18:46 +0000)
committermiod <miod@openbsd.org>
Wed, 31 Aug 2022 18:46:06 +0000 (18:46 +0000)
case install the first level bootstrap at the beginning of the of the wd0a
filesystem, rather than at the beginning of the disk.

Both locations work but the previous behaviour overwriting an existing MBR
is a violation of POLA.

tweaks & ok krw@

distrib/special/installboot/Makefile
usr.sbin/installboot/Makefile
usr.sbin/installboot/landisk_installboot.c

index cfc4d7b..9b461c0 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.17 2022/08/24 21:08:51 kn Exp $
+#      $OpenBSD: Makefile,v 1.18 2022/08/31 18:46:06 miod Exp $
 
 .PATH: ${.CURDIR}/../../../usr.sbin/installboot
 
@@ -24,7 +24,6 @@ SRCS += efi_installboot.c
 CFLAGS += -DBOOTSTRAP
 SRCS += hppa_installboot.c
 .elif ${MACHINE} == "landisk"
-CFLAGS += -DBOOTSTRAP
 SRCS += landisk_installboot.c
 .elif ${MACHINE} == "loongson"
 SRCS += loongson_installboot.c
index c4c5ea3..6e1d1ef 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.25 2022/08/15 17:06:43 kn Exp $
+#      $OpenBSD: Makefile,v 1.26 2022/08/31 18:46:06 miod Exp $
 
 PROG=          installboot
 SRCS=          installboot.c util.c
@@ -25,7 +25,6 @@ SRCS += efi_installboot.c
 CFLAGS += -DBOOTSTRAP
 SRCS += hppa_installboot.c
 .elif ${MACHINE} == "landisk"
-CFLAGS += -DBOOTSTRAP
 SRCS += landisk_installboot.c
 .elif ${MACHINE} == "loongson"
 SRCS += loongson_installboot.c
index b61a536..0be563c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: landisk_installboot.c,v 1.10 2021/07/20 14:51:56 kettenis Exp $       */
+/*     $OpenBSD: landisk_installboot.c,v 1.11 2022/08/31 18:46:06 miod Exp $   */
 
 /*
  * Copyright (c) 2013 Joel Sing <jsing@openbsd.org>
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <sys/param.h> /* DEV_BSIZE */
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <ufs/ffs/fs.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include "installboot.h"
 
+void   md_bootstrap(int, char *, char *);
+
 char   *bootldr;
 
 void
@@ -56,6 +70,158 @@ md_installboot(int devfd, char *dev)
                if (filecopy(stage2, bootldr) == -1)
                        exit(1);
 
-       /* Write bootblock into the superblock. */
-       bootstrap(devfd, dev, stage1);
+       /*
+        * Write bootblock into the beggining of the OpenBSD partition or
+        * at the beginning of the disk.
+        */
+       md_bootstrap(devfd, dev, stage1);
+}
+
+void
+md_bootstrap(int devfd, char *dev, char *bootfile)
+{
+       struct disklabel dl;
+       struct disklabel *lp;
+       struct partition *pp;
+       char *boot, *p, part;
+       size_t bootsize;
+       size_t bootsec;
+       struct stat sb;
+       daddr_t bootpos = 0;
+       int fd, i;
+
+       /*
+        * Install bootstrap code onto the given disk, preserving the
+        * existing disklabel.
+        */
+
+       /* Read disklabel from disk. */
+       if (ioctl(devfd, DIOCGDINFO, &dl) == -1)
+               err(1, "disklabel");
+       if (dl.d_secsize == 0) {
+               warnx("disklabel has sector size of 0, assuming %d", DEV_BSIZE);
+               dl.d_secsize = DEV_BSIZE;
+       }
+
+       /* Read bootstrap file. */
+       if (verbose)
+               fprintf(stderr, "reading bootstrap from %s\n", bootfile);
+       fd = open(bootfile, O_RDONLY);
+       if (fd == -1)
+               err(1, "open %s", bootfile);
+       if (fstat(fd, &sb) == -1)
+               err(1, "fstat %s", bootfile);
+       bootsec = howmany((ssize_t)sb.st_size, dl.d_secsize);
+       bootsize = bootsec * dl.d_secsize;
+       if (verbose)
+               fprintf(stderr, "bootstrap is %zu bytes "
+                   "(%zu sectors @ %u bytes = %zu bytes)\n",
+                   (ssize_t)sb.st_size, bootsec, dl.d_secsize, bootsize);
+       boot = calloc(1, bootsize);
+       if (boot == NULL)
+               err(1, "calloc");
+       if (read(fd, boot, bootsize) != (ssize_t)sb.st_size)
+               err(1, "read");
+       close(fd);
+
+       /*
+        * The landisk bootstrap can work when put either at the start of the
+        * disk, or at the start of an OpenBSD MBR partition, invoked from
+        * /usr/mdec/mbr.
+        * Check for a partition table in order to decide where to put the
+        * first-level bootstrap code.
+        */
+
+       if (dl.d_secsize >= sizeof(struct dos_mbr)) {
+               uint8_t *secbuf;
+               struct dos_mbr *mbr;
+
+               secbuf = malloc(dl.d_secsize);
+               if (secbuf == NULL)
+                       err(1, "malloc");
+
+               /* Read MBR. */
+               if (pread(devfd, secbuf, dl.d_secsize, 0) != dl.d_secsize)
+                       err(4, "can't read mbr");
+               mbr = (struct dos_mbr *)secbuf;
+               /* safe check because landisk is little endian */
+               if (mbr->dmbr_sign == DOSMBR_SIGNATURE) {
+                       for (i = 0; i < NDOSPART; i++) {
+                               if (mbr->dmbr_parts[i].dp_typ ==
+                                   DOSPTYP_OPENBSD) {
+                                       bootpos = mbr->dmbr_parts[i].dp_start;
+                                       break;
+                               }
+                       }
+               }
+
+               free(secbuf);
+       }
+
+       if (bootpos == 0) {
+               /*
+                * Installing at the start of the disk.
+                * Check that the bootstrap will fit - partitions must not
+                * overlap, or if they do, the partition type must be either
+                * FS_BOOT or FS_UNUSED. The 'c' partition will always overlap
+                * and is ignored.
+                */
+               if (verbose)
+                       fprintf(stderr,
+                           "ensuring used partitions do not overlap "
+                           "with bootstrap sectors 0-%zu\n", bootsec);
+               for (i = 0; i < dl.d_npartitions; i++) {
+                       part = 'a' + i;
+                       pp = &dl.d_partitions[i];
+                       if (i == RAW_PART)
+                               continue;
+                       if (DL_GETPSIZE(pp) == 0)
+                               continue;
+                       if (bootpos + (u_int64_t)bootsec <= DL_GETPOFFSET(pp))
+                               continue;
+                       switch (pp->p_fstype) {
+                       case FS_BOOT:
+                               break;
+                       case FS_UNUSED:
+                               warnx("bootstrap overlaps "
+                                   "with unused partition %c", part);
+                               break;
+                       default:
+                               errx(1, "bootstrap overlaps with partition %c",
+                                   part);
+                       }
+               }
+       } else {
+               /*
+                * Installing at the start of the OpenBSD partition.
+                * We only need to ensure the bootstrap code fits in the
+                * BBSIZE reserved area at the beginning of the file
+                * system.
+                */
+               if (bootsize > BBSIZE)
+                       errx(1, "bootstrap is too large");
+       }
+
+       /*
+        * Make sure the bootstrap has left space for the disklabel.
+        * N.B.: LABELSECTOR *is* a DEV_BSIZE quantity!
+        */
+       lp = (struct disklabel *)(boot + (LABELSECTOR * DEV_BSIZE) +
+           LABELOFFSET);
+       for (i = 0, p = (char *)lp; i < (int)sizeof(*lp); i++)
+               if (p[i] != 0)
+                       errx(1, "bootstrap has data in disklabel area");
+
+       /* Patch the disklabel into the bootstrap code. */
+       memcpy(lp, &dl, sizeof(dl));
+
+       /* Write the bootstrap out to the disk. */
+       bootpos *= dl.d_secsize;
+       if (verbose)
+               fprintf(stderr, "%s bootstrap to disk at offset %llx\n",
+                   (nowrite ? "would write" : "writing"), bootpos);
+       if (nowrite)
+               return;
+       if (pwrite(devfd, boot, bootsize, bootpos) != (ssize_t)bootsize)
+               err(1, "pwrite");
 }