DF-3912 / trigger_analysis.c
/* * 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; } |