DF-1345 / trigger.c
/* AMD powerplay smumgr div0 triplet (DF-1323/1325/1345) * Ports the slope computation from iceland/fiji/polaris10 thermal_setup_fan_table. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <signal.h> #include <setjmp.h> static jmp_buf jb; static void on_fpe(int s){ longjmp(jb,1); } /* vulnerable slope computation */ static int slope_vuln(uint16_t usTMin, uint16_t usTMed, uint16_t usTHigh, uint16_t usPWMMin, uint16_t usPWMMed, uint16_t usPWMHigh, uint32_t duty100, uint16_t *s1, uint16_t *s2){ uint32_t t_diff1 = usTMed - usTMin; /* uint16 promotes to int; assign to u32 */ uint32_t t_diff2 = usTHigh - usTMed; uint32_t pwm_diff1 = usPWMMed - usPWMMin; uint32_t pwm_diff2 = usPWMHigh - usPWMMed; *s1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); *s2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); return 0; } /* fixed slope computation */ static int slope_fixed(uint16_t usTMin, uint16_t usTMed, uint16_t usTHigh, uint16_t usPWMMin, uint16_t usPWMMed, uint16_t usPWMHigh, uint32_t duty100, uint16_t *s1, uint16_t *s2){ uint32_t t_diff1 = usTMed - usTMin; uint32_t t_diff2 = usTHigh - usTMed; if (t_diff1 == 0 || t_diff2 == 0) return 1; /* disable microcode fan control */ uint32_t pwm_diff1 = usPWMMed - usPWMMin; uint32_t pwm_diff2 = usPWMHigh - usPWMMed; *s1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100); *s2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100); return 0; } int main(void){ signal(SIGFPE, on_fpe); /* malicious VBIOS: usTMed == usTMin -> t_diff1 == 0 */ uint16_t TMin=2500, TMed=2500, THigh=3500; /* 0.01C units */ uint16_t PWMMin=100, PWMMed=5000, PWMHigh=10000; uint32_t duty100=100; uint16_t s1, s2; printf("== BEFORE-FIX (vulnerable) ==\n"); if (setjmp(jb)==0){ slope_vuln(TMin,TMed,THigh,PWMMin,PWMMed,PWMHigh,duty100,&s1,&s2); printf("slope1=%u slope2=%u (no crash)\n", s1, s2); } else { printf("BUG: SIGFPE — integer divide by zero in slope1/slope2 (VBIOS t_diff==0)\n"); } printf("== AFTER-FIX ==\n"); int rc = slope_fixed(TMin,TMed,THigh,PWMMin,PWMMed,PWMHigh,duty100,&s1,&s2); if (rc == 0) printf("slope1=%u slope2=%u\n", s1, s2); else printf("FIX: t_diff==0 detected, fan control disabled (return 0)\n"); return 0; } |