DF-1334 / trigger.c
/* DF-1334 rv770_dpm multiple div0 sinks */ #include <stdio.h> #include <stdint.h> #include <signal.h> #include <setjmp.h> static jmp_buf jb; static void on_fpe(int s){ longjmp(jb,1); } static int populate_smc_t_vuln(int low_sclk, int med_sclk, int high_sclk, int rlp, int lmp, int rmp, int lhp){ /* a_d = low.sclk*(100-rlp) + med.sclk*lmp ; if both sclk=0 -> div0 */ int a_n = med_sclk*lmp + low_sclk*(150-rlp); /* R600_AH_DFLT=150 */ int a_d = low_sclk*(100-rlp) + med_sclk*lmp; return (low_sclk*100)/a_d + (a_n/a_d); /* div0 if a_d==0 */ } static int populate_smc_t_fixed(int low_sclk, int med_sclk, int high_sclk, int rlp, int lmp, int rmp, int lhp){ int a_n = med_sclk*lmp + low_sclk*(150-rlp); int a_d = low_sclk*(100-rlp) + med_sclk*lmp; if (a_d == 0) return 0; /* guard */ return (low_sclk*100)/a_d + (a_n/a_d); } static int sclk_ss_vuln(int ref_clock, int ref_div, int rate, int pct, int fbdiv){ int clk_s = ref_clock*5/(ref_div*rate); /* div0 if rate==0 or ref_div==0 */ int clk_v = pct*fbdiv/(clk_s*10000); /* div0 if clk_s==0 */ return clk_s+clk_v; } static int sclk_ss_fixed(int ref_clock, int ref_div, int rate, int pct, int fbdiv){ if (ref_div==0||rate==0) return 0; int clk_s = ref_clock*5/(ref_div*rate); if (clk_s==0) return 0; int clk_v = pct*fbdiv/(clk_s*10000); return clk_s+clk_v; } static int vddc_steps_vuln(int vddc_min, int vddc_max, int step){ return (vddc_max - vddc_min)/step + 1; /* div0 if step==0 */ } static int vddc_steps_fixed(int vddc_min, int vddc_max, int step){ if (step==0) return -1; /* EINVAL */ return (vddc_max - vddc_min)/step + 1; } int main(void){ signal(SIGFPE, on_fpe); printf("== BEFORE-FIX (vulnerable) ==\n"); if (setjmp(jb)==0){ populate_smc_t_vuln(0,0,0,5,5,5,5); } else printf("BUG: SIGFPE in rv770_populate_smc_t (a_d==0 when VBIOS sclk=0)\n"); if (setjmp(jb)==0){ sclk_ss_vuln(27000, 1, 0, 10, 50); } else printf("BUG: SIGFPE in rv770_populate_sclk_value (VBIOS SS rate<100 -> /100 trunc=0)\n"); if (setjmp(jb)==0){ vddc_steps_vuln(500, 1100, 0); } else printf("BUG: SIGFPE in rv770_construct_vddc_table (step==0 from radeon_atom_get_voltage_step -EINVAL)\n"); printf("== AFTER-FIX ==\n"); populate_smc_t_fixed(0,0,0,5,5,5,5); printf("FIX: a_d==0 guarded, no division\n"); sclk_ss_fixed(27000,1,0,10,50); printf("FIX: rate/ref_div==0 guarded\n"); vddc_steps_fixed(500,1100,0); printf("FIX: step==0 returns -EINVAL\n"); return 0; } |