NetBSD-Bugs archive

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

port-i386/46583: BIOS bootloader problems with partitions that start above 1TB

>Number:         46583
>Category:       port-i386
>Synopsis:       BIOS bootloader problems with partitions that start above 1TB
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Jun 11 07:30:01 +0000 2012
>Originator:     Dave Huang
>Release:        NetBSD 6.99.7
Name: Dave Huang         |  Mammal, mammal / their names are called /
INet: |  they raise a paw / the bat, the cat /
FurryMUCK: Dahan         |  dolphin and dog / koala bear and hog -- TMBG
Dahan: Hani G Y+C 36 Y++ L+++ W- C++ T++ A+ E+ S++ V++ F- Q+++ P+ B+ PA+ PL++
NetBSD/x86 BIOS Boot, Revision 5.9 (from NetBSD 6.0_BETA2)
        The x86 BIOS bootloader has an integer overflow bug that
causes it to not see MBR partitions that start above 1TB (2^31 512-byte
blocks), even though the limit on MBR partitions is 2TB.
        Partition a disk with MBR-style partitioning and create a
NetBSD partition with a start LBA above 2^31, install the bootloader,
copy a kernel to the partition, and attempt to boot.

For example:
  Disk: /dev/rwd1d
  NetBSD disklabel disk geometry:
  cylinders: 3876021, heads: 16, sectors/track: 63 (1008 sectors/cylinder)
  total sectors: 3907029168

  BIOS disk geometry:
  cylinders: 1023, heads: 255, sectors/track: 63 (16065 sectors/cylinder)
  total sectors: 3907029168

  Partitions aligned to 2048 sector boundaries, offset 63

  Partition table:
  0: NTFS, OS/2 HPFS, QNX2 or Advanced UNIX (sysid 7)
      start 206848, size 3824902144 (1867628 MB, Cyls 12/223/20-238102/5/47)
  1: NetBSD (sysid 169)
      start 3825108992, size 81920176 (40000 MB, Cyls 
238102/5/48-243201/80/63), Active
  2: <UNUSED>
  3: <UNUSED>
  First active partition: 1
  Drive serial number: 2051726421 (0x7a4adc55)

When attempting to boot, the bootloader will run, but will be unable
to find the kernel, or even the partition that the kernel is on:

  booting hd0a:netbsd - starting in 0 seconds.
  open netbsd:  Input/output error
  boot: hd0a:netbsd:  Input/output error
  booting hd0a:netbsd.gz
  open netbsd.gz:  Input/output error
  boot: hd0a:netbsd.gz: Input/output error
  > dev
  disk hd0 size 1863 GB
[ note that no partitions are listed ]

Compiling the bootloader with -DDISK_DEBUG shows that the sector
number is overflowing a signed 32-bit int:

  ptn type 7 in sector 206848
  ptn type 169 in sector -469858304
  read error dblk -469858303--469858286

Not sure whether uint32_t or daddr_t is more correct--I went with the
former, since MBR partition LBAs are 32 bits.

Index: sys/arch/i386/stand/lib/biosdisk.c
RCS file: /cvsroot/src/sys/arch/i386/stand/lib/biosdisk.c,v
retrieving revision 1.40
diff -u -p -r1.40 biosdisk.c
--- sys/arch/i386/stand/lib/biosdisk.c  16 Jan 2012 18:47:57 -0000      1.40
+++ sys/arch/i386/stand/lib/biosdisk.c  11 Jun 2012 07:03:04 -0000
@@ -414,7 +414,7 @@ read_minix_subp(struct biosdisk *d, stru
        if (readsects(&d->ll, sector, 1, d->buf, 0)) {
 #ifdef DISK_DEBUG
-               printf("Error reading MFS sector %d\n", sector);
+               printf("Error reading MFS sector %ld\n", (long)sector);
                return EIO;
@@ -443,10 +443,11 @@ read_label(struct biosdisk *d)
        struct disklabel dflt_lbl;
        struct mbr_partition mbr[MBR_PART_COUNT];
        struct partition *p;
-       int sector, i;
+       uint32_t sector;
+       int i;
        int error;
        int typ;
-       int ext_base, this_ext, next_ext;
+       uint32_t ext_base, this_ext, next_ext;
        int sector_386bsd = -1;
@@ -471,7 +472,7 @@ read_label(struct biosdisk *d)
                next_ext = 0;
                if (readsects(&d->ll, this_ext, 1, d->buf, 0)) {
 #ifdef DISK_DEBUG
-                       printf("error reading MBR sector %d\n", this_ext);
+                       printf("error reading MBR sector %u\n", this_ext);
                        return EIO;
@@ -484,7 +485,7 @@ read_label(struct biosdisk *d)
                        sector = this_ext + mbr[i].mbrp_start;
 #ifdef DISK_DEBUG
-                       printf("ptn type %d in sector %d\n", typ, sector);
+                       printf("ptn type %d in sector %u\n", typ, sector);
                         if (typ == MBR_PTYPE_MINIX_14B) {
                                if (!read_minix_subp(d, &dflt_lbl,


Home | Main Index | Thread Index | Old Index