From 76b359a8784c15455da5374ece9f7b09358d5ccf Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Mon, 20 Apr 2026 12:28:16 +0200 Subject: [PATCH] x86/APIC: handle overflow in TMICT calculation With an expiry value on the order of 10 hours, and with a bus scale value of 256k (as supplied by qemu), the (signed) multiplication will be UB. As we've checked that the value is positive, we mean unsigned multiplication anyway. Yet let's play safe against even larger expiry and bus scale values, leveraging the compiler builtin that there is for this purpose. While there also drop the stray cast from the actual TMICT write. Fixes: 9062553a0dc1 ("added time and accurate timer support") Fixes: b95beb185810 ("x86: Clean up APIC local timer handling") Reported-by: Stewart Hildebrand Signed-off-by: Jan Beulich Acked-by: Andrew Cooper Tested-by: Stewart Hildebrand master commit: 4f14d97a620c3a005ad0604ae47ee6091281cda0 master date: 2026-04-16 10:29:54 +0200 --- xen/arch/x86/apic.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index 7747718600..a3e5ecdfbc 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -1224,10 +1224,16 @@ int reprogram_timer(s_time_t timeout) } if ( timeout && ((expire = timeout - NOW()) > 0) ) - apic_tmict = min_t(uint64_t, (bus_scale * expire) >> BUS_SCALE_SHIFT, - UINT32_MAX); + { + unsigned long product; - apic_write(APIC_TMICT, (unsigned long)apic_tmict); + apic_tmict = UINT32_MAX; + if ( !__builtin_umull_overflow(bus_scale, expire, &product) && + (product >>= BUS_SCALE_SHIFT) < apic_tmict ) + apic_tmict = product; + } + + apic_write(APIC_TMICT, apic_tmict); return apic_tmict || !timeout; }