From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1DY19g-0003hv-0u for qemu-devel@nongnu.org; Tue, 17 May 2005 08:26:36 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1DXxgV-0002Zd-SA for qemu-devel@nongnu.org; Tue, 17 May 2005 04:44:17 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DXx7w-0005ko-Mi for qemu-devel@nongnu.org; Tue, 17 May 2005 04:08:32 -0400 Received: from [192.76.135.70] (helo=kurt.tools.de) by monty-python.gnu.org with esmtp (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.34) id 1DXxC7-00034T-Ue for qemu-devel@nongnu.org; Tue, 17 May 2005 04:12:52 -0400 Received: from imap3.tools.intra (imap3.tools.intra [172.20.0.8]) by kurt.tools.de (8.13.3/8.13.3) with ESMTP id j4H84mfV016331 for ; Tue, 17 May 2005 10:04:49 +0200 (MEST) Received: from tiger2.tools.intra (tiger2.tools.intra [172.20.0.11]) by imap3.tools.intra (8.13.1+Sun/8.13.1) with SMTP id j4H84mg4018307 for ; Tue, 17 May 2005 10:04:48 +0200 (MEST) Message-Id: <200505170804.j4H84mg4018307@imap3.tools.intra> Date: Tue, 17 May 2005 10:04:48 +0200 (CEST) From: Juergen Keil MIME-Version: 1.0 Content-Type: TEXT/plain; charset=us-ascii Content-MD5: Wyh2/xZp/4Q7+1m20/4wKA== Subject: [Qemu-devel] [PATCH] Fix for a malloc heap corruption problem in the slirp network code Reply-To: Juergen Keil , qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Compiling inside a NetBSD 1.5 qemu guest OS (source files are located on an NFS filesystem mounted from the Solaris host OS) crashes qemu with a malloc heap corruption error, when the slirp user mode networking code is in use. Solaris' umem malloc library reports that a block freed by a call to realloc (from function m_inc()) is still being used, when it shouldn't: % mdb i386-softmmu/qemu core Loading modules: [ libumem.so.1 libc.so.1 ld.so.1 ] > ::umem_status Status: ready and active Concurrency: 2 Logs: transaction=64k (inactive) Message buffer: umem allocator: boundary tag corrupted bcp ^ bxstat = 2c694858, should be f4eef4ee buffer=1977f000 bufctl=19713340 cache: umem_alloc_8192 previous transaction on buffer 1977f000: thread=1 time=T-0.009171995 slab=8f9b2c0 cache: umem_alloc_8192 libumem.so.1'?? (0xd1f99c49) libumem.so.1'umem_cache_free+0x3f libumem.so.1'umem_free+0xd5 libumem.so.1'?? (0xd1f97c05) libumem.so.1'free+0x14 libumem.so.1'realloc+0x66 qemu'm_inc+0x26 qemu'm_cat+0x4b qemu'ip_reass+0x321 qemu'ip_input+0x261 qemu'slirp_input+0x6f qemu'?? (0x8065055) qemu'qemu_send_packet+0x13 qemu'?? (0x807d116) qemu'cpu_outb+0x1b umem: heap corruption detected stack trace: libumem.so.1'?? (0xd1f96099) libumem.so.1'?? (0xd1f98b1c) libumem.so.1'?? (0xd1f99ad2) libumem.so.1'umem_cache_alloc+0xe1 libumem.so.1'umem_alloc+0x3f libumem.so.1'malloc+0x23 qemu'm_inc+0x41 qemu'm_cat+0x4b qemu'ip_reass+0x321 qemu'ip_input+0x261 qemu'slirp_input+0x6f qemu'?? (0x8065055) qemu'qemu_send_packet+0x13 qemu'?? (0x807d116) qemu'cpu_outb+0x1b qemu'code_gen_buffer+0x1103bd qemu'main_loop+0x22 qemu'main+0x10ce qemu'_start+0x5d > Using the "electric fence" memory allocator, the location of the data corruption can be narrowed down to the destination address in the memcpy call in slirp/mbuf.c, function m_cat(): void m_cat(m, n) register struct mbuf *m, *n; { /* * If there's no room, realloc */ if (M_FREEROOM(m) < n->m_len) m_inc(m,m->m_size+MINCSIZE); memcpy(m->m_data+m->m_len, n->m_data, n->m_len); <<<< this memcpy corrupts the malloc heap .... } The problem is apparently in m_inc(), when an mbuf with an external data buffer is resized. After resizing the mbuf, the m_data member still points into the old buffer, before is was reallocated. For some reason, the code to re-adjust the m_data pointer is present in the M_EXT case in m_inc(), but is commented out. (With a bit of luck, realloc might be able to adjust the size of the memory block in place; but slirp shouldn't rely on this) Fix: Adjust mbuf->m_data after a realloc of the external data buffer % gdiff -u qemu-cvs/slirp/mbuf.c qemu-debug/slirp/mbuf.c --- qemu-cvs/slirp/mbuf.c 2004-04-22 02:10:47.000000000 +0200 +++ qemu-debug/slirp/mbuf.c 2005-05-16 11:24:14.557567000 +0200 @@ -146,18 +146,19 @@ struct mbuf *m; int size; { + int datasize; + /* some compiles throw up on gotos. This one we can fake. */ if(m->m_size>size) return; if (m->m_flags & M_EXT) { - /* datasize = m->m_data - m->m_ext; */ + datasize = m->m_data - m->m_ext; m->m_ext = (char *)realloc(m->m_ext,size); /* if (m->m_ext == NULL) * return (struct mbuf *)NULL; */ - /* m->m_data = m->m_ext + datasize; */ + m->m_data = m->m_ext + datasize; } else { - int datasize; char *dat; datasize = m->m_data - m->m_dat; dat = (char *)malloc(size);