5d360b
From 7f476950b0f5780d1112f8e9d0d92ece55ae6912 Mon Sep 17 00:00:00 2001
5d360b
From: Richard Jones <rjones@redhat.com>
5d360b
Date: Wed, 1 Nov 2017 11:33:00 +0100
5d360b
Subject: [PATCH 5/7] i6300esb: Fix signed integer overflow
5d360b
5d360b
RH-Author: Richard Jones <rjones@redhat.com>
5d360b
Message-id: <1509535982-27927-2-git-send-email-rjones@redhat.com>
5d360b
Patchwork-id: 77461
5d360b
O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 1/3] i6300esb: Fix signed integer overflow
5d360b
Bugzilla: 1470244
5d360b
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
5d360b
RH-Acked-by: Thomas Huth <thuth@redhat.com>
5d360b
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
5d360b
5d360b
From: David Gibson <david@gibson.dropbear.id.au>
5d360b
5d360b
If the guest programs a sufficiently large timeout value an integer
5d360b
overflow can occur in i6300esb_restart_timer().  e.g. if the maximum
5d360b
possible timer preload value of 0xfffff is programmed then we end up with
5d360b
the calculation:
5d360b
5d360b
timeout = get_ticks_per_sec() * (0xfffff << 15) / 33000000;
5d360b
5d360b
get_ticks_per_sec() returns 1000000000 (10^9) giving:
5d360b
5d360b
     10^9 * (0xfffff * 2^15) == 0x1dcd632329b000000 (65 bits)
5d360b
5d360b
Obviously the division by 33MHz brings it back under 64-bits, but the
5d360b
overflow has already occurred.
5d360b
5d360b
Since signed integer overflow has undefined behaviour in C, in theory this
5d360b
could be arbitrarily bad.  In practice, the overflowed value wraps around
5d360b
to something negative, causing the watchdog to immediately expire, killing
5d360b
the guest, which is still fairly bad.
5d360b
5d360b
The bug can be triggered by running a Linux guest, loading the i6300esb
5d360b
driver with parameter "heartbeat=2046" and opening /dev/watchdog.  The
5d360b
watchdog will trigger as soon as the device is opened.
5d360b
5d360b
This patch corrects the problem by using muldiv64(), which effectively
5d360b
allows a 128-bit intermediate value between the multiplication and
5d360b
division.
5d360b
5d360b
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
5d360b
Message-Id: <1427075508-12099-3-git-send-email-david@gibson.dropbear.id.au>
5d360b
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5d360b
(cherry picked from commit 4bc7b4d56657ebf75b986ad46e959cf7232ff26a)
5d360b
5d360b
BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1470244
5d360b
Upstream-status: 4bc7b4d56657ebf75b986ad46e959cf7232ff26a
5d360b
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
5d360b
---
5d360b
 hw/watchdog/wdt_i6300esb.c | 10 ++++++++--
5d360b
 1 file changed, 8 insertions(+), 2 deletions(-)
5d360b
5d360b
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
5d360b
index a2ace52..be35034 100644
5d360b
--- a/hw/watchdog/wdt_i6300esb.c
5d360b
+++ b/hw/watchdog/wdt_i6300esb.c
5d360b
@@ -125,8 +125,14 @@ static void i6300esb_restart_timer(I6300State *d, int stage)
5d360b
     else
5d360b
         timeout <<= 5;
5d360b
 
5d360b
-    /* Get the timeout in units of ticks_per_sec. */
5d360b
-    timeout = get_ticks_per_sec() * timeout / 33000000;
5d360b
+    /* Get the timeout in units of ticks_per_sec.
5d360b
+     *
5d360b
+     * ticks_per_sec is typically 10^9 == 0x3B9ACA00 (30 bits), with
5d360b
+     * 20 bits of user supplied preload, and 15 bits of scale, the
5d360b
+     * multiply here can exceed 64-bits, before we divide by 33MHz, so
5d360b
+     * we use a higher-precision intermediate result.
5d360b
+     */
5d360b
+    timeout = muldiv64(get_ticks_per_sec(), timeout, 33000000);
5d360b
 
5d360b
     i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
5d360b
 
5d360b
-- 
5d360b
1.8.3.1
5d360b