Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x68k/x68k Fix buffer overrun in readdisklabel(9) (a...



details:   https://anonhg.NetBSD.org/src/rev/b619e4bae154
branches:  trunk
changeset: 764795:b619e4bae154
user:      tsutsui <tsutsui%NetBSD.org@localhost>
date:      Thu May 05 04:38:20 2011 +0000

description:
Fix buffer overrun in readdisklabel(9) (and writedisklabel(9))
that causes unexpected panic during installation and
DIAGNOSTIC pool assertions.
Also fix bp->b_flags in writedisklabel(9) error path.

The problem was reported from Y.Sugahara during XM6i development,
and this fix is confirmed on both X68030 (by me) and XM6i (by Sugahara).

XXX: broken dkbad support (which makes struct cpu_disklabel larger
XXX: than 512 bytes) should be removed...

diffstat:

 sys/arch/x68k/x68k/disksubr.c |  46 ++++++++++++++++++++++++------------------
 1 files changed, 26 insertions(+), 20 deletions(-)

diffs (134 lines):

diff -r 29529e4fd6a4 -r b619e4bae154 sys/arch/x68k/x68k/disksubr.c
--- a/sys/arch/x68k/x68k/disksubr.c     Thu May 05 04:20:51 2011 +0000
+++ b/sys/arch/x68k/x68k/disksubr.c     Thu May 05 04:38:20 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: disksubr.c,v 1.33 2008/01/02 11:48:32 ad Exp $ */
+/*     $NetBSD: disksubr.c,v 1.34 2011/05/05 04:38:20 tsutsui Exp $    */
 
 /*
  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.33 2008/01/02 11:48:32 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.34 2011/05/05 04:38:20 tsutsui Exp $");
 
 #include "opt_compat_netbsd.h"
 
@@ -69,7 +69,7 @@
        struct buf *bp;
        struct disklabel *dlp;
        const char *msg = NULL;
-       int i, labelsz;
+       int i, bsdlabelsz, humanlabelsz;
 
        if (osdep)
                dp = osdep->dosparts;
@@ -90,15 +90,19 @@
        lp->d_partitions[0].p_offset = 0;
 
        /* get a buffer and initialize it */
-       bp = geteblk((int)lp->d_secsize);
+       bsdlabelsz =
+           howmany(LABELOFFSET + sizeof(struct disklabel), lp->d_secsize)
+           * lp->d_secsize;
+       humanlabelsz =
+           howmany(sizeof(struct cpu_disklabel), lp->d_secsize)
+           * lp->d_secsize;
+       bp = geteblk(MAX(bsdlabelsz, humanlabelsz));
        bp->b_dev = dev;
 
        /* read BSD disklabel first */
        bp->b_blkno = LABELSECTOR;
        bp->b_cylinder = LABELSECTOR/lp->d_secpercyl;
-       labelsz = howmany(LABELOFFSET+sizeof(struct disklabel), lp->d_secsize)
-               * lp->d_secsize;
-       bp->b_bcount = labelsz; /* to support < 512B/sector disks */
+       bp->b_bcount = bsdlabelsz;      /* to support < 512B/sector disks */
        bp->b_flags |= B_READ;
        (*strat)(bp);
 
@@ -109,7 +113,7 @@
        }
        for (dlp = (struct disklabel *)bp->b_data;
             dlp <= (struct disklabel *)
-               ((char *)bp->b_data + labelsz - sizeof(*dlp));
+               ((char *)bp->b_data + bsdlabelsz - sizeof(*dlp));
             dlp = (struct disklabel *)((uint8_t *)dlp + sizeof(long))) {
                if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
                        if (msg == NULL)
@@ -135,9 +139,7 @@
        bp->b_blkno = DOSPARTOFF * DEF_BSIZE / lp->d_secsize;
                                /* DOSPARTOFF in DEV_BSIZE unit */
        bp->b_cylinder = DOSBBSECTOR / lp->d_secpercyl;
-       labelsz = howmany(sizeof(struct cpu_disklabel),
-                         lp->d_secsize) * lp->d_secsize;
-       bp->b_bcount = labelsz; /* to support < 512B/sector disks */
+       bp->b_bcount = humanlabelsz;    /* to support < 512B/sector disks */
        bp->b_oflags &= ~(BO_DONE);
        (*strat)(bp);
 
@@ -313,7 +315,7 @@
        struct dos_partition *dp = 0;
        struct buf *bp;
        struct disklabel *dlp;
-       int error, labelsz, i;
+       int error, bsdlabelsz, humanlabelsz, i;
        const char *np;
 
        if (osdep)
@@ -326,15 +328,19 @@
                parttbl_consistency_check(lp, dp);
 
        /* get a buffer and initialize it */
-       bp = geteblk((int)lp->d_secsize);
+       bsdlabelsz =
+           howmany(LABELOFFSET + sizeof(struct disklabel), lp->d_secsize)
+           * lp->d_secsize;
+       humanlabelsz =
+           howmany(sizeof(struct cpu_disklabel), lp->d_secsize)
+           * lp->d_secsize;
+       bp = geteblk(MAX(bsdlabelsz, humanlabelsz));
        bp->b_dev = dev;
 
        /* attempt to write BSD disklabel first */
        bp->b_blkno = LABELSECTOR;
        bp->b_cylinder = LABELSECTOR / lp->d_secpercyl;
-       labelsz = howmany(LABELOFFSET+sizeof(struct disklabel), lp->d_secsize)
-               * lp->d_secsize;
-       bp->b_bcount = labelsz; /* to support < 512B/sector disks */
+       bp->b_bcount = bsdlabelsz;      /* to support < 512B/sector disks */
        bp->b_flags |= B_READ;
        (*strat)(bp);
 
@@ -344,7 +350,7 @@
        error = ESRCH;
        for (dlp = (struct disklabel *)bp->b_data;
             dlp <= (struct disklabel *)
-               ((char *)bp->b_data + labelsz - sizeof(*dlp));
+               ((char *)bp->b_data + bsdlabelsz - sizeof(*dlp));
             dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
                if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
                    dkcksum(dlp) == 0) {
@@ -370,6 +376,7 @@
                bp->b_blkno = DOSBBSECTOR;
                bp->b_bcount = lp->d_secsize;
                bp->b_oflags &= ~(BO_DONE);
+               bp->b_flags &= ~(B_WRITE);
                bp->b_flags |= B_READ;
                bp->b_cylinder = DOSBBSECTOR / lp->d_secpercyl;
                (*strat)(bp);
@@ -379,10 +386,9 @@
 
                /* read the partition table */
                bp->b_blkno = DOSPARTOFF;
-               labelsz = howmany(sizeof(struct cpu_disklabel),
-                                 lp->d_secsize) * lp->d_secsize;
-               bp->b_bcount = labelsz;
+               bp->b_bcount = humanlabelsz;
                bp->b_oflags &= ~(BO_DONE);
+               bp->b_flags &= ~(B_WRITE);
                bp->b_flags |= B_READ;
                bp->b_cylinder = DOSPARTOFF / lp->d_secpercyl;
                (*strat)(bp);



Home | Main Index | Thread Index | Old Index