diff mbox

[06/23] hpet: fix buffer overrun on invalid state load

Message ID 1386087086-3691-7-git-send-email-mst@redhat.com
State New
Headers show

Commit Message

Michael S. Tsirkin Dec. 3, 2013, 4:28 p.m. UTC
CVE-2013-4527 hw/timer/hpet.c buffer overrun

hpet is a VARRAY with a uint8 size but static array of 32

To fix, make sure num_timers is valid using post_load hook.

Reported-by: Anthony Liguori <anthony@codemonkey.ws>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/timer/hpet.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

Comments

Peter Maydell Dec. 3, 2013, 6:39 p.m. UTC | #1
On 3 December 2013 16:28, Michael S. Tsirkin <mst@redhat.com> wrote:
> CVE-2013-4527 hw/timer/hpet.c buffer overrun
>
> hpet is a VARRAY with a uint8 size but static array of 32
>
> To fix, make sure num_timers is valid using post_load hook.
>
> Reported-by: Anthony Liguori <anthony@codemonkey.ws>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>  hw/timer/hpet.c | 18 +++++++++++++-----
>  1 file changed, 13 insertions(+), 5 deletions(-)
>
> diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
> index 2eb75ea..acdc874 100644
> --- a/hw/timer/hpet.c
> +++ b/hw/timer/hpet.c
> @@ -211,6 +211,15 @@ static void update_irq(struct HPETTimer *timer, int set)
>      }
>  }
>
> +static void hpet_fix_num_timers(HPETState *s)
> +{
> +    if (s->num_timers < HPET_MIN_TIMERS) {
> +        s->num_timers = HPET_MIN_TIMERS;
> +    } else if (s->num_timers > HPET_MAX_TIMERS) {
> +        s->num_timers = HPET_MAX_TIMERS;
> +    }
> +}
> +
>  static void hpet_pre_save(void *opaque)
>  {
>      HPETState *s = opaque;
> @@ -232,6 +241,8 @@ static int hpet_post_load(void *opaque, int version_id)
>  {
>      HPETState *s = opaque;
>
> +    hpet_fix_num_timers(s);

Haven't we already overrun the buffer at this point?

thanks
-- PMM
diff mbox

Patch

diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 2eb75ea..acdc874 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -211,6 +211,15 @@  static void update_irq(struct HPETTimer *timer, int set)
     }
 }
 
+static void hpet_fix_num_timers(HPETState *s)
+{
+    if (s->num_timers < HPET_MIN_TIMERS) {
+        s->num_timers = HPET_MIN_TIMERS;
+    } else if (s->num_timers > HPET_MAX_TIMERS) {
+        s->num_timers = HPET_MAX_TIMERS;
+    }
+}
+
 static void hpet_pre_save(void *opaque)
 {
     HPETState *s = opaque;
@@ -232,6 +241,8 @@  static int hpet_post_load(void *opaque, int version_id)
 {
     HPETState *s = opaque;
 
+    hpet_fix_num_timers(s);
+
     /* Recalculate the offset between the main counter and guest time */
     s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 
@@ -719,11 +730,8 @@  static void hpet_realize(DeviceState *dev, Error **errp)
         sysbus_init_irq(sbd, &s->irqs[i]);
     }
 
-    if (s->num_timers < HPET_MIN_TIMERS) {
-        s->num_timers = HPET_MIN_TIMERS;
-    } else if (s->num_timers > HPET_MAX_TIMERS) {
-        s->num_timers = HPET_MAX_TIMERS;
-    }
+    hpet_fix_num_timers(s);
+
     for (i = 0; i < HPET_MAX_TIMERS; i++) {
         timer = &s->timer[i];
         timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer);