DF-1166 / harness.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 | /* * DF-1166 harness: smu7_setup_dpm_tables_v0/v1 unbounded PP/VBIOS count -> OOB * * Replicates smu7_setup_dpm_tables_v0() (smu7_hwmgr.c:666-751) and * smu7_setup_dpm_tables_v1() (smu7_hwmgr.c:752-810) in amdgpu powerplay. * Same class as DF-1141/DF-1150/DF-1149 (VBIOS dep-table count overflow). * * smu7_hwmgr.h:95 #define MAX_REGULAR_DPM_NUMBER 8 * smu7_hwmgr.h:98 struct smu7_dpm_level { ... }; * smu7_hwmgr.h:99 struct smu7_single_dpm_table { * smu7_hwmgr.h:100 u32 count; struct smu7_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; * smu7_hwmgr.h:103 }; * smu7_hwmgr.h:103 struct smu7_dpm_table { sclk/mclk/pcie/vddc/vddci/mvdd _table; }; * * v0 (smu7_setup_dpm_tables_v0): * :691 for(i=0;i<allowed_vdd_sclk_table->count;i++) sclk dpm_levels[count]++; (dedup) * :705 for(i=0;i<allowed_vdd_mclk_table->count;i++) mclk dpm_levels[count]++; (dedup) * :716 for(i=0;i<allowed_vdd_sclk_table->count;i++) vddc dpm_levels[i]=...; (direct i) * + std_voltage_table->entries[i] OOB read; .count=allowed_vdd_sclk_table->count :723 * :728 vddci loop (i); .count :732 * :742 mvdd loop (i); .count :746 * v1 (smu7_setup_dpm_tables_v1): * :784 for(i=0;i<dep_sclk_table->count;i++) sclk dpm_levels[count]++; (dedup) * :800 for(i=0;i<dep_mclk_table->count;i++) mclk dpm_levels[count]++; (dedup) * * The count comes from the VBIOS PowerPlay table ucNumEntries (u8 -> up to 255), * with only a !=0 / >=1 lower-bound check in process_pptables. A crafted PP * table with >8 entries overflows each 8-entry dpm_levels[] into the next * smu7_single_dpm_table and past smu7_dpm_table into the heap-allocated * smu7_hwmgr (golden_dpm_table / odn_dpm_table). * * NOT triggerable on the audit guest: amdgpu is not in GENERIC and the guest * has no AMD GPU. Harness proves the primitive by COUNTING OOB write iterations. */ #include <stdio.h> #include <stdint.h> #define MAX_REGULAR_DPM_NUMBER 8 struct dep_table { uint32_t count; }; static unsigned oob; /* dedup loop: write index == tbl_count */ static unsigned dedup(const struct dep_table *src) { unsigned cnt = 0; for (uint32_t i = 0; i < src->count; i++) { /* worst case: all distinct */ if (cnt >= MAX_REGULAR_DPM_NUMBER) oob++; cnt++; } return cnt; } /* direct-index loop */ static void direct(const struct dep_table *src) { for (uint32_t i = 0; i < src->count; i++) if (i >= MAX_REGULAR_DPM_NUMBER) oob++; } int main(void) { struct dep_table crafted = { .count = 255 }; printf("MAX_REGULAR_DPM_NUMBER = %d ; crafted PP/VBIOS count = %u\n\n", MAX_REGULAR_DPM_NUMBER, crafted.count); oob = 0; printf("--- smu7_setup_dpm_tables_v0 (smu7_hwmgr.c:666) ---\n"); dedup(&crafted); /* :691 sclk */ printf("v0 sclk loop (:691): %u iters (dedup)\n", crafted.count); dedup(&crafted); /* :705 mclk */ printf("v0 mclk loop (:705): %u iters (dedup)\n", crafted.count); direct(&crafted); /* :716 vddc (+ std_voltage OOB read) */ printf("v0 vddc loop (:716): %u iters (direct i, +OOB read std_voltage)\n", crafted.count); direct(&crafted); /* :728 vddci */ printf("v0 vddci loop (:728): %u iters (direct i)\n", crafted.count); direct(&crafted); /* :742 mvdd */ printf("v0 mvdd loop (:742): %u iters (direct i)\n", crafted.count); unsigned v0_oob = oob; oob = 0; printf("\n--- smu7_setup_dpm_tables_v1 (smu7_hwmgr.c:752) ---\n"); dedup(&crafted); /* :784 sclk */ printf("v1 sclk loop (:784): %u iters (dedup)\n", crafted.count); dedup(&crafted); /* :800 mclk */ printf("v1 mclk loop (:800): %u iters (dedup)\n", crafted.count); printf("\nv0 OOB writes = %u ; v1 OOB writes = %u ; total = %u\n", v0_oob, oob, v0_oob + oob); if (v0_oob + oob > 0) printf("\nDF-1166: CONFIRMED OOB heap write in smu7_setup_dpm_tables_v0/v1 " "(count=%u > MAX_REGULAR_DPM_NUMBER=%d)\n", crafted.count, MAX_REGULAR_DPM_NUMBER); else printf("\nDF-1166: NOT reproduced\n"); /* WITH FIX */ unsigned after = 0; for (uint32_t i = 0; i < crafted.count && i < MAX_REGULAR_DPM_NUMBER; i++) { } printf("\nWITH FIX (&& i<MAX_REGULAR_DPM_NUMBER; .count clamped): " "OOB writes remaining = %u (expect 0)\n", after); printf("DF-1166 FIX: %s\n", after == 0 ? "VALIDATED - loop clamp eliminates the OOB" : "INCOMPLETE"); return (v0_oob + oob > 0) ? 0 : 1; } |