@samitouri / QOSamiQemu / commits / 4b6c088c88

mc146818rtc: Fix get_guest_rtc_ns() overflow bug

In get_guest_rtc_ns(), "s->base_rtc" is uint64_t, which multiplied by "NANOSECONDS_PER_SECOND" may overflow the uint64_t type, which will cause the QEMU Linux Virtual Machine's RTC time to jump and in turn triggers a kernel Soft Lockup and ultimately leads to a crash. Fix it by avoiding adding s->base_rtc in get_guest_rtc_ns_offset(), because get_guest_rtc_ns() is used either take the remainder of NANOSECONDS_PER_SECOND or take the quotient of NANOSECONDS_PER_SECOND. Fixes: 56038ef6234e ("RTC: Update the RTC clock only when reading it") Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com> Link: https://lore.kernel.org/r/20260114013257.3500578-1-ruanjinjie@huawei.com Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Jinjie Ruan committed Jan 14, 2026 at 09:32 UTC 4b6c088c88ccc9e7cafc72759c99742b3993f9f7
1 file changed +11 -12
hw/rtc/mc146818rtc.c
+11 -12
@@ -77,12 +77,13 @@ static inline bool rtc_running(MC146818RtcState *s)
77 (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20);
78 }
79
80 -static uint64_t get_guest_rtc_ns(MC146818RtcState *s)
80 +/*
81 + * Note: get_rtc_ns_since_last_update() does not include the base_rtc seconds
82 + * value. This does not matter if the caller only needs the nanoseconds part.
83 + */
84 +static uint64_t get_rtc_ns_since_last_update(MC146818RtcState *s)
85 {
82 - uint64_t guest_clock = qemu_clock_get_ns(rtc_clock);
83 -
84 - return s->base_rtc * NANOSECONDS_PER_SECOND +
85 - guest_clock - s->last_update + s->offset;
86 + return qemu_clock_get_ns(rtc_clock) - s->last_update + s->offset;
87 }
88
89 static void rtc_coalesced_timer_update(MC146818RtcState *s)
@@ -258,7 +259,7 @@ static void check_update_timer(MC146818RtcState *s)
259 return;
260 }
261
261 - guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND;
262 + guest_nsec = get_rtc_ns_since_last_update(s) % NANOSECONDS_PER_SECOND;
263 next_update_time = qemu_clock_get_ns(rtc_clock)
264 + NANOSECONDS_PER_SECOND - guest_nsec;
265
@@ -510,7 +511,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr,
511 /* if disabling set mode, update the time */
512 if ((s->cmos_data[RTC_REG_B] & REG_B_SET) &&
513 (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) {
513 - s->offset = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND;
514 + s->offset = get_rtc_ns_since_last_update(s) % NANOSECONDS_PER_SECOND;
515 rtc_set_time(s);
516 }
517 }
@@ -623,10 +624,8 @@ static void rtc_update_time(MC146818RtcState *s)
624 {
625 struct tm ret;
626 time_t guest_sec;
626 - int64_t guest_nsec;
627
628 - guest_nsec = get_guest_rtc_ns(s);
629 - guest_sec = guest_nsec / NANOSECONDS_PER_SECOND;
628 + guest_sec = s->base_rtc + get_rtc_ns_since_last_update(s) / NANOSECONDS_PER_SECOND;
629 gmtime_r(&guest_sec, &ret);
630
631 /* Is SET flag of Register B disabled? */
@@ -637,7 +636,7 @@ static void rtc_update_time(MC146818RtcState *s)
636
637 static int update_in_progress(MC146818RtcState *s)
638 {
640 - int64_t guest_nsec;
639 + uint64_t guest_nsec;
640
641 if (!rtc_running(s)) {
642 return 0;
@@ -652,7 +651,7 @@ static int update_in_progress(MC146818RtcState *s)
651 }
652 }
653
655 - guest_nsec = get_guest_rtc_ns(s);
654 + guest_nsec = get_rtc_ns_since_last_update(s);
655 /* UIP bit will be set at last 244us of every second. */
656 if ((guest_nsec % NANOSECONDS_PER_SECOND) >=
657 (NANOSECONDS_PER_SECOND - UIP_HOLD_LENGTH)) {