DragonFlyBSD Kernel Audit
DF-1259 / mfi_stp_oob.c
← back to finding ↓ download raw
/*
 * DF-1259 trigger PoC — mfi_stp_cmd unbounded SGE loop corrupts mfi_softc.
 *
 * Bug (sys/dev/raid/mfi/mfi.c:2725 mfi_stp_cmd):
 *   uint8_t i;                                              (loop var)
 *   for (i = 0; i < ioc->mfi_sge_count; i++) {              (~:2747)
 *       bus_dma_tag_create(..., &sc->mfi_kbuff_arr_dmat[i]); // sized [2]
 *       bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i], ...&sc->kbuff_arr[i]);
 *       bus_dmamap_load(..., &sc->mfi_kbuff_arr_busaddr[i]); // sized [2]
 *       kern_sge[i].phys_addr = ...;                        // mfi_sgl sized [2]
 *       cm->cm_frame->stp.sgl.sg64[i].addr = ...;           // sg64 sized [2]
 *       copyin(ioc->mfi_sgl[i].iov_base, sc->kbuff_arr[i], ioc->mfi_sgl[i].iov_len);
 *   }
 *   mfivar.h:196-198  mfi_kbuff_arr_dmat[2] / _dmamap[2] / _busaddr[2]
 *   mfireg.h:591-598  struct mfi_stp_frame { ...; sg32[2]; sg64[2]; }
 *   The native MFI_CMD path has NO MAX_IOCTL_SGE cap before calling
 *   mfi_stp_cmd.  mfi_sge_count >= 3 -> index 2 writes OOB past the [2]
 *   arrays into the adjacent mfi_softc fields (mfi_comms, frame structs).
 *   (uint8_t i additionally wraps at 256, secondary.)
 *
 * Reachability on the audit guest:
 *   As with DF-1258, the /dev/mfi%d node only exists once mfi attaches to an
 *   LSI MegaRAID SAS controller (absent on this QEMU guest).  The STP command
 *   path is additionally gated on a user frame with header.cmd == MFI_CMD_STP.
 *   This program reports the device-absence to make the result unambiguous.
 *
 * Build:  cc -o mfi_stp_oob mfi_stp_oob.c
 * Run:    ./mfi_stp_oob
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(void) {
    int fd = open("/dev/mfi0", O_RDWR);
    if (fd < 0) {
        printf("[DF-1259] open(\"/dev/mfi0\") failed: %s (errno=%d)\n",
               strerror(errno), errno);
        if (errno == ENOENT || errno == ENXIO)
            printf("[DF-1259] RESULT: /dev/mfi0 absent -> mfi not attached.\n"
                   "[DF-1259] The mfi_stp_cmd OOB write into mfi_softc is NOT\n"
                   "[DF-1259] reachable on this guest (no LSI MegaRAID HW).\n"
                   "[DF-1259] Bug confirmed in source at mfi.c:2747; latent on\n"
                   "[DF-1259] hardware-equipped hosts.\n");
        return 0;
    }
    close(fd);
    return 0;
}