⬢ DragonFlyBSD Kernel Audit
DF-4426 / wrap_harness.c
← back to finding ↓ download raw
/*
 * DF-4426 logic harness (host-side, userspace).
 *
 * Verbatim reproduction of the CMI enumeration loop from
 * sys/dev/acpica/acpi_hp/acpi_hp.c:1164-1204 (acpi_hp_hpcmi_read),
 * with the WMI layer stubbed to prove the UINT8 `instance` wraparound:
 *
 *   UINT8 maxInstance;
 *   maxInstance = sc->has_cmi;              // = max_instance+1, in [1,256]
 *   if (!(detail & SHOW_MAX_INSTANCE) && maxInstance > 0) maxInstance--;
 *   for (instance = 0; instance < maxInstance; ++instance) {
 *           if (get_cmi_block_fails(instance)) instance = maxInstance; // "break"
 *           ...
 *   }
 *
 * When has_cmi == 255 (WMI max_instance == 254) AND the SHOW_MAX_INSTANCE
 * detail bit is set, maxInstance stays 255. The error "break" assigns
 * instance = 255; the loop increment wraps UINT8 255 -> 0 and the loop
 * restarts from 0 forever (the loop variable is unsigned char).
 *
 * In the kernel this loop runs inside acpi_hp_hpcmi_read() while holding
 * ACPI_SERIAL_BEGIN(hp) (acpi_hp.c:1157) => unkillable thread + global
 * 'hp' lock held forever. If get_cmi_block() fails already at instance 0,
 * cmi_order_size never grows: this is a PURE infinite loop with no memory
 * write at all (distinct manifestation from the DF-2382 overflow sink).
 *
 * Build: cc -O2 -o wrap_harness wrap_harness.c
 * Run:   ./wrap_harness            (default: error-at-0 => pure hang, capped)
 *        ./wrap_harness 5          (error at instance 5 => restart forever)
 *        ./wrap_harness 254 noerr  (normal termination, no wrap)
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE 0x08

static int      err_at = -1;      /* instance index that makes WMI eval fail */
static uint64_t iterations;       /* loop body executions */
static uint64_t inserts;          /* cmi_order inserts (successful blocks)  */
static long     max_order_size;   /* high-water mark of cmi_order_size      */

int main(int argc, char **argv)
{
        uint8_t instance, maxInstance;
        int has_cmi = 255;        /* WMI GUID max_instance == 254 */
        int cmi_detail = ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE;
        long cmi_order_size = 0;
        uint64_t limit = 300000;  /* cap so the demo terminates */

        if (argc > 1) err_at = atoi(argv[1]);
        if (argc > 2 && argv[2][0] == 'n') err_at = -1;

        maxInstance = has_cmi;    /* acpi_hp.c:1165 (UINT8 = int truncation) */
        if (!(cmi_detail & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) &&
            maxInstance > 0)
                maxInstance--;    /* acpi_hp.c:1168 */

        printf("has_cmi=%d detail=0x%x => maxInstance=%u (0x%02x)\n",
               has_cmi, cmi_detail, maxInstance, maxInstance);

        for (instance = 0; instance < maxInstance; ++instance) {
                iterations++;
                if (err_at >= 0 && (int)instance >= err_at) {
                        /* acpi_hp_get_cmi_block() != 0 => acpi_hp.c:1178 */
                        instance = maxInstance;   /* the fatal assignment */
                } else {
                        inserts++;
                        if (++cmi_order_size > max_order_size)
                                max_order_size = cmi_order_size;
                }
                if (iterations >= limit)
                        break;    /* demo-only circuit breaker */
        }

        printf("loop exited after %llu body executions "
               "(%llu inserts, max cmi_order_size=%ld)\n",
               (unsigned long long)iterations,
               (unsigned long long)inserts, max_order_size);

        if (iterations >= limit) {
                printf("VERDICT: loop did NOT terminate on its own "
                       "(hit %llu-iteration demo cap) => wraparound "
                       "infinite loop CONFIRMED at the logic level\n",
                       (unsigned long long)limit);
                return 2;
        }
        printf("VERDICT: loop terminated normally (no wrap)\n");
        return 0;
}