Package: kvm
Version: 66+dfsg-1.1
Severity: critical
Tags: patch security
Justification: root security hole
User: [EMAIL PROTECTED]
Usertags: origin-ubuntu hardy ubuntu-patch

Attached is a patch to address several open CVEs in the embedded qemu
software in kvm. These issues were addressed in [1] and [2] in qemu, but
not kvm.

This patch has been extensively tested in Ubuntu's kvm62, which has the
same embedded version of qemu (0.9.1) as kvm66 in sid. The Ubuntu patch is
the same as 90_security.patch from qemu 0.9.1-1 (excepting some fuzz). The
attached patch for sid's kvm is the same as the patch for Ubuntu, except it
had to be changed slightly because CVE-2008-0928.patch is applied first in
sid.

Please note that this does not include the fix for CVE-2008-2004, which was
recently included in qemu (0.9.1-5).

A suggested changelog entry might be:

  * debian/patches/CVE-2007-1320+1321+1322+1366+2893.patch based on
    90_security.patch from qemu 0.9.1-1. Please note that CVE-2007-2893 is
    also known as CVE-2007-1323, and CVE-2007-5729 and CVE-2007-5730 are known
    as CVE-2007-1321 in Debian. This patch addresses the following:
    - Cirrus LGD-54XX "bitblt" heap overflow.
    - NE2000 "mtu" heap overflow.
    - QEMU "net socket" heap overflow.
    - QEMU NE2000 "receive" integer signedness error.
    - Infinite loop in the emulated SB16 device.
    - Unprivileged "aam" instruction does not correctly handle the
      undocumented divisor operand.
    - Unprivileged "icebp" instruction will halt emulation.


[1] http://www.debian.org/security/2007/dsa-1284
[2] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=424070

