Message ID | 20230709011213.17890-1-astrajoan@yahoo.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | drm/modes: Fix division by zero error | expand |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Not a local patch |
Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-and-tested-by: syzbot+622bba18029bcde672e1@syzkaller.appspotmail.com Tested on: commit: 1c7873e3 mm: lock newly mapped VMA with corrected orde.. git tree: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master console output: https://syzkaller.appspot.com/x/log.txt?x=101196d2a80000 kernel config: https://syzkaller.appspot.com/x/.config?x=8f6b0c7ae2c9c303 dashboard link: https://syzkaller.appspot.com/bug?extid=622bba18029bcde672e1 compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2 patch: https://syzkaller.appspot.com/x/patch.diff?x=10e44354a80000 Note: testing is done by a robot and is best-effort only.
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ac9a406250c5..aa98bd7b8bc9 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1285,13 +1285,13 @@ EXPORT_SYMBOL(drm_mode_set_name); */ int drm_mode_vrefresh(const struct drm_display_mode *mode) { - unsigned int num, den; + unsigned long long num, den; if (mode->htotal == 0 || mode->vtotal == 0) return 0; - num = mode->clock; - den = mode->htotal * mode->vtotal; + num = mul_u32_u32(mode->clock, 1000); + den = mul_u32_u32(mode->htotal, mode->vtotal); if (mode->flags & DRM_MODE_FLAG_INTERLACE) num *= 2; @@ -1300,7 +1300,10 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode) if (mode->vscan > 1) den *= mode->vscan; - return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(num, 1000), den); + if (unlikely(den >> 32)) + return div64_u64(num + (den >> 1), den); + else + return DIV_ROUND_CLOSEST_ULL(num, (unsigned int) den); } EXPORT_SYMBOL(drm_mode_vrefresh);
In the bug reported by Syzbot, the variable `den == (1 << 22)` and `mode->vscan == (1 << 10)`, causing the multiplication to overflow and accidentally make `den == 0`. To prevent any chance of overflow, we replace `num` and `den` with 64-bit unsigned integers, and explicitly check if the divisor `den` will overflow. If so, we employ full 64-bit division with rounding; otherwise we keep the 64-bit to 32-bit division that could potentially be better optimized. In order to minimize the performance overhead, the overflow check for `den` is wrapped with an `unlikely` condition. Please let me know if this usage is appropriate. #syz test: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master Signed-off-by: Ziqi Zhao <astrajoan@yahoo.com> --- drivers/gpu/drm/drm_modes.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)