[PATCH] hw/rtc/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. 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> --- hw/rtc/mc146818rtc.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index ccbb279716..0311d567a9 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -77,12 +77,9 @@ static inline bool rtc_running(MC146818RtcState *s) (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20); } -static uint64_t get_guest_rtc_ns(MC146818RtcState *s) +static uint64_t get_guest_rtc_ns_offset(MC146818RtcState *s) { - uint64_t guest_clock = qemu_clock_get_ns(rtc_clock); - - return s->base_rtc * NANOSECONDS_PER_SECOND + - guest_clock - s->last_update + s->offset; + return qemu_clock_get_ns(rtc_clock) - s->last_update + s->offset; } static void rtc_coalesced_timer_update(MC146818RtcState *s) @@ -258,7 +255,7 @@ static void check_update_timer(MC146818RtcState *s) return; } - guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND; + guest_nsec = get_guest_rtc_ns_offset(s) % NANOSECONDS_PER_SECOND; next_update_time = qemu_clock_get_ns(rtc_clock) + NANOSECONDS_PER_SECOND - guest_nsec; @@ -510,7 +507,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, /* if disabling set mode, update the time */ if ((s->cmos_data[RTC_REG_B] & REG_B_SET) && (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) { - s->offset = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND; + s->offset = get_guest_rtc_ns_offset(s) % NANOSECONDS_PER_SECOND; rtc_set_time(s); } } @@ -623,10 +620,8 @@ static void rtc_update_time(MC146818RtcState *s) { struct tm ret; time_t guest_sec; - int64_t guest_nsec; - guest_nsec = get_guest_rtc_ns(s); - guest_sec = guest_nsec / NANOSECONDS_PER_SECOND; + guest_sec = s->base_rtc + get_guest_rtc_ns_offset(s) / NANOSECONDS_PER_SECOND; gmtime_r(&guest_sec, &ret); /* Is SET flag of Register B disabled? */ @@ -637,8 +632,6 @@ static void rtc_update_time(MC146818RtcState *s) static int update_in_progress(MC146818RtcState *s) { - int64_t guest_nsec; - if (!rtc_running(s)) { return 0; } @@ -652,9 +645,8 @@ static int update_in_progress(MC146818RtcState *s) } } - guest_nsec = get_guest_rtc_ns(s); /* UIP bit will be set at last 244us of every second. */ - if ((guest_nsec % NANOSECONDS_PER_SECOND) >= + if ((get_guest_rtc_ns_offset(s) % NANOSECONDS_PER_SECOND) >= (NANOSECONDS_PER_SECOND - UIP_HOLD_LENGTH)) { return 1; } -- 2.34.1
participants (1)
-
Jinjie Ruan