Jamie Strandboge
diff -u kvm-66+dfsg/debian/changelog kvm-66+dfsg/debian/changelog
diff -u kvm-66+dfsg/debian/patches/series kvm-66+dfsg/debian/patches/series
--- kvm-66+dfsg/debian/patches/series
+++ kvm-66+dfsg/debian/patches/series
@@ -10,0 +11 @@
+CVE-2007-1320+1321+1322+1366+2893.patch
only in patch2:
unchanged:
--- kvm-66+dfsg.orig/debian/patches/CVE-2007-1320+1321+1322+1366+2893.patch
+++ kvm-66+dfsg/debian/patches/CVE-2007-1320+1321+1322+1366+2893.patch
@@ -0,0 +1,323 @@
+diff -Nur kvm-66+dfsg/qemu/block.c kvm-66+dfsg.new/qemu/block.c
+--- kvm-66+dfsg/qemu/block.c	2008-05-07 09:59:51.000000000 -0400
++++ kvm-66+dfsg.new/qemu/block.c	2008-05-07 10:03:24.000000000 -0400
+@@ -612,6 +612,8 @@
+         return -ENOMEDIUM;
+     if (bs->read_only)
+         return -EACCES;
++    if (sector_num < 0)
++        return -EINVAL;
+     if (bdrv_wr_badreq_sectors(bs, sector_num, nb_sectors))
+         return -EDOM;
+     if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+@@ -619,8 +621,14 @@
+     }
+     if (drv->bdrv_pwrite) {
+         int ret, len;
++        int64_t ns;
++
+         len = nb_sectors * 512;
+-        ret = drv->bdrv_pwrite(bs, sector_num * 512, buf, len);
++        ns = sector_num * 512;
++        if (ns < 0)
++            return -EINVAL;
++
++        ret = drv->bdrv_pwrite(bs, ns, buf, len);
+         if (ret < 0)
+             return ret;
+         else if (ret != len)
+diff -Nur kvm-66+dfsg/qemu/hw/cirrus_vga.c kvm-66+dfsg.new/qemu/hw/cirrus_vga.c
+--- kvm-66+dfsg/qemu/hw/cirrus_vga.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/hw/cirrus_vga.c	2008-05-07 10:00:01.000000000 -0400
+@@ -224,6 +224,20 @@
+ #define CIRRUS_HOOK_NOT_HANDLED 0
+ #define CIRRUS_HOOK_HANDLED 1
+ 
++#define BLTUNSAFE(s) \
++    ( \
++        ( /* check dst is within bounds */ \
++            (s)->cirrus_blt_height * (s)->cirrus_blt_dstpitch \
++                + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
++                    (s)->vram_size \
++        ) || \
++        ( /* check src is within bounds */ \
++            (s)->cirrus_blt_height * (s)->cirrus_blt_srcpitch \
++                + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
++                    (s)->vram_size \
++        ) \
++    )
++
+ struct CirrusVGAState;
+ typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
+                                      uint8_t * dst, const uint8_t * src,
+@@ -645,7 +659,7 @@
+ 
+     for (y = 0; y < lines; y++) {
+ 	off_cur = off_begin;
+-	off_cur_end = off_cur + bytesperline;
++	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
+ 	off_cur &= TARGET_PAGE_MASK;
+ 	while (off_cur < off_cur_end) {
+ 	    cpu_physical_memory_set_dirty(s->vram_offset + off_cur);
+@@ -660,7 +674,11 @@
+ {
+     uint8_t *dst;
+ 
+-    dst = s->vram_ptr + s->cirrus_blt_dstaddr;
++    dst = s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
++
++    if (BLTUNSAFE(s))
++        return 0;
++
+     (*s->cirrus_rop) (s, dst, src,
+                       s->cirrus_blt_dstpitch, 0,
+                       s->cirrus_blt_width, s->cirrus_blt_height);
+@@ -676,8 +694,10 @@
+ {
+     cirrus_fill_t rop_func;
+ 
++    if (BLTUNSAFE(s))
++        return 0;
+     rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+-    rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr,
++    rop_func(s, s->vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask), 
+              s->cirrus_blt_dstpitch,
+              s->cirrus_blt_width, s->cirrus_blt_height);
+     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+@@ -696,8 +716,8 @@
+ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
+ {
+     return cirrus_bitblt_common_patterncopy(s,
+-					    s->vram_ptr +
+-                                            (s->cirrus_blt_srcaddr & ~7));
++					    s->vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
++                                            s->cirrus_addr_mask));
+ }
+ 
+ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
+@@ -747,8 +767,10 @@
+     if (notify)
+ 	vga_hw_update();
+ 
+-    (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
+-		      s->vram_ptr + s->cirrus_blt_srcaddr,
++    (*s->cirrus_rop) (s, s->vram_ptr +
++		          (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
++		          s->vram_ptr +
++		          (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
+ 		      s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
+ 		      s->cirrus_blt_width, s->cirrus_blt_height);
+ 
+@@ -774,8 +796,14 @@
+ 		       s->cirrus_blt_srcaddr - s->start_addr,
+ 		       s->cirrus_blt_width, s->cirrus_blt_height);
+     } else {
+-	(*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
+-			  s->vram_ptr + s->cirrus_blt_srcaddr,
++
++    if (BLTUNSAFE(s))
++        return 0;
++
++	(*s->cirrus_rop) (s, s->vram_ptr +
++                (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
++			  s->vram_ptr +
++                (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
+ 			  s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
+ 			  s->cirrus_blt_width, s->cirrus_blt_height);
+ 
+@@ -807,8 +835,9 @@
+         } else {
+             /* at least one scan line */
+             do {
+-                (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr,
+-                                 s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
++                (*s->cirrus_rop)(s, s->vram_ptr +
++                    (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
++                        s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
+                 cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
+                                          s->cirrus_blt_width, 1);
+                 s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
+@@ -1929,7 +1958,7 @@
+     unsigned val = mem_value;
+     uint8_t *dst;
+ 
+-    dst = s->vram_ptr + offset;
++    dst = s->vram_ptr + (offset &= s->cirrus_addr_mask);
+     for (x = 0; x < 8; x++) {
+ 	if (val & 0x80) {
+ 	    *dst = s->cirrus_shadow_gr1;
+@@ -1952,7 +1981,7 @@
+     unsigned val = mem_value;
+     uint8_t *dst;
+ 
+-    dst = s->vram_ptr + offset;
++    dst = s->vram_ptr + (offset &= s->cirrus_addr_mask);
+     for (x = 0; x < 8; x++) {
+ 	if (val & 0x80) {
+ 	    *dst = s->cirrus_shadow_gr1;
+diff -Nur kvm-66+dfsg/qemu/hw/cirrus_vga_rop.h kvm-66+dfsg.new/qemu/hw/cirrus_vga_rop.h
+--- kvm-66+dfsg/qemu/hw/cirrus_vga_rop.h	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/hw/cirrus_vga_rop.h	2008-05-07 10:00:01.000000000 -0400
+@@ -31,6 +31,12 @@
+     int x,y;
+     dstpitch -= bltwidth;
+     srcpitch -= bltwidth;
++
++    if (dstpitch < 0 || srcpitch < 0) {
++        /* is 0 valid? srcpitch == 0 could be useful */
++        return;
++    }
++
+     for (y = 0; y < bltheight; y++) {
+         for (x = 0; x < bltwidth; x++) {
+             ROP_OP(*dst, *src);
+diff -Nur kvm-66+dfsg/qemu/hw/dma.c kvm-66+dfsg.new/qemu/hw/dma.c
+--- kvm-66+dfsg/qemu/hw/dma.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/hw/dma.c	2008-05-07 10:00:01.000000000 -0400
+@@ -341,9 +341,11 @@
+ #endif
+ 
+     r = dma_controllers[ncont].regs + ichan;
+-    n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
+-                             r->now[COUNT], (r->base[COUNT] + 1) << ncont);
+-    r->now[COUNT] = n;
++    if (r->transfer_handler) {
++        n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
++                                 r->now[COUNT], (r->base[COUNT] + 1) << ncont);
++        r->now[COUNT] = n;
++    }
+     ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
+ }
+ 
+diff -Nur kvm-66+dfsg/qemu/hw/fdc.c kvm-66+dfsg.new/qemu/hw/fdc.c
+--- kvm-66+dfsg/qemu/hw/fdc.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/hw/fdc.c	2008-05-07 10:00:01.000000000 -0400
+@@ -1344,7 +1344,13 @@
+             len = fdctrl->data_len - fdctrl->data_pos;
+             if (len > FD_SECTOR_LEN)
+                 len = FD_SECTOR_LEN;
+-            bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1);
++            if (cur_drv->bs) {
++                bdrv_read(cur_drv->bs, fd_sector(cur_drv), 
++                          fdctrl->fifo, 1);
++            } else {
++                FLOPPY_ERROR("can't read data from drive\n");
++                return 0;
++            }
+         }
+     }
+     retval = fdctrl->fifo[pos];
+diff -Nur kvm-66+dfsg/qemu/hw/pc.c kvm-66+dfsg.new/qemu/hw/pc.c
+--- kvm-66+dfsg/qemu/hw/pc.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/hw/pc.c	2008-05-07 10:00:01.000000000 -0400
+@@ -341,7 +341,8 @@
+     case 0x400:
+     case 0x401:
+         fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
+-        exit(1);
++        /* according to documentation, these can be safely ignored */
++        break;
+     case 0x402:
+     case 0x403:
+ #ifdef DEBUG_BIOS
+@@ -364,8 +365,9 @@
+         /* LGPL'ed VGA BIOS messages */
+     case 0x501:
+     case 0x502:
++        /* according to documentation, these can be safely ignored */
+         fprintf(stderr, "VGA BIOS panic, line %d\n", val);
+-        exit(1);
++        break;
+     case 0x500:
+     case 0x503:
+ #ifdef DEBUG_BIOS
+diff -Nur kvm-66+dfsg/qemu/hw/sb16.c kvm-66+dfsg.new/qemu/hw/sb16.c
+--- kvm-66+dfsg/qemu/hw/sb16.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/hw/sb16.c	2008-05-07 10:00:01.000000000 -0400
+@@ -1246,8 +1246,10 @@
+             s->block_size);
+ #endif
+ 
+-    while (s->left_till_irq <= 0) {
+-        s->left_till_irq = s->block_size + s->left_till_irq;
++    if (s->block_size) {
++        while (s->left_till_irq <= 0) {
++            s->left_till_irq = s->block_size + s->left_till_irq;
++        }
+     }
+ 
+     return dma_pos;
+diff -Nur kvm-66+dfsg/qemu/slirp/slirp.c kvm-66+dfsg.new/qemu/slirp/slirp.c
+--- kvm-66+dfsg/qemu/slirp/slirp.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/slirp/slirp.c	2008-05-07 10:00:01.000000000 -0400
+@@ -620,6 +620,10 @@
+         if (!m)
+             return;
+         /* Note: we add to align the IP header */
++        /* taviso: large values in ne2k TCNT register may exceed msize on transmit */
++        if (M_FREEROOM(m) < pkt_len + 2) {
++            m_inc(m, pkt_len + 2);
++        }
+         m->m_len = pkt_len + 2;
+         memcpy(m->m_data + 2, pkt, pkt_len);
+ 
+diff -Nur kvm-66+dfsg/qemu/target-i386/translate.c kvm-66+dfsg.new/qemu/target-i386/translate.c
+--- kvm-66+dfsg/qemu/target-i386/translate.c	2008-04-15 09:35:58.000000000 -0400
++++ kvm-66+dfsg.new/qemu/target-i386/translate.c	2008-05-07 10:00:01.000000000 -0400
+@@ -5452,6 +5452,7 @@
+         gen_jmp_im(pc_start - s->cs_base);
+         gen_op_into(s->pc - pc_start);
+         break;
++#ifdef WANT_ICEBP
+     case 0xf1: /* icebp (undocumented, exits to external debugger) */
+         if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP))
+             break;
+@@ -5463,6 +5464,7 @@
+         cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM);
+ #endif
+         break;
++#endif /* icebp */
+     case 0xfa: /* cli */
+         if (!s->vm86) {
+             if (s->cpl <= s->iopl) {
+diff -Nur kvm-66+dfsg/qemu/vl.c kvm-66+dfsg.new/qemu/vl.c
+--- kvm-66+dfsg/qemu/vl.c	2008-05-07 09:59:51.000000000 -0400
++++ kvm-66+dfsg.new/qemu/vl.c	2008-05-07 10:00:01.000000000 -0400
+@@ -4294,8 +4294,8 @@
+     VLANClientState *vc;
+     int fd;
+     int state; /* 0 = getting length, 1 = getting data */
+-    int index;
+-    int packet_len;
++    unsigned int index;
++    unsigned int packet_len;
+     uint8_t buf[4096];
+     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
+ } NetSocketState;
+@@ -4326,7 +4326,8 @@
+ static void net_socket_send(void *opaque)
+ {
+     NetSocketState *s = opaque;
+-    int l, size, err;
++    int size, err;
++    unsigned l;
+     uint8_t buf1[4096];
+     const uint8_t *buf;
+ 
+@@ -4365,7 +4366,15 @@
+             l = s->packet_len - s->index;
+             if (l > size)
+                 l = size;
+-            memcpy(s->buf + s->index, buf, l);
++            if (s->index + l <= sizeof(s->buf)) {
++                memcpy(s->buf + s->index, buf, l);
++            } else {
++                fprintf(stderr, "serious error: oversized packet received,"
++                    "connection terminated.\n");
++                s->state = 0;
++                goto eoc;
++            }
++
+             s->index += l;
+             buf += l;
+             size -= l;

Reply via email to