[Bug 197881] boot1.efi UEFI system table corruption

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Sat Feb 21 16:51:33 UTC 2015


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197881

            Bug ID: 197881
           Summary: boot1.efi UEFI system table corruption
           Product: Base System
           Version: 10.1-RELEASE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs at FreeBSD.org
          Reporter: cmruffin at gmail.com

boot1.efi from 10.1-RELEASE can cause data corruption of its own UEFI system
table pointer in memory.

The EfiBlockIoProtocol instance associated with a CDROM parition typically has
a block size of 2048. boot1.efi assumes a block size of 512 in the call to
dskread() to read the superblock, yet the dskread() function in boot1.efi uses
the block size from the BlockIoProtocol instance.  This causes the call to
BlkIoProtocol->ReadBlocks() in dskread() to expose a larger-than-actual buffer
size to UEFI FW, which will cause the ReadBlocks() call to overrun the dmadat
buffer. 

So if a partition is present in the system with a block size of 2048 (such as
cdrom media partitions), boot1.efi can overrun its dmadat structure and cause
corruption of other global data including a global pointe r to the UEFI system
table. 

Failure sequence:
    1) dmadat.sbbuf  is allocated 8192 bytes at build time (SBLOCKSIZE)
    2) Boot1.efi retrieves handles with all instances  of BlockIoProtocol.
    3) If cdrom partition is present in the system, UEFI FW will return a
BlockIoProtocol of the CDROM partition which has a
BlockIoProtocol->Media->BlockSize = 2048.
    4) domount() is called for this BlockIoProtocol instance.
    5) fsread() is called to read the superblock
    6) Boot1.efi dskread() is called with nblk=16 (fixed SBLOCKSIZE (8192) /
fixed DEV_BSIZE (512)).  This is assuming a block size of 512.
    7) dskread() in boot1.efi  calls 

            status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
                nblk * bootdev->Media->BlockSize, buf);

    Here nblk=16 but bootdev->Media->BlockSize is 2048 which results in passing
a Buffer Size argument of 16 * 2048 = 32768 which overruns the dmadat->sbbuf 
fixed allocation.
    8) UEFI ReaadBlocks() overruns dmadat and overwrites the global pointer to
the UEFI system table (sets it to zero)
    9) A subsequent call to systab->BootServices->HandleProtocol() causes path
of exeution at physical address 0x98  which does not contain valid code.
    10) Processor eventually raises an invalid opcode exception.

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list