โฌข DragonFlyBSD Kernel Audit
DF-3912 / trigger_analysis.c
โ† back to finding โ†“ download raw
/*
 * DF-3912 trigger/analysis โ€” signed underflow livelock in
 * mpt_recv_handshake_reply() (sys/dev/disk/mpt/mpt.c:1475-1491)
 *
 * Kernel path (hardware-gated: LSI MPT Fusion IOC โ€” malicious or faulty):
 *   hdr->MsgLength is an IOC-supplied byte count (in dwords) of the
 *   handshake reply.  The driver computes
 *       left = (hdr->MsgLength << 1) - 2;          [mpt.c:1475]
 *   and then loops
 *       while (left--) {                           [mpt.c:1477]
 *           if (mpt_wait_db_int(mpt) != MPT_OK) return ETIMEDOUT;
 *           data = mpt_read(mpt, MPT_OFFSET_DOORBELL);
 *           ...
 *       }
 *   With MsgLength == 0 (or any value < 2) `left` becomes negative (-2) and
 *   `left--` is always non-zero: the loop can only exit when the IOC stops
 *   asserting the doorbell interrupt for MPT_MAX_WAIT (300000 x 100us = 30s)
 *   consecutive polls.  A malicious IOC that keeps MPT_DB_INTR asserted
 *   spins the attach thread forever inside mpt_wait_db_int()/DELAY() with
 *   MPT_LOCK held -> boot/attach hang (kernel livelock DoS).
 *
 * This harness demonstrates the loop-condition arithmetic (bounded here only
 * by the harness counter; in the kernel no such bound exists).
 */
#include <stdio.h>

int main(void)
{
    int      left;
    unsigned msg_length = 0;          /* IOC-supplied MsgLength */
    unsigned iterations = 0;

    left = (msg_length << 1) - 2;     /* == -2 : mpt.c:1475 */
    printf("MsgLength=%u -> left=%d\n", msg_length, left);

    while (left--) {                  /* mpt.c:1477 โ€” always true for left<0 */
        iterations++;
        if (iterations >= 100000000)  /* harness bound; kernel has none */
            break;
    }
    printf("loop ran %u iterations and %s naturally (kernel: never exits\n"
           "while the IOC keeps the doorbell interrupt asserted; up to 30s\n"
           "spin per mpt_wait_db_int otherwise)\n",
           iterations, iterations < 100000000 ? "exited" : "was cut off by the harness");
    return (iterations >= 100000000) ? 1 : 0;
}