On 20-06-05 22:42:17, Klemens Nanni wrote:
> On Mon, Jun 01, 2020 at 11:48:05PM +0200, Klemens Nanni wrote:
> > Installing an unstripped boot loader on softraid on sparc64 fails
> > without proper error message.
> > 
> > Make BIOCINSTALLBOOT return a proper errno, make installboot(8) use it
> > to provide proper usage errors plus unique code paths for debugging.
> > 
> > At first, I made sr_ioctl_installboot() use sr_error() in the relevant
> > spot and this made the kernel print my errors, however the following
> > piece in softraid.c:sr_bio_handler() means using sr_error() will hide
> > the error code from the ioctl(2) call, i.e. installboot(8) would
> > report no error message on stderr and exit zero:
> > 
> >     if (sc->sc_status.bs_msg_count > 0)                  
> >             rv = 0;    
> > 
> > So instead, use a proper errno that yields a simple
> > 
> >     # ./obj/installboot sd2 /usr/mdec/bootblk /ofwboot.new
> >     installboot.sr: softraid installboot failed: File too large
> > 
> > 
> > 
> > Background:  I built ofwboot on one machine ("make" without
> > "make install", then copy obj/ofwboot over), the resulting executable
> > was not stripped during build (happens during "make install") and was
> > about twice as big:
> > 
> >     # ls -l /ofwboot*       
> >     -rw-r--r--  1 root  wheel  106688 May 23 22:42 /ofwboot
> >     -rwxr-xr-x  1 kn    wheel  272452 May 24 00:20 /ofwboot.new
> >     -rwxr-xr-x  1 root  wheel  106752 May 24 01:21 /ofwboot.new.strip
> > 
> > It took me longer than anticipated to find out that installboot(8)
> > fails beause my new boot loader was too big:
> > 
> >     # installboot sd2 /usr/mdec/bootblk /ofwboot.new
> >     installboot: softraid installboot failed
> > 
> >     # installboot -v sd2 /usr/mdec/bootblk /ofwboot.new
> >     Using / as root
> >     installing bootstrap on /dev/rsd2c
> >     using first-stage /usr/mdec/bootblk, second-stage /ofwboot.new
> >     boot block is 6882 bytes (14 blocks @ 512 bytes = 7168 bytes)
> >     sd2: softraid volume with 1 disk(s)
> >     sd2: installing boot loader on softraid volume
> >     installboot: softraid installboot failed
> > 
> > That's it, no details or additional messages from the kernel.
> > While this was primarily my own fault, perhaps there are more legitimate
> > reasons foor bootblk/ofwboot builds to exceed their maximum size.
> 
> In a i386 VM with root on crypto softraid, I built a much bigger second
> stage boot loader and performed the same tests as on sparc64: i386 does
> not try to install the bogus boot code due to checks in i386_softraid.c
> up front:
> 
>       # ls -l /usr/mdec/boot /boot.efbig
>       -r-xr-xr-x  1 root  bin     89728 Jun  5 03:02 /usr/mdec/boot
>       -rwxr-xr-x  1 root  wheel  176172 Jun  5 22:16 /boot.efbig
>       # installboot -v sd1 /usr/mdec/biosboot /boot.efbig
>       Using / as root
>       installing bootstrap on /dev/rsd1c
>       using first-stage /usr/mdec/biosboot, second-stage /boot.efbig
>       sd1: softraid volume with 1 disk(s)
>       installboot: boot code will not fit
> 
> So for installboot(8) on sparc64 and i386 as the only two users of
> BIOCINSTALLBOOT, this makes root on softraid on sparc64 the only use
> that actually hits size checks in the ioctl code.

Keep in mind that the i386 installboot code is used on both i386
and amd64.

> sr_ioctl_installboot() seems inconsistent to me in how it reports some
> errors through sr_error() (causing ioctl() to return zero) and returing
> proper error codes (causing ioctl() and therefore installboot to fail);

sr_error() is used to add detail - the installboot code should be
checking and handling the case where bs->bs_status is non-zero.
IIRC the reason the ioctl has to succeed for this to work, is that
on failure there is no copyout().

> Assuming my EFBIG approach is still sensible (for sparc64), diff below
> adjusts the errx() call to err() in installboot for both platforms, even
> though i386 never reaches it.
> 
> Feedback? OK?

While this works, you would be better off making use of the error
reporting mechanism that exists. A compile tested only diff for
the kernel side is below. A diff to installboot would be needed to
graft some code similar to that in bioctl's bio_status() function.

Index: softraid.c
===================================================================
RCS file: /cvs/src/sys/dev/softraid.c,v
retrieving revision 1.401
diff -u -p -u -p -r1.401 softraid.c
--- softraid.c  14 Apr 2020 07:38:21 -0000      1.401
+++ softraid.c  6 Jun 2020 14:32:56 -0000
@@ -3704,11 +3704,17 @@ sr_ioctl_installboot(struct sr_softc *sc
                goto done;
        }
 
-       if (bb->bb_bootblk_size > SR_BOOT_BLOCKS_SIZE * DEV_BSIZE)
+       if (bb->bb_bootblk_size > SR_BOOT_BLOCKS_SIZE * DEV_BSIZE) {
+               sr_error(sc, "boot block is too large (%d > %d)",
+                   bb->bb_bootblk_size, SR_BOOT_BLOCKS_SIZE * DEV_BSIZE);
                goto done;
+       }
 
-       if (bb->bb_bootldr_size > SR_BOOT_LOADER_SIZE * DEV_BSIZE)
+       if (bb->bb_bootldr_size > SR_BOOT_LOADER_SIZE * DEV_BSIZE) {
+               sr_error(sc, "boot loader is too large (%d > %d)",
+                   bb->bb_bootldr_size, SR_BOOT_LOADER_SIZE * DEV_BSIZE);
                goto done;
+       }
 
        secsize = sd->sd_meta->ssdi.ssd_secsize;
 

Reply via email to