Bugs item #1881532, was opened at 2008-01-28 18:16
Message generated for change (Tracker Item Submitted) made by Item Submitter
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=893831&aid=1881532&group_id=180599

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: None
Group: None
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: Scott Pakin (pakin)
Assigned to: Nobody/Anonymous (nobody)
Summary: Network access seg faults KVM on large-memory machine

Initial Comment:
The TCP-handling code in qemu/slirp is not 64-bit clean.  On a system
with tons of memory -- I'm running on a system with just under 48GB of
RAM -- KVM dies with a segmentation fault when I try to access the
network.

Specifically, I boot the Ubuntu live CD image, open a terminal, and
try to ssh to the host machine.  KVM segfaults before ssh returns.

For completeness, here are the parameters requested on the "Submitting
a bug report" page:

    CPU model:     Dual-Core AMD Opteron(tm) Processor 8212
    KVM version:   60
    Host kernel:   Linux version 2.6.18-8.1.14.el5 ([EMAIL PROTECTED]) (gcc 
version 4.1.1 20070105 (Red Hat 4.1.1-52)) #1 SMP Thu Sep 27 19:05:32 EDT 2007
    Guest arch:    x86_64
    Guest OS:      Ubuntu Linux 7.10
    Guest bitness: 64
    Guest kernel:  Linux version 2.6.22-14-generic ([EMAIL PROTECTED]) (gcc 
version 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)) #1 SMP Sun Oct 14 
21:45:15 GMT 2007
    Command line:  qemu-system-x86_64 -cdrom ubuntu-7.10-desktop-amd64.iso 
-boot d -localtime -m 1024
    With -no-kvm:  [still fails]

Fortunately, I managed to track down the problem.  First, note how the
seg_next field is declared in a TCP control block:

    qemu/slirp/tcp_var.h:
      43 #if SIZEOF_CHAR_P == 4
      44  typedef struct tcpiphdr *tcpiphdrp_32;
      45 #else
      46  typedef u_int32_t tcpiphdrp_32;
      47 #endif
      ...
      52 struct tcpcb {
      53         tcpiphdrp_32 seg_next;  /* sequencing queue */
      54         tcpiphdrp_32 seg_prev;

Because this is a 64-bit build, SIZEOF_CHAR_P is 8 so tcpiphdrp_32 --
and hence seg_next -- is defined as a u_int32_t, a 32-bit integer.

Second, note how tp->seg_next is defined:

    qemu/slirp/tcp_subr.c:
      189 tcp_newtcpcb(so)
      190         struct socket *so;
      191 {
      192         register struct tcpcb *tp;
      193
      194         tp = (struct tcpcb *)malloc(sizeof(*tp));
      195         if (tp == NULL)
      196                 return ((struct tcpcb *)0);
      197
      198         memset((char *) tp, 0, sizeof(struct tcpcb));
      199         tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp;

It's taking a 64-bit pointer, tp, and assigning it to a seg_next
field, which is a 32-bit integer.  Not surprisingly, a SIGSEGV is
generated when that 32-bit integer is cast back to a 64-bit pointer
and dereferenced:

    qemu/slirp/tcp_input.c:
      207         ti = (struct tcpiphdr *) tp->seg_next;
      208         if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt)
      209                 return (0);

I believe the following patch should fix the problem:

===================== BEGIN kvm_tcp_seg_next.patch =====================
--- qemu/slirp/tcp_var.h.ORIG   2008-01-28 17:27:09.000000000 -0700
+++ qemu/slirp/tcp_var.h        2008-01-28 17:27:20.000000000 -0700
@@ -40,11 +40,7 @@
 #include "tcpip.h"
 #include "tcp_timer.h"

-#if SIZEOF_CHAR_P == 4
- typedef struct tcpiphdr *tcpiphdrp_32;
-#else
- typedef u_int32_t tcpiphdrp_32;
-#endif
+typedef struct tcpiphdr *tcpiphdrp_32;

 /*
  * Tcp control block, one per tcp; fields:
====================== END kvm_tcp_seg_next.patch ======================

As far as I can tell, tcpiphdr_32 is used only to define seg_next and
seg_prev so it _should_ be safe to define it as an ordinary pointer
regardless of 32/64-bitness.

There are a bunch of other potential sources of similar problems in
qemu/slirp, but I haven't yet triggered these:

    slirp/ip_input.c:278: warning: cast from pointer to integer of different 
size
    slirp/ip_input.c:298: warning: cast from pointer to integer of different 
size
    slirp/ip_input.c:427: warning: cast from pointer to integer of different 
size
    slirp/ip_input.c:429: warning: cast from pointer to integer of different 
size
    slirp/ip_input.c:430: warning: cast from pointer to integer of different 
size
    slirp/misc.c:115: warning: cast from pointer to integer of different size
    slirp/misc.c:116: warning: cast from pointer to integer of different size
    slirp/misc.c:118: warning: cast from pointer to integer of different size
    slirp/tcp_input.c:173: warning: cast from pointer to integer of different 
size

Still, you might want to have a look at those, too, to make sure that
KVM will work on large-memory machines.



----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=893831&aid=1881532&group_id=180599

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to