qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Robert Reif <reif@earthlink.net>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] buffer overruns in qemu-system-sparc (hw/eccmemctl.c: ecc_reset())
Date: Tue, 17 Jun 2008 19:38:59 -0400	[thread overview]
Message-ID: <48584B13.7000503@earthlink.net> (raw)
In-Reply-To: <200806172235.19974.jseward@acm.org>

[-- Attachment #1: Type: text/plain, Size: 4713 bytes --]

Julian Seward wrote:
> This is in qemu svn trunk.
>
> Running 'qemu-system-sparc -M SS-10' (or SS-20) produces a bunch of
> invalid writes in hw/eccmemctl.c: ecc_reset(), as shown at the end
> of this message.  Sometimes these are sufficiently severe to corrupt
> the heap and cause glibc to abort qemu.  Problem does not happen with
> -M SS-5.
>
> The writes are caused by
>
> 290:    s->regs[ECC_VCR] = 0;
> 291:    s->regs[ECC_MFAR0] = 0x07c00000;
> 292:    s->regs[ECC_MFAR1] = 0;
>
> In fact all the assignments to s->regs[] are very strange.  regs[]
> is declared with 9 elements:
>
>   #define ECC_NREGS      9
>   ...
>   uint32_t regs[ECC_NREGS];
>
> so valid indices should be 0 .. 8.  But the constants ECC_* used to
> index in ..
>
> /* Register offsets */
> #define ECC_MER        0                /* Memory Enable Register */
> #define ECC_MDR        4                /* Memory Delay Register */
> #define ECC_MFSR       8                /* Memory Fault Status Register */
> #define ECC_VCR        12               /* Video Configuration Register */
> #define ECC_MFAR0      16               /* Memory Fault Address Register 0 */
> #define ECC_MFAR1      20               /* Memory Fault Address Register 1 */
> #define ECC_DR         24               /* Diagnostic Register */
> #define ECC_ECR0       28               /* Event Count Register 0 */
> #define ECC_ECR1       32               /* Event Count Register 1 */
>
> are register offsets, not indexes; AFAICS they should be divided by
> sizeof(uint32_t) before use.
>
> Even stranger .. at eccmemctl.c:297, having (incorrectly) filled in 
> s->regs[], there is a loop that zeroes all but one of the entries:
>
>     for (i = 1; i < ECC_NREGS; i++)
>         s->regs[i] = 0;
>
> The following kludge removes the invalid writes, but is not elegant,
> and still leaves the question of why the loop zeroes out the entries
> afterwards.
>
> J
>
> Index: hw/eccmemctl.c
> ===================================================================
> --- hw/eccmemctl.c      (revision 4744)
> +++ hw/eccmemctl.c      (working copy)
> @@ -281,18 +281,18 @@
>  static void ecc_reset(void *opaque)
>  {
>      ECCState *s = opaque;
> -    int i;
> +    int i, four = sizeof(s->regs[0]);
>
> -    s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL);
> -    s->regs[ECC_MER] |= ECC_MER_MRR;
> -    s->regs[ECC_MDR] = 0x20;
> -    s->regs[ECC_MFSR] = 0;
> -    s->regs[ECC_VCR] = 0;
> -    s->regs[ECC_MFAR0] = 0x07c00000;
> -    s->regs[ECC_MFAR1] = 0;
> -    s->regs[ECC_DR] = 0;
> -    s->regs[ECC_ECR0] = 0;
> -    s->regs[ECC_ECR1] = 0;
> +    s->regs[ECC_MER   / four] &= (ECC_MER_VER | ECC_MER_IMPL);
> +    s->regs[ECC_MER   / four] |= ECC_MER_MRR;
> +    s->regs[ECC_MDR   / four] = 0x20;
> +    s->regs[ECC_MFSR  / four] = 0;
> +    s->regs[ECC_VCR   / four] = 0;
> +    s->regs[ECC_MFAR0 / four] = 0x07c00000;
> +    s->regs[ECC_MFAR1 / four] = 0;
> +    s->regs[ECC_DR    / four] = 0;
> +    s->regs[ECC_ECR0  / four] = 0;
> +    s->regs[ECC_ECR1  / four] = 0;
>
>      for (i = 1; i < ECC_NREGS; i++)
>          s->regs[i] = 0;
>
>
> The original problem:
>
> ==21509== Invalid write of size 4
> ==21509==    at 0x42E056: ecc_reset (eccmemctl.c:290)
> ==21509==    by 0x42E149: ecc_init (eccmemctl.c:323)
> ==21509==    by 0x425E7F: sun4m_hw_init (sun4m.c:547)
> ==21509==    by 0x40D50E: main (vl.c:8609)
> ==21509==  Address 0x7af3c20 is 8 bytes after a block of size 48 alloc'd
> ==21509==    at 0x4C234BB: malloc (vg_replace_malloc.c:207)
> ==21509==    by 0x42F995: qemu_mallocz (qemu-malloc.c:44)
> ==21509==    by 0x42E0DA: ecc_init (eccmemctl.c:306)
> ==21509==    by 0x425E7F: sun4m_hw_init (sun4m.c:547)
> ==21509==    by 0x40D50E: main (vl.c:8609)
> ==21509==
> ==21509== Invalid write of size 4
> ==21509==    at 0x42E05D: ecc_reset (eccmemctl.c:291)
> ==21509==    by 0x42E149: ecc_init (eccmemctl.c:323)
> ==21509==    by 0x425E7F: sun4m_hw_init (sun4m.c:547)
> ==21509==    by 0x40D50E: main (vl.c:8609)
> ==21509==  Address 0x7af3c30 is not stack'd, malloc'd or (recently) free'd
> ==21509==
> ==21509== Invalid write of size 4
> ==21509==    at 0x42E064: ecc_reset (eccmemctl.c:292)
> ==21509==    by 0x42E149: ecc_init (eccmemctl.c:323)
> ==21509==    by 0x425E7F: sun4m_hw_init (sun4m.c:547)
> ==21509==    by 0x40D50E: main (vl.c:8609)
> ==21509==  Address 0x7af3c40 is 8 bytes before a block of size 296 alloc'd
> ==21509==    at 0x4C234BB: malloc (vg_replace_malloc.c:207)
> ==21509==    by 0x40973E: register_savevm (vl.c:5958)
> ==21509==    by 0x42E134: ecc_init (eccmemctl.c:321)
> ==21509==    by 0x425E7F: sun4m_hw_init (sun4m.c:547)
> ==21509==    by 0x40D50E: main (vl.c:8609)
>
>
>
>   
Here is a little cleaner version:


[-- Attachment #2: eccmemctl.diff.txt --]
[-- Type: text/plain, Size: 949 bytes --]

--- hw/eccmemctl.c	(revision 4744)
+++ hw/eccmemctl.c	(working copy)
@@ -283,19 +283,16 @@
     ECCState *s = opaque;
     int i;
 
-    s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL);
-    s->regs[ECC_MER] |= ECC_MER_MRR;
-    s->regs[ECC_MDR] = 0x20;
-    s->regs[ECC_MFSR] = 0;
-    s->regs[ECC_VCR] = 0;
-    s->regs[ECC_MFAR0] = 0x07c00000;
-    s->regs[ECC_MFAR1] = 0;
-    s->regs[ECC_DR] = 0;
-    s->regs[ECC_ECR0] = 0;
-    s->regs[ECC_ECR1] = 0;
-
-    for (i = 1; i < ECC_NREGS; i++)
-        s->regs[i] = 0;
+    s->regs[ECC_MER/4] &= (ECC_MER_VER | ECC_MER_IMPL);
+    s->regs[ECC_MER/4] |= ECC_MER_MRR;
+    s->regs[ECC_MDR/4] = 0x20;
+    s->regs[ECC_MFSR/4] = 0;
+    s->regs[ECC_VCR/4] = 0;
+    s->regs[ECC_MFAR0/4] = 0x07c00000;
+    s->regs[ECC_MFAR1/4] = 0;
+    s->regs[ECC_DR/4] = 0;
+    s->regs[ECC_ECR0/4] = 0;
+    s->regs[ECC_ECR1/4] = 0;
 }
 
 void * ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version)

  parent reply	other threads:[~2008-06-17 23:39 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-17 20:35 [Qemu-devel] buffer overruns in qemu-system-sparc (hw/eccmemctl.c: ecc_reset()) Julian Seward
2008-06-17 23:37 ` Paul Brook
2008-06-17 23:38 ` Robert Reif [this message]
2008-06-17 23:58   ` Julian Seward
2008-06-19 14:11   ` Blue Swirl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48584B13.7000503@earthlink.net \
    --to=reif@earthlink.net \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).