DF-1353 / trigger.c
/* DF-1353 vega12_force_clock_level OOB dpm_levels[16+] */ #include <stdio.h> #include <stdint.h> #include <string.h> #define MAX_REGULAR_DPM_NUMBER 16 struct dpm_table { uint32_t count; uint32_t levels[MAX_REGULAR_DPM_NUMBER]; }; static uint32_t read_oob_count_vuln; static int force_lvl_vuln(struct dpm_table *t, uint32_t mask, uint32_t *out){ /* soft_min_level = ffs(mask)-1 ; soft_max_level = fls(mask)-1 */ uint32_t soft_min = mask ? (__builtin_ffs(mask)-1) : 0; uint32_t soft_max = mask ? (31 - __builtin_clz(mask)) : 0; if (soft_max >= MAX_REGULAR_DPM_NUMBER) read_oob_count_vuln++; if (soft_min >= MAX_REGULAR_DPM_NUMBER) read_oob_count_vuln++; /* dpm_levels[soft_min/max].value */ *out = t->levels[soft_min] + t->levels[soft_max]; /* OOB read if mask bit >= 16 */ return 0; } static int force_lvl_fixed(struct dpm_table *t, uint32_t mask, uint32_t *out){ uint32_t soft_min = mask ? (__builtin_ffs(mask)-1) : 0; uint32_t soft_max = mask ? (31 - __builtin_clz(mask)) : 0; if (soft_min >= t->count || soft_max >= t->count) return -1; *out = t->levels[soft_min] + t->levels[soft_max]; return 0; } int main(void){ struct dpm_table t; memset(&t, 0, sizeof(t)); t.count = 5; printf("== BEFORE-FIX (vulnerable) ==\n"); uint32_t out; read_oob_count_vuln = 0; force_lvl_vuln(&t, 0x80000000, &out); /* bit 31 set -> soft_max=31, OOB read dpm_levels[31] */ printf("BUG: mask=0x80000000 -> soft_max=31, reads dpm_levels[31] past 16-element array (OOB reads: %u)\n", read_oob_count_vuln); printf("== AFTER-FIX ==\n"); int rc = force_lvl_fixed(&t, 0x80000000, &out); printf("FIX: soft_max=31 >= count=%u -> return -EINVAL (rc=%d)\n", t.count, rc); return 0; } |