DF-4426 / wrap_harness.c
/* * 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; } |