DF-4141 / df4141_oob.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* * DF-4141 โ proof-of-primitive harness (userspace, no hardware required) * * File audited: sys/dev/netif/ath/ath_hal/ar5211/ar5211_reset.c * Function: ar5211GetLowerUpperValues() (lines 1813-1867) โ VERBATIM copy * * Defect: when invoked with listSize == 0 the function executes * * const uint16_t listEndValue = *(pList + listSize - 1); // :1818 * * i.e. loads 2 bytes BELOW the caller's array (pList[-1]), and then reads * the uninitialized *pList (tempChannelList[0]) at :1829. * * Kernel reachability (ar5211_reset.c:1528-1551): ar5211SetRateTable() * copies a CTL's RD_EDGES_POWER row into `uint16_t tempChannelList[NUM_EDGES]` * stopping at the first zero rdEdge; a matched CTL (ee_ctl[i] == cfgCtl != 0) * whose first edge is blanked (rdEdge == 0, twice_rdEdgePower == 0 โ a * degenerate/corrupt/crafted EEPROM image) leaves numEdges == 0 and the * stack array untouched, then calls * * ar5211GetLowerUpperValues(freq, tempChannelList, numEdges, ...) * * at :1537 -> pList[-1] OOB stack read + uninitialized stack read; the * resulting garbage lower/upper channel feeds twiceMaxEdgePower selection * (regulatory edge-power misprogramming). * * This harness places the array at the start of an mmap'd page whose * predecessor page is PROT_NONE, so the pList[-1] load faults. SUCCESS * CRITERION: the process dies exactly at the :1818 load (marker printed * by the SIGSEGV handler) โ proving the below-array read is real and * unconditional for listSize == 0. */ #include <sys/mman.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef int int32_t; #define EEP_SCALE 100 #define EEP_DELTA 10 /* ---- verbatim from ar5211_reset.c:1813-1867 ---- */ static void ar5211GetLowerUpperValues(uint16_t value, const uint16_t *pList, uint16_t listSize, uint16_t *pLowerValue, uint16_t *pUpperValue) { const uint16_t listEndValue = *(pList + listSize - 1); /* :1818 */ uint32_t target = value * EEP_SCALE; int i; *pLowerValue = 0; /* avoid gcc warnings */ *pUpperValue = 0; /* avoid gcc warnings */ if (target < (uint32_t)(*pList * EEP_SCALE - EEP_DELTA)) { *pLowerValue = *pList; *pUpperValue = *pList; return; } if (target > (uint32_t)(listEndValue * EEP_SCALE + EEP_DELTA)) { *pLowerValue = listEndValue; *pUpperValue = listEndValue; return; } for (i = 0; i < listSize; i++) { if (abs(pList[i] * EEP_SCALE - (int32_t) target) < EEP_DELTA) { *pLowerValue = pList[i]; *pUpperValue = pList[i]; return; } if (target < (uint32_t)(pList[i + 1] * EEP_SCALE - EEP_DELTA)) { *pLowerValue = pList[i]; *pUpperValue = pList[i + 1]; return; } } } /* ---- end verbatim ---- */ static const char *stage = "not-yet"; static void fault_handler(int sig) { printf("SIGSEGV (%s) โ OOB load below the array confirmed\n", stage); printf("RESULT: FAULTED at %s : primitive PROVEN\n", stage); fflush(stdout); _exit(33); /* distinctive exit code = proof */ } int main(void) { uint16_t *array; uint16_t lo, hi; void *base; long pg = sysconf(_SC_PAGESIZE); signal(SIGSEGV, fault_handler); signal(SIGBUS, fault_handler); /* two adjacent pages; first becomes PROT_NONE */ base = mmap(NULL, 2 * pg, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); if (base == MAP_FAILED) { perror("mmap"); return 1; } if (mprotect(base, pg, PROT_NONE) != 0) { perror("mprotect"); return 1; } /* array sits exactly at the start of the second page */ array = (uint16_t *)((char *)base + pg); memset(array, 0xAA, 64); /* whatever: must NOT be read below */ /* simulates ar5211SetRateTable:1530-1537 with a blanked CTL edge row */ stage = ":1818 *(pList + listSize - 1) with listSize=0 (numEdges=0)"; printf("calling ar5211GetLowerUpperValues(listSize=0) " "with array at page start, predecessor PROT_NONE...\n"); fflush(stdout); ar5211GetLowerUpperValues(2437 /* freq */, array, 0, &lo, &hi); /* * If the OOB load somehow did not fault (e.g. mapping granularity), * the uninitialized-array read at :1829 still produced garbage: */ printf("no fault: lower=%u upper=%u (from untouched stack)\n", lo, hi); printf("RESULT: NOT-FAULTED (weaker evidence of uninit read only)\n"); return 1; } |