[RFC PATCH 2/2] hrtimer: Prevent overflow for relative refrences

From: Hongbo Yao
Date: Wed Mar 06 2019 - 08:01:02 EST


I ran Syzkaller testsuite, and got the following call trace.

===============================================================
UBSAN: Undefined behaviour in ../kernel/time/hrtimer.c:514:11
signed integer overflow:
9223372036854775807 - -240652746 cannot be represented in type 'long
long int'
CPU: 1 PID: 9308 Comm: trinity-c5 Not tainted 4.19.25-dirty #4
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014
Call Trace:
<IRQ>
dump_stack+0xdd/0x12a
ubsan_epilogue+0x10/0x65
handle_overflow+0x1a8/0x212
? val_to_string.constprop.2+0x137/0x137
? print_lock_contention_bug+0x190/0x190
? __next_base+0x2b/0xc0
? __hrtimer_run_queues+0xca/0x830
__ubsan_handle_sub_overflow+0x11/0x19
__hrtimer_next_event_base+0x1a9/0x1b0
__hrtimer_get_next_event+0x96/0x140
hrtimer_interrupt+0x391/0x610
smp_apic_timer_interrupt+0x137/0x3d0
apic_timer_interrupt+0xf/0x20

===============================================================

Use ktime_sub_safe() which has the necessary sanity checks in place and
limits the result to the valid range.

Signed-off-by: Hongbo Yao <yaohongbo@xxxxxxxxxx>
---
kernel/time/hrtimer.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index cadc5bcbfc9e..2195b35af085 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -527,7 +527,8 @@ static ktime_t __hrtimer_next_event_base(struct hrtimer_cpu_base *cpu_base,

timer = container_of(next, struct hrtimer, node);
}
- expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
+ expires = ktime_sub_safe(hrtimer_get_expires(timer),
+ base->offset);
if (expires < expires_next) {
expires_next = expires;

@@ -781,7 +782,8 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
struct hrtimer_clock_base *base = timer->base;
- ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset);
+ ktime_t expires = ktime_sub_safe(hrtimer_get_expires(timer),
+ base->offset);

WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0);

--
2.20.1