DF-3689 / vddind_oob_read.c
/* * DF-3689 harness: unvalidated VBIOS vddInd (u8) used as an index into the * voltage-lookup table in smu7_patch_voltage_dependency_tables_with_lookup_table * (smu7_hwmgr.c:1865-1869, 1872-1876, 1878-1882) and * smu7_patch_voltage_workaround (:2135). * * The lookup table is allocated by get_vddc_lookup_table * (process_pptables_v1_0.c:160-190) for max_levels=16 records, while dep * records carry a raw ucVddcInd u8 (0..255) from VBIOS with no range check. * The harness reproduces the read arithmetic against the real allocation * geometry and shows OOB reads landing past the table. */ #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> struct lookup_record { uint16_t us_calculated, us_vdd, us_cac_low, us_cac_mid, us_cac_high; }; struct lookup_table { uint32_t count; /* = ucNumEntries from VBIOS */ struct lookup_record entries[16]; /* allocation per max_levels=16 */ }; struct dep_record { uint32_t clk; uint8_t vddInd; }; struct dep_table { uint32_t count; struct dep_record entries[255]; }; int main(void) { /* allocation geometry as in process_pptables_v1_0.c:168-171 */ struct lookup_table *lk = calloc(1, sizeof(uint32_t) + 16 * sizeof(struct lookup_record)); struct dep_table dep; int i, oob_reads = 0; if (!lk) return 1; lk->count = 4; /* VBIOS says 4 lookup entries */ dep.count = 255; for (i = 0; i < 255; i++) dep.entries[i].vddInd = (uint8_t)(i * 7); /* crafted u8 indices */ printf("lookup table: %zu usable records (max_levels=16), count field=%u\n", (size_t)(16), lk->count); /* verbatim loop shape from smu7_hwmgr.c:1865-1869 */ for (i = 0; i < (int)dep.count; i++) { uint8_t voltage_id = dep.entries[i].vddInd; /* kernel does: vddc = vddc_lookup_table->entries[voltage_id].us_vdd; */ size_t idx_bytes = sizeof(uint32_t) + 16 * sizeof(struct lookup_record); if ((size_t)voltage_id * sizeof(struct lookup_record) + sizeof(uint32_t) >= idx_bytes) oob_reads++; } printf("dep entries whose vddInd read lands past the 16-record kmalloc: %d / %d\n", oob_reads, (int)dep.count); printf("max index 255 -> byte offset %llu past entries[0] (allocation holds " "%zu bytes of entries)\n", (unsigned long long)255 * sizeof(struct lookup_record), (size_t)(16 * sizeof(struct lookup_record))); if (oob_reads > 0) { printf("RESULT: HEAP OOB READ CONFIRMED at the arithmetic level - u8 vddInd " "indexes up to 255 into a 16-record table (also OOB vs count=%u)\n", lk->count); return 0; } fprintf(stderr, "RESULT: OOB read not observed\n"); return 1; } |