|
|
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 |
|