diff -Nru qemu-2.0.0+dfsg/debian/changelog qemu-2.0.0+dfsg/debian/changelog --- qemu-2.0.0+dfsg/debian/changelog 2015-08-05 14:28:15.000000000 +0000 +++ qemu-2.0.0+dfsg/debian/changelog 2015-08-25 14:05:49.000000000 +0000 @@ -1,3 +1,20 @@ +qemu (2.0.0+dfsg-2ubuntu1.17) trusty-security; urgency=medium + + * SECURITY UPDATE: denial of service via PRDT with zero complete sectors + - debian/patches/CVE-2014-9718.patch: refactor return codes in + hw/ide/ahci.c, hw/ide/core.c, hw/ide/internal.h, hw/ide/macio.c, + hw/ide/pci.c. + - CVE-2014-9718 + * SECURITY UPDATE: process heap memory disclosure + - debian/patches/CVE-2015-5165.patch: check sizes in hw/net/rtl8139.c. + - CVE-2015-5165 + * SECURITY UPDATE: denial of service via virtio-serial + - debian/patches/CVE-2015-5745.patch: don't assume a specific layout + for control messages in hw/char/virtio-serial-bus.c. + - CVE-2015-5745 + + -- Marc Deslauriers Tue, 25 Aug 2015 10:03:25 -0400 + qemu (2.0.0+dfsg-2ubuntu1.16) trusty; urgency=medium * Support qemu-kvm on x32, arm64, ppc64 and pp64el architectures diff -Nru qemu-2.0.0+dfsg/debian/patches/CVE-2014-9718.patch qemu-2.0.0+dfsg/debian/patches/CVE-2014-9718.patch --- qemu-2.0.0+dfsg/debian/patches/CVE-2014-9718.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.0.0+dfsg/debian/patches/CVE-2014-9718.patch 2015-08-25 15:49:14.000000000 +0000 @@ -0,0 +1,337 @@ +Backport of: + +From 3251bdcf1c67427d964517053c3d185b46e618e8 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Fri, 31 Oct 2014 16:03:39 -0400 +Subject: [PATCH] ide: Correct handling of malformed/short PRDTs + +This impacts both BMDMA and AHCI HBA interfaces for IDE. +Currently, we confuse the difference between a PRDT having +"0 bytes" and a PRDT having "0 complete sectors." + +When we receive an incomplete sector, inconsistent error checking +leads to an infinite loop wherein the call succeeds, but it +didn't give us enough bytes -- leading us to re-call the +DMA chain over and over again. This leads to, in the BMDMA case, +leaked memory for short PRDTs, and infinite loops and resource +usage in the AHCI case. + +The .prepare_buf() callback is reworked to return the number of +bytes that it successfully prepared. 0 is a valid, non-error +answer that means the table was empty and described no bytes. +-1 indicates an error. + +Our current implementation uses the io_buffer in IDEState to +ultimately describe the size of a prepared scatter-gather list. +Even though the AHCI PRDT/SGList can be as large as 256GiB, the +AHCI command header limits transactions to just 4GiB. ATA8-ACS3, +however, defines the largest transaction to be an LBA48 command +that transfers 65,536 sectors. With a 512 byte sector size, this +is just 32MiB. + +Since our current state structures use the int type to describe +the size of the buffer, and this state is migrated as int32, we +are limited to describing 2GiB buffer sizes unless we change the +migration protocol. + +For this reason, this patch begins to unify the assertions in the +IDE pathways that the scatter-gather list provided by either the +AHCI PRDT or the PCI BMDMA PRDs can only describe, at a maximum, +2GiB. This should be resilient enough unless we need a sector +size that exceeds 32KiB. + +Further, the likelihood of any guest operating system actually +attempting to transfer this much data in a single operation is +very slim. + +To this end, the IDEState variables have been updated to more +explicitly clarify our maximum supported size. Callers to the +prepare_buf callback have been reworked to understand the new +return code, and all versions of the prepare_buf callback have +been adjusted accordingly. + +Lastly, the ahci_populate_sglist helper, relied upon by the +AHCI implementation of .prepare_buf() as well as the PCI +implementation of the callback have had overflow assertions +added to help make clear the reasonings behind the various +type changes. + +[Added %d -> %"PRId64" fix John sent because off_pos changed from int to +int64_t. +--Stefan] + +Signed-off-by: John Snow +Reviewed-by: Paolo Bonzini +Message-id: 1414785819-26209-4-git-send-email-jsnow@redhat.com +Signed-off-by: Stefan Hajnoczi +--- + hw/ide/ahci.c | 33 ++++++++++++++++++++++++++------- + hw/ide/core.c | 10 ++++++++-- + hw/ide/internal.h | 13 +++++++------ + hw/ide/macio.c | 7 ++++++- + hw/ide/pci.c | 27 +++++++++++++++++++++------ + 5 files changed, 68 insertions(+), 22 deletions(-) + +Index: qemu-2.0.0+dfsg/hw/ide/ahci.c +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/ide/ahci.c 2015-08-25 09:56:30.496062375 -0400 ++++ qemu-2.0.0+dfsg/hw/ide/ahci.c 2015-08-25 09:58:28.321286292 -0400 +@@ -639,7 +639,8 @@ + } + } + +-static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset) ++static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, ++ int32_t offset) + { + AHCICmdHdr *cmd = ad->cur_cmd; + uint32_t opts = le32_to_cpu(cmd->opts); +@@ -650,13 +651,21 @@ + uint8_t *prdt; + int i; + int r = 0; +- int sum = 0; ++ uint64_t sum = 0; + int off_idx = -1; +- int off_pos = -1; ++ int64_t off_pos = -1; + int tbl_entry_size; + IDEBus *bus = &ad->port; + BusState *qbus = BUS(bus); + ++ /* ++ * Note: AHCI PRDT can describe up to 256GiB. SATA/ATA only support ++ * transactions of up to 32MiB as of ATA8-ACS3 rev 1b, assuming a ++ * 512 byte sector size. We limit the PRDT in this implementation to ++ * a reasonably large 2GiB, which can accommodate the maximum transfer ++ * request for sector sizes up to 32K. ++ */ ++ + if (!sglist_alloc_hint) { + DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts); + return -1; +@@ -691,7 +700,7 @@ + } + if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) { + DPRINTF(ad->port_no, "%s: Incorrect offset! " +- "off_idx: %d, off_pos: %d\n", ++ "off_idx: %d, off_pos: %"PRId64"\n", + __func__, off_idx, off_pos); + r = -1; + goto out; +@@ -706,6 +715,13 @@ + /* flags_size is zero-based */ + qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr), + le32_to_cpu(tbl[i].flags_size) + 1); ++ if (sglist->size > INT32_MAX) { ++ error_report("AHCI Physical Region Descriptor Table describes " ++ "more than 2 GiB.\n"); ++ qemu_sglist_destroy(sglist); ++ r = -1; ++ goto out; ++ } + } + } + +@@ -1050,16 +1066,19 @@ + dma_cb(s, 0); + } + +-static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) ++static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int is_write) + { + AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); + IDEState *s = &ad->port.ifs[0]; + +- ahci_populate_sglist(ad, &s->sg, 0); ++ if (ahci_populate_sglist(ad, &s->sg, 0) == -1) { ++ DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n"); ++ return -1; ++ } + s->io_buffer_size = s->sg.size; + + DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size); +- return s->io_buffer_size != 0; ++ return s->io_buffer_size; + } + + static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) +Index: qemu-2.0.0+dfsg/hw/ide/core.c +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/ide/core.c 2015-08-25 09:56:30.496062375 -0400 ++++ qemu-2.0.0+dfsg/hw/ide/core.c 2015-08-25 09:58:57.121585236 -0400 +@@ -659,10 +659,11 @@ + n = s->nsector; + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; +- if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) { ++ if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) < 512) { + /* The PRDs were too short. Reset the Active bit, but don't raise an + * interrupt. */ + s->status = READY_STAT | SEEK_STAT; ++ dma_buf_commit(s); + goto eot; + } + +@@ -2207,6 +2208,11 @@ + return 0; + } + ++static int32_t ide_nop_int32(IDEDMA *dma, int x) ++{ ++ return 0; ++} ++ + static void ide_nop_restart(void *opaque, int x, RunState y) + { + } +@@ -2214,7 +2220,7 @@ + static const IDEDMAOps ide_dma_nop_ops = { + .start_dma = ide_nop_start, + .start_transfer = ide_nop, +- .prepare_buf = ide_nop_int, ++ .prepare_buf = ide_nop_int32, + .rw_buf = ide_nop_int, + .set_unit = ide_nop_int, + .add_status = ide_nop_int, +Index: qemu-2.0.0+dfsg/hw/ide/internal.h +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/ide/internal.h 2015-08-25 09:56:30.496062375 -0400 ++++ qemu-2.0.0+dfsg/hw/ide/internal.h 2015-08-25 09:59:32.225949500 -0400 +@@ -322,6 +322,7 @@ + typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *); + typedef int DMAFunc(IDEDMA *); + typedef int DMAIntFunc(IDEDMA *, int); ++typedef int32_t DMAInt32Func(IDEDMA *, int); + typedef void DMARestartFunc(void *, int, RunState); + + struct unreported_events { +@@ -383,7 +384,7 @@ + uint8_t cdrom_changed; + int packet_transfer_size; + int elementary_transfer_size; +- int io_buffer_index; ++ int32_t io_buffer_index; + int lba; + int cd_sector_size; + int atapi_dma; /* true if dma is requested for the packet cmd */ +@@ -392,8 +393,8 @@ + struct iovec iov; + QEMUIOVector qiov; + /* ATA DMA state */ +- int io_buffer_offset; +- int io_buffer_size; ++ int32_t io_buffer_offset; ++ int32_t io_buffer_size; + QEMUSGList sg; + /* PIO transfer handling */ + int req_nb_sectors; /* number of sectors per interrupt */ +@@ -403,8 +404,8 @@ + uint8_t *io_buffer; + /* PIO save/restore */ + int32_t io_buffer_total_len; +- int cur_io_buffer_offset; +- int cur_io_buffer_len; ++ int32_t cur_io_buffer_offset; ++ int32_t cur_io_buffer_len; + uint8_t end_transfer_fn_idx; + QEMUTimer *sector_write_timer; /* only used for win2k install hack */ + uint32_t irq_count; /* counts IRQs when using win2k install hack */ +@@ -428,7 +429,7 @@ + struct IDEDMAOps { + DMAStartFunc *start_dma; + DMAFunc *start_transfer; +- DMAIntFunc *prepare_buf; ++ DMAInt32Func *prepare_buf; + DMAIntFunc *rw_buf; + DMAIntFunc *set_unit; + DMAIntFunc *add_status; +Index: qemu-2.0.0+dfsg/hw/ide/macio.c +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/ide/macio.c 2015-08-25 09:56:30.496062375 -0400 ++++ qemu-2.0.0+dfsg/hw/ide/macio.c 2015-08-25 09:59:50.150135444 -0400 +@@ -505,6 +505,11 @@ + return 0; + } + ++static int32_t ide_nop_int32(IDEDMA *dma, int x) ++{ ++ return 0; ++} ++ + static void ide_nop_restart(void *opaque, int x, RunState y) + { + } +@@ -522,7 +527,7 @@ + static const IDEDMAOps dbdma_ops = { + .start_dma = ide_dbdma_start, + .start_transfer = ide_nop, +- .prepare_buf = ide_nop_int, ++ .prepare_buf = ide_nop_int32, + .rw_buf = ide_nop_int, + .set_unit = ide_nop_int, + .add_status = ide_nop_int, +Index: qemu-2.0.0+dfsg/hw/ide/pci.c +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/ide/pci.c 2015-08-25 09:56:30.496062375 -0400 ++++ qemu-2.0.0+dfsg/hw/ide/pci.c 2015-08-25 09:56:30.492062334 -0400 +@@ -28,7 +28,7 @@ + #include + #include "block/block.h" + #include "sysemu/dma.h" +- ++#include "qemu/error-report.h" + #include + + #define BMDMA_PAGE_SIZE 4096 +@@ -51,8 +51,11 @@ + } + } + +-/* return 0 if buffer completed */ +-static int bmdma_prepare_buf(IDEDMA *dma, int is_write) ++/** ++ * Return the number of bytes successfully prepared. ++ * -1 on error. ++ */ ++static int32_t bmdma_prepare_buf(IDEDMA *dma, int is_write) + { + BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); + IDEState *s = bmdma_active_if(bm); +@@ -70,8 +73,9 @@ + if (bm->cur_prd_len == 0) { + /* end of table (with a fail safe of one page) */ + if (bm->cur_prd_last || +- (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) +- return s->io_buffer_size != 0; ++ (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) { ++ return s->io_buffer_size; ++ } + pci_dma_read(pci_dev, bm->cur_addr, &prd, 8); + bm->cur_addr += 8; + prd.addr = le32_to_cpu(prd.addr); +@@ -86,12 +90,23 @@ + l = bm->cur_prd_len; + if (l > 0) { + qemu_sglist_add(&s->sg, bm->cur_prd_addr, l); ++ ++ /* Note: We limit the max transfer to be 2GiB. ++ * This should accommodate the largest ATA transaction ++ * for LBA48 (65,536 sectors) and 32K sector sizes. */ ++ if (s->sg.size > INT32_MAX) { ++ error_report("IDE: sglist describes more than 2GiB.\n"); ++ break; ++ } + bm->cur_prd_addr += l; + bm->cur_prd_len -= l; + s->io_buffer_size += l; + } + } +- return 1; ++ ++ qemu_sglist_destroy(&s->sg); ++ s->io_buffer_size = 0; ++ return -1; + } + + /* return 0 if buffer completed */ diff -Nru qemu-2.0.0+dfsg/debian/patches/CVE-2015-5165.patch qemu-2.0.0+dfsg/debian/patches/CVE-2015-5165.patch --- qemu-2.0.0+dfsg/debian/patches/CVE-2015-5165.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.0.0+dfsg/debian/patches/CVE-2015-5165.patch 2015-08-25 14:02:56.000000000 +0000 @@ -0,0 +1,429 @@ +Description: fix process heap memory disclosure +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=39b8e7dcaf04cbdb926b478f825b160d852752b5 +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=d6812d60e7932de3cd0f602c0ee63dd3d09f1847 +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=e1c120a9c54872f8a538ff9129d928de4e865cbd +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=03247d43c577dfea8181cd40177ad5ba77c8db76 +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=c6296ea88df040054ccd781f3945fe103f8c7c17 +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=4240be45632db7831129f124bcf53c1223825b0f +Origin: upstream, http://git.qemu.org/?p=qemu.git;a=commit;h=8357946b15f0a31f73dd691b7da95f29318ed310 +Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=794610 + +Index: qemu-2.0.0+dfsg/hw/net/rtl8139.c +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/net/rtl8139.c 2015-08-25 10:02:53.232032873 -0400 ++++ qemu-2.0.0+dfsg/hw/net/rtl8139.c 2015-08-25 10:02:53.176032292 -0400 +@@ -2161,6 +2161,11 @@ + { + DPRINTF("+++ C+ mode offloaded task checksum\n"); + ++ /* Large enough for Ethernet and IP headers? */ ++ if (saved_size < ETH_HLEN + sizeof(ip_header)) { ++ goto skip_offload; ++ } ++ + /* ip packet header */ + ip_header *ip = NULL; + int hlen = 0; +@@ -2171,223 +2176,230 @@ + size_t eth_payload_len = 0; + + int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); +- if (proto == ETH_P_IP) ++ if (proto != ETH_P_IP) + { +- DPRINTF("+++ C+ mode has IP packet\n"); ++ goto skip_offload; ++ } + +- /* not aligned */ +- eth_payload_data = saved_buffer + ETH_HLEN; +- eth_payload_len = saved_size - ETH_HLEN; +- +- ip = (ip_header*)eth_payload_data; +- +- if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { +- DPRINTF("+++ C+ mode packet has bad IP version %d " +- "expected %d\n", IP_HEADER_VERSION(ip), +- IP_HEADER_VERSION_4); +- ip = NULL; +- } else { +- hlen = IP_HEADER_LENGTH(ip); +- ip_protocol = ip->ip_p; +- ip_data_len = be16_to_cpu(ip->ip_len) - hlen; +- } ++ DPRINTF("+++ C+ mode has IP packet\n"); ++ ++ /* not aligned */ ++ eth_payload_data = saved_buffer + ETH_HLEN; ++ eth_payload_len = saved_size - ETH_HLEN; ++ ++ ip = (ip_header*)eth_payload_data; ++ ++ if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { ++ DPRINTF("+++ C+ mode packet has bad IP version %d " ++ "expected %d\n", IP_HEADER_VERSION(ip), ++ IP_HEADER_VERSION_4); ++ goto skip_offload; ++ } ++ ++ hlen = IP_HEADER_LENGTH(ip); ++ if (hlen < sizeof(ip_header) || hlen > eth_payload_len) { ++ goto skip_offload; + } + +- if (ip) ++ ip_protocol = ip->ip_p; ++ ip_data_len = be16_to_cpu(ip->ip_len) - hlen; ++ ++ if (txdw0 & CP_TX_IPCS) + { +- if (txdw0 & CP_TX_IPCS) +- { +- DPRINTF("+++ C+ mode need IP checksum\n"); ++ DPRINTF("+++ C+ mode need IP checksum\n"); + +- if (hleneth_payload_len) {/* min header length */ +- /* bad packet header len */ +- /* or packet too short */ +- } +- else +- { +- ip->ip_sum = 0; +- ip->ip_sum = ip_checksum(ip, hlen); +- DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", +- hlen, ip->ip_sum); +- } +- } ++ ip->ip_sum = 0; ++ ip->ip_sum = ip_checksum(ip, hlen); ++ DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n", ++ hlen, ip->ip_sum); ++ } + +- if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) +- { +- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; ++ if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) ++ { ++ /* Large enough for the TCP header? */ ++ if (ip_data_len < sizeof(tcp_header)) { ++ goto skip_offload; ++ } + +- DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " +- "frame data %d specified MSS=%d\n", ETH_MTU, +- ip_data_len, saved_size - ETH_HLEN, large_send_mss); ++ int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + +- int tcp_send_offset = 0; +- int send_count = 0; ++ DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " ++ "frame data %d specified MSS=%d\n", ETH_MTU, ++ ip_data_len, saved_size - ETH_HLEN, large_send_mss); + +- /* maximum IP header length is 60 bytes */ +- uint8_t saved_ip_header[60]; ++ int tcp_send_offset = 0; ++ int send_count = 0; + +- /* save IP header template; data area is used in tcp checksum calculation */ +- memcpy(saved_ip_header, eth_payload_data, hlen); ++ /* maximum IP header length is 60 bytes */ ++ uint8_t saved_ip_header[60]; + +- /* a placeholder for checksum calculation routine in tcp case */ +- uint8_t *data_to_checksum = eth_payload_data + hlen - 12; +- // size_t data_to_checksum_len = eth_payload_len - hlen + 12; ++ /* save IP header template; data area is used in tcp checksum calculation */ ++ memcpy(saved_ip_header, eth_payload_data, hlen); + +- /* pointer to TCP header */ +- tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); ++ /* a placeholder for checksum calculation routine in tcp case */ ++ uint8_t *data_to_checksum = eth_payload_data + hlen - 12; ++ // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + +- int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); ++ /* pointer to TCP header */ ++ tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + +- /* ETH_MTU = ip header len + tcp header len + payload */ +- int tcp_data_len = ip_data_len - tcp_hlen; +- int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; ++ int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + +- DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " +- "data len %d TCP chunk size %d\n", ip_data_len, +- tcp_hlen, tcp_data_len, tcp_chunk_size); ++ /* Invalid TCP data offset? */ ++ if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) { ++ goto skip_offload; ++ } + +- /* note the cycle below overwrites IP header data, +- but restores it from saved_ip_header before sending packet */ ++ /* ETH_MTU = ip header len + tcp header len + payload */ ++ int tcp_data_len = ip_data_len - tcp_hlen; ++ int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; + +- int is_last_frame = 0; ++ DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP " ++ "data len %d TCP chunk size %d\n", ip_data_len, ++ tcp_hlen, tcp_data_len, tcp_chunk_size); + +- for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) +- { +- uint16_t chunk_size = tcp_chunk_size; ++ /* note the cycle below overwrites IP header data, ++ but restores it from saved_ip_header before sending packet */ + +- /* check if this is the last frame */ +- if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) +- { +- is_last_frame = 1; +- chunk_size = tcp_data_len - tcp_send_offset; +- } +- +- DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", +- be32_to_cpu(p_tcp_hdr->th_seq)); +- +- /* add 4 TCP pseudoheader fields */ +- /* copy IP source and destination fields */ +- memcpy(data_to_checksum, saved_ip_header + 12, 8); +- +- DPRINTF("+++ C+ mode TSO calculating TCP checksum for " +- "packet with %d bytes data\n", tcp_hlen + +- chunk_size); +- +- if (tcp_send_offset) +- { +- memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); +- } +- +- /* keep PUSH and FIN flags only for the last frame */ +- if (!is_last_frame) +- { +- TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); +- } +- +- /* recalculate TCP checksum */ +- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; +- p_tcpip_hdr->zeros = 0; +- p_tcpip_hdr->ip_proto = IP_PROTO_TCP; +- p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); +- +- p_tcp_hdr->th_sum = 0; +- +- int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); +- DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", +- tcp_checksum); +- +- p_tcp_hdr->th_sum = tcp_checksum; +- +- /* restore IP header */ +- memcpy(eth_payload_data, saved_ip_header, hlen); +- +- /* set IP data length and recalculate IP checksum */ +- ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); +- +- /* increment IP id for subsequent frames */ +- ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); +- +- ip->ip_sum = 0; +- ip->ip_sum = ip_checksum(eth_payload_data, hlen); +- DPRINTF("+++ C+ mode TSO IP header len=%d " +- "checksum=%04x\n", hlen, ip->ip_sum); +- +- int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; +- DPRINTF("+++ C+ mode TSO transferring packet size " +- "%d\n", tso_send_size); +- rtl8139_transfer_frame(s, saved_buffer, tso_send_size, +- 0, (uint8_t *) dot1q_buffer); +- +- /* add transferred count to TCP sequence number */ +- p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); +- ++send_count; +- } ++ int is_last_frame = 0; + +- /* Stop sending this frame */ +- saved_size = 0; +- } +- else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) ++ for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) + { +- DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); ++ uint16_t chunk_size = tcp_chunk_size; + +- /* maximum IP header length is 60 bytes */ +- uint8_t saved_ip_header[60]; +- memcpy(saved_ip_header, eth_payload_data, hlen); ++ /* check if this is the last frame */ ++ if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) ++ { ++ is_last_frame = 1; ++ chunk_size = tcp_data_len - tcp_send_offset; ++ } + +- uint8_t *data_to_checksum = eth_payload_data + hlen - 12; +- // size_t data_to_checksum_len = eth_payload_len - hlen + 12; ++ DPRINTF("+++ C+ mode TSO TCP seqno %08x\n", ++ be32_to_cpu(p_tcp_hdr->th_seq)); + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + +- if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) ++ DPRINTF("+++ C+ mode TSO calculating TCP checksum for " ++ "packet with %d bytes data\n", tcp_hlen + ++ chunk_size); ++ ++ if (tcp_send_offset) ++ { ++ memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); ++ } ++ ++ /* keep PUSH and FIN flags only for the last frame */ ++ if (!is_last_frame) + { +- DPRINTF("+++ C+ mode calculating TCP checksum for " +- "packet with %d bytes data\n", ip_data_len); ++ TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); ++ } + +- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; +- p_tcpip_hdr->zeros = 0; +- p_tcpip_hdr->ip_proto = IP_PROTO_TCP; +- p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); ++ /* recalculate TCP checksum */ ++ ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; ++ p_tcpip_hdr->zeros = 0; ++ p_tcpip_hdr->ip_proto = IP_PROTO_TCP; ++ p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); ++ ++ p_tcp_hdr->th_sum = 0; ++ ++ int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); ++ DPRINTF("+++ C+ mode TSO TCP checksum %04x\n", ++ tcp_checksum); + +- tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); ++ p_tcp_hdr->th_sum = tcp_checksum; + +- p_tcp_hdr->th_sum = 0; ++ /* restore IP header */ ++ memcpy(eth_payload_data, saved_ip_header, hlen); + +- int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); +- DPRINTF("+++ C+ mode TCP checksum %04x\n", +- tcp_checksum); ++ /* set IP data length and recalculate IP checksum */ ++ ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); + +- p_tcp_hdr->th_sum = tcp_checksum; +- } +- else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) +- { +- DPRINTF("+++ C+ mode calculating UDP checksum for " +- "packet with %d bytes data\n", ip_data_len); ++ /* increment IP id for subsequent frames */ ++ ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + +- ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; +- p_udpip_hdr->zeros = 0; +- p_udpip_hdr->ip_proto = IP_PROTO_UDP; +- p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); ++ ip->ip_sum = 0; ++ ip->ip_sum = ip_checksum(eth_payload_data, hlen); ++ DPRINTF("+++ C+ mode TSO IP header len=%d " ++ "checksum=%04x\n", hlen, ip->ip_sum); ++ ++ int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; ++ DPRINTF("+++ C+ mode TSO transferring packet size " ++ "%d\n", tso_send_size); ++ rtl8139_transfer_frame(s, saved_buffer, tso_send_size, ++ 0, (uint8_t *) dot1q_buffer); ++ ++ /* add transferred count to TCP sequence number */ ++ p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); ++ ++send_count; ++ } + +- udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); ++ /* Stop sending this frame */ ++ saved_size = 0; ++ } ++ else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) ++ { ++ DPRINTF("+++ C+ mode need TCP or UDP checksum\n"); + +- p_udp_hdr->uh_sum = 0; ++ /* maximum IP header length is 60 bytes */ ++ uint8_t saved_ip_header[60]; ++ memcpy(saved_ip_header, eth_payload_data, hlen); + +- int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); +- DPRINTF("+++ C+ mode UDP checksum %04x\n", +- udp_checksum); ++ uint8_t *data_to_checksum = eth_payload_data + hlen - 12; ++ // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + +- p_udp_hdr->uh_sum = udp_checksum; +- } ++ /* add 4 TCP pseudoheader fields */ ++ /* copy IP source and destination fields */ ++ memcpy(data_to_checksum, saved_ip_header + 12, 8); + +- /* restore IP header */ +- memcpy(eth_payload_data, saved_ip_header, hlen); ++ if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) ++ { ++ DPRINTF("+++ C+ mode calculating TCP checksum for " ++ "packet with %d bytes data\n", ip_data_len); ++ ++ ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; ++ p_tcpip_hdr->zeros = 0; ++ p_tcpip_hdr->ip_proto = IP_PROTO_TCP; ++ p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); ++ ++ tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); ++ ++ p_tcp_hdr->th_sum = 0; ++ ++ int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); ++ DPRINTF("+++ C+ mode TCP checksum %04x\n", ++ tcp_checksum); ++ ++ p_tcp_hdr->th_sum = tcp_checksum; + } ++ else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) ++ { ++ DPRINTF("+++ C+ mode calculating UDP checksum for " ++ "packet with %d bytes data\n", ip_data_len); ++ ++ ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; ++ p_udpip_hdr->zeros = 0; ++ p_udpip_hdr->ip_proto = IP_PROTO_UDP; ++ p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); ++ ++ udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); ++ ++ p_udp_hdr->uh_sum = 0; ++ ++ int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); ++ DPRINTF("+++ C+ mode UDP checksum %04x\n", ++ udp_checksum); ++ ++ p_udp_hdr->uh_sum = udp_checksum; ++ } ++ ++ /* restore IP header */ ++ memcpy(eth_payload_data, saved_ip_header, hlen); + } + } + ++skip_offload: + /* update tally counter */ + ++s->tally_counters.TxOk; + diff -Nru qemu-2.0.0+dfsg/debian/patches/CVE-2015-5745.patch qemu-2.0.0+dfsg/debian/patches/CVE-2015-5745.patch --- qemu-2.0.0+dfsg/debian/patches/CVE-2015-5745.patch 1970-01-01 00:00:00.000000000 +0000 +++ qemu-2.0.0+dfsg/debian/patches/CVE-2015-5745.patch 2015-08-25 14:03:16.000000000 +0000 @@ -0,0 +1,29 @@ +From 7882080388be5088e72c425b02223c02e6cb4295 Mon Sep 17 00:00:00 2001 +From: Michael S. Tsirkin +Date: Thu, 23 Jul 2015 17:52:02 +0300 +Subject: [PATCH] virtio-serial: fix ANY_LAYOUT + +Don't assume a specific layout for control messages. +Required by virtio 1. + +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Amit Shah +Reviewed-by: Jason Wang +--- + hw/char/virtio-serial-bus.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +Index: qemu-2.0.0+dfsg/hw/char/virtio-serial-bus.c +=================================================================== +--- qemu-2.0.0+dfsg.orig/hw/char/virtio-serial-bus.c 2015-08-25 10:03:12.388231214 -0400 ++++ qemu-2.0.0+dfsg/hw/char/virtio-serial-bus.c 2015-08-25 10:03:12.348230799 -0400 +@@ -173,7 +173,8 @@ + return 0; + } + +- memcpy(elem.in_sg[0].iov_base, buf, len); ++ /* TODO: detect a buffer that's too short, set NEEDS_RESET */ ++ iov_from_buf(elem.in_sg, elem.in_num, 0, buf, len); + + virtqueue_push(vq, &elem, len); + virtio_notify(VIRTIO_DEVICE(vser), vq); diff -Nru qemu-2.0.0+dfsg/debian/patches/series qemu-2.0.0+dfsg/debian/patches/series --- qemu-2.0.0+dfsg/debian/patches/series 2015-07-27 18:23:02.000000000 +0000 +++ qemu-2.0.0+dfsg/debian/patches/series 2015-08-25 14:03:10.000000000 +0000 @@ -63,3 +63,6 @@ ubuntu/add-machine-type-pc-i440fx-1.5-qemu-kvm-for-live-migrate.patch CVE-2015-3214.patch CVE-2015-5154.patch +CVE-2014-9718.patch +CVE-2015-5165.patch +CVE-2015-5745.patch