diff --git a/CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch b/CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch new file mode 100644 index 0000000..e0fa101 --- /dev/null +++ b/CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch @@ -0,0 +1,74 @@ +From a9de14175548c04e0f8be7fae219246509ba46a9 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 3 Jun 2015 14:13:31 +0200 +Subject: [PATCH 1/3] ide: Check array bounds before writing to io_buffer + (CVE-2015-5154) + +If the end_transfer_func of a command is called because enough data has +been read or written for the current PIO transfer, and it fails to +correctly call the command completion functions, the DRQ bit in the +status register and s->end_transfer_func may remain set. This allows the +guest to access further bytes in s->io_buffer beyond s->data_end, and +eventually overflowing the io_buffer. + +One case where this currently happens is emulation of the ATAPI command +START STOP UNIT. + +This patch fixes the problem by adding explicit array bounds checks +before accessing the buffer instead of relying on end_transfer_func to +function correctly. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +--- + hw/ide/core.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +Index: xen-4.2.5-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +=================================================================== +--- xen-4.2.5-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c ++++ xen-4.2.5-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +@@ -3002,6 +3002,10 @@ static void ide_data_writew(void *opaque + buffered_pio_write(s, addr, 2); + + p = s->data_ptr; ++ if (p + 2 > s->data_end) { ++ return; ++ } ++ + *(uint16_t *)p = le16_to_cpu(val); + p += 2; + s->data_ptr = p; +@@ -3021,6 +3025,10 @@ static uint32_t ide_data_readw(void *opa + buffered_pio_read(s, addr, 2); + + p = s->data_ptr; ++ if (p + 2 > s->data_end) { ++ return 0; ++ } ++ + ret = cpu_to_le16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; +@@ -3040,6 +3048,10 @@ static void ide_data_writel(void *opaque + buffered_pio_write(s, addr, 4); + + p = s->data_ptr; ++ if (p + 4 > s->data_end) { ++ return; ++ } ++ + *(uint32_t *)p = le32_to_cpu(val); + p += 4; + s->data_ptr = p; +@@ -3059,6 +3071,10 @@ static uint32_t ide_data_readl(void *opa + buffered_pio_read(s, addr, 4); + + p = s->data_ptr; ++ if (p + 4 > s->data_end) { ++ return 0; ++ } ++ + ret = cpu_to_le32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; diff --git a/CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch b/CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch new file mode 100644 index 0000000..acbfd6c --- /dev/null +++ b/CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch @@ -0,0 +1,68 @@ +From 1d3c2268f8708126a34064c2e0c1000b40e6f3e5 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 3 Jun 2015 14:41:27 +0200 +Subject: [PATCH 3/3] ide: Clear DRQ after handling all expected accesses + +This is additional hardening against an end_transfer_func that fails to +clear the DRQ status bit. The bit must be unset as soon as the PIO +transfer has completed, so it's better to do this in a central place +instead of duplicating the code in all commands (and forgetting it in +some). + +Signed-off-by: Kevin Wolf +--- + hw/ide/core.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +Index: xen-4.2.5-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +=================================================================== +--- xen-4.2.5-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c ++++ xen-4.2.5-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +@@ -3016,8 +3016,10 @@ static void ide_data_writew(void *opaque + *(uint16_t *)p = le16_to_cpu(val); + p += 2; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + } + + static uint32_t ide_data_readw(void *opaque, uint32_t addr) +@@ -3039,8 +3041,10 @@ static uint32_t ide_data_readw(void *opa + ret = cpu_to_le16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + return ret; + } + +@@ -3062,8 +3066,10 @@ static void ide_data_writel(void *opaque + *(uint32_t *)p = le32_to_cpu(val); + p += 4; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + } + + static uint32_t ide_data_readl(void *opaque, uint32_t addr) +@@ -3085,8 +3091,10 @@ static uint32_t ide_data_readl(void *opa + ret = cpu_to_le32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + return ret; + } + diff --git a/CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch b/CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch new file mode 100644 index 0000000..c670850 --- /dev/null +++ b/CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch @@ -0,0 +1,54 @@ +Subject: ATAPI: STARTSTOPUNIT only eject/load media if powercondition is 0 +From: Ronnie Sahlberg ronniesahlberg@gmail.com Tue Jul 31 11:28:26 2012 +1000 +Date: Wed Sep 12 15:50:09 2012 +0200: +Git: ce560dcf20c14194db5ef3b9fc1ea592d4e68109 + +The START STOP UNIT command will only eject/load media if +power condition is zero. + +If power condition is !0 then LOEJ and START will be ignored. + +From MMC (sbc contains similar wordings too) + The Power Conditions field requests the block device to be placed + in the power condition defined in + Table 558. If this field has a value other than 0h then the Start + and LoEj bits shall be ignored. + +Signed-off-by: Ronnie Sahlberg +Signed-off-by: Kevin Wolf + +From aa851d30acfbb9580098ac1dc82885530cb8b3c1 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 3 Jun 2015 14:17:46 +0200 +Subject: [PATCH 2/3] ide/atapi: Fix START STOP UNIT command completion + +The command must be completed on all code paths. START STOP UNIT with +pwrcnd set should succeed without doing anything. + +Signed-off-by: Kevin Wolf +--- + hw/ide/atapi.c | 1 + + 1 file changed, 1 insertion(+) + +Index: xen-4.2.5-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +=================================================================== +--- xen-4.2.5-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c ++++ xen-4.2.5-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +@@ -2095,9 +2095,16 @@ static void ide_atapi_cmd(IDEState *s) + break; + case GPCMD_START_STOP_UNIT: + { +- int start, eject; ++ int start, eject, pwrcnd; + start = packet[4] & 1; + eject = (packet[4] >> 1) & 1; ++ pwrcnd = buf[4] & 0xf0; ++ ++ if (pwrcnd) { ++ /* eject/load only happens for power condition == 0 */ ++ ide_atapi_cmd_ok(s); ++ return; ++ } + + if (eject && !start) { + /* eject the disk */ diff --git a/CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch b/CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch new file mode 100644 index 0000000..4a08fcb --- /dev/null +++ b/CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch @@ -0,0 +1,74 @@ +From a9de14175548c04e0f8be7fae219246509ba46a9 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 3 Jun 2015 14:13:31 +0200 +Subject: [PATCH 1/3] ide: Check array bounds before writing to io_buffer + (CVE-2015-5154) + +If the end_transfer_func of a command is called because enough data has +been read or written for the current PIO transfer, and it fails to +correctly call the command completion functions, the DRQ bit in the +status register and s->end_transfer_func may remain set. This allows the +guest to access further bytes in s->io_buffer beyond s->data_end, and +eventually overflowing the io_buffer. + +One case where this currently happens is emulation of the ATAPI command +START STOP UNIT. + +This patch fixes the problem by adding explicit array bounds checks +before accessing the buffer instead of relying on end_transfer_func to +function correctly. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +--- + hw/ide/core.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/core.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/ide/core.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/core.c +@@ -1901,6 +1901,10 @@ void ide_data_writew(void *opaque, uint3 + } + + p = s->data_ptr; ++ if (p + 2 > s->data_end) { ++ return; ++ } ++ + *(uint16_t *)p = le16_to_cpu(val); + p += 2; + s->data_ptr = p; +@@ -1922,6 +1926,10 @@ uint32_t ide_data_readw(void *opaque, ui + } + + p = s->data_ptr; ++ if (p + 2 > s->data_end) { ++ return 0; ++ } ++ + ret = cpu_to_le16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; +@@ -1943,6 +1951,10 @@ void ide_data_writel(void *opaque, uint3 + } + + p = s->data_ptr; ++ if (p + 4 > s->data_end) { ++ return; ++ } ++ + *(uint32_t *)p = le32_to_cpu(val); + p += 4; + s->data_ptr = p; +@@ -1964,6 +1976,10 @@ uint32_t ide_data_readl(void *opaque, ui + } + + p = s->data_ptr; ++ if (p + 4 > s->data_end) { ++ return 0; ++ } ++ + ret = cpu_to_le32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; diff --git a/CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch b/CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch new file mode 100644 index 0000000..f6d0f19 --- /dev/null +++ b/CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch @@ -0,0 +1,68 @@ +From 1d3c2268f8708126a34064c2e0c1000b40e6f3e5 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 3 Jun 2015 14:41:27 +0200 +Subject: [PATCH 3/3] ide: Clear DRQ after handling all expected accesses + +This is additional hardening against an end_transfer_func that fails to +clear the DRQ status bit. The bit must be unset as soon as the PIO +transfer has completed, so it's better to do this in a central place +instead of duplicating the code in all commands (and forgetting it in +some). + +Signed-off-by: Kevin Wolf +--- + hw/ide/core.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/core.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/ide/core.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/core.c +@@ -1908,8 +1908,10 @@ void ide_data_writew(void *opaque, uint3 + *(uint16_t *)p = le16_to_cpu(val); + p += 2; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + } + + uint32_t ide_data_readw(void *opaque, uint32_t addr) +@@ -1933,8 +1935,10 @@ uint32_t ide_data_readw(void *opaque, ui + ret = cpu_to_le16(*(uint16_t *)p); + p += 2; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + return ret; + } + +@@ -1958,8 +1962,10 @@ void ide_data_writel(void *opaque, uint3 + *(uint32_t *)p = le32_to_cpu(val); + p += 4; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + } + + uint32_t ide_data_readl(void *opaque, uint32_t addr) +@@ -1983,8 +1989,10 @@ uint32_t ide_data_readl(void *opaque, ui + ret = cpu_to_le32(*(uint32_t *)p); + p += 4; + s->data_ptr = p; +- if (p >= s->data_end) ++ if (p >= s->data_end) { ++ s->status &= ~DRQ_STAT; + s->end_transfer_func(s); ++ } + return ret; + } + diff --git a/CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch b/CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch new file mode 100644 index 0000000..d355907 --- /dev/null +++ b/CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch @@ -0,0 +1,25 @@ +From aa851d30acfbb9580098ac1dc82885530cb8b3c1 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Wed, 3 Jun 2015 14:17:46 +0200 +Subject: [PATCH 2/3] ide/atapi: Fix START STOP UNIT command completion + +The command must be completed on all code paths. START STOP UNIT with +pwrcnd set should succeed without doing anything. + +Signed-off-by: Kevin Wolf +--- + hw/ide/atapi.c | 1 + + 1 file changed, 1 insertion(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/atapi.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/ide/atapi.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/atapi.c +@@ -879,6 +879,7 @@ static void cmd_start_stop_unit(IDEState + + if (pwrcnd) { + /* eject/load only happens for power condition == 0 */ ++ ide_atapi_cmd_ok(s); + return; + } + diff --git a/qemu-dm-segfault.patch b/qemu-dm-segfault.patch index 307a881..5dc60e4 100644 --- a/qemu-dm-segfault.patch +++ b/qemu-dm-segfault.patch @@ -1,7 +1,7 @@ -Index: xen-4.2.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c =================================================================== ---- xen-4.2.0-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c -+++ xen-4.2.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/ide.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c @@ -935,8 +935,9 @@ static inline void ide_dma_submit_check( static inline void ide_set_irq(IDEState *s) @@ -74,7 +74,7 @@ Index: xen-4.2.0-testing/tools/qemu-xen-traditional-dir-remote/hw/ide.c if (ret < 0) { ide_atapi_io_error(s, ret); -@@ -2365,7 +2368,7 @@ static void cdrom_change_cb(void *opaque +@@ -2372,7 +2375,7 @@ static void cdrom_change_cb(void *opaque IDEState *s = opaque; uint64_t nb_sectors; diff --git a/xen.changes b/xen.changes index ad76df0..1ef2b0f 100644 --- a/xen.changes +++ b/xen.changes @@ -1,3 +1,51 @@ +------------------------------------------------------------------- +Tue Jul 28 09:04:13 MDT 2015 - carnold@suse.com + +- bsc#939712 - VUL-0: XSA-140: QEMU leak of uninitialized heap + memory in rtl8139 device model + xsa140-qemuu-1.patch + xsa140-qemuu-2.patch + xsa140-qemuu-3.patch + xsa140-qemuu-4.patch + xsa140-qemuu-5.patch + xsa140-qemuu-6.patch + xsa140-qemuu-7.patch + xsa140-qemut-1.patch + xsa140-qemut-2.patch + xsa140-qemut-3.patch + xsa140-qemut-4.patch + xsa140-qemut-5.patch + xsa140-qemut-6.patch + xsa140-qemut-7.patch +- bsc#939709 - VUL-0: XSA-139: xen: Use after free in QEMU/Xen + block unplug protocol + xsa139-qemuu.patch + +------------------------------------------------------------------- +Tue Jul 21 10:03:24 UTC 2015 - ohering@suse.de + +- bsc#937371 - xen vm's running after reboot + xendomains-libvirtd-conflict.patch + +------------------------------------------------------------------- +Thu Jul 16 10:14:12 MDT 2015 - carnold@suse.com + +- bsc#938344 - VUL-0: CVE-2015-5154: qemu,kvm,xen: host code + execution via IDE subsystem CD-ROM + CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch + CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch + CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch + CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch + CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch + CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch + +------------------------------------------------------------------- +Wed Jul 15 08:28:23 UTC 2015 - ohering@suse.de + +- Remove xendomains.service from systemd preset file because it + conflicts with libvirt-guests.service (bnc#937371) + Its up to the admin to run systemctl enable xendomains.service + ------------------------------------------------------------------- Wed Jul 8 11:38:26 MDT 2015 - carnold@suse.com @@ -48,6 +96,11 @@ Wed Jul 8 11:38:26 MDT 2015 - carnold@suse.com qemu-MSI-X-latch-writes.patch x86-MSI-X-guest-mask.patch +------------------------------------------------------------------- +Tue Jul 7 13:35:34 UTC 2015 - ohering@suse.de + +- Adjust more places to use br0 instead of xenbr0 + ------------------------------------------------------------------- Tue Jun 30 08:25:35 MDT 2015 - carnold@suse.com diff --git a/xen.spec b/xen.spec index 5478004..bbb00c7 100644 --- a/xen.spec +++ b/xen.spec @@ -15,7 +15,6 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # - # needssslcertforbuild Name: xen @@ -216,6 +215,21 @@ Patch11: 559b9dd6-x86-p2m-ept-don-t-unmap-in-use-EPT-pagetable.patch Patch12: 559bdde5-pull-in-latest-linux-earlycpio.patch Patch131: CVE-2015-4106-xsa131-9.patch Patch137: CVE-2015-3259-xsa137.patch +Patch139: xsa139-qemuu.patch +Patch14001: xsa140-qemuu-1.patch +Patch14002: xsa140-qemuu-2.patch +Patch14003: xsa140-qemuu-3.patch +Patch14004: xsa140-qemuu-4.patch +Patch14005: xsa140-qemuu-5.patch +Patch14006: xsa140-qemuu-6.patch +Patch14007: xsa140-qemuu-7.patch +Patch14011: xsa140-qemut-1.patch +Patch14012: xsa140-qemut-2.patch +Patch14013: xsa140-qemut-3.patch +Patch14014: xsa140-qemut-4.patch +Patch14015: xsa140-qemut-5.patch +Patch14016: xsa140-qemut-6.patch +Patch14017: xsa140-qemut-7.patch # Upstream qemu Patch250: VNC-Support-for-ExtendedKeyEvent-client-message.patch Patch251: 0001-net-move-the-tap-buffer-into-TAPState.patch @@ -226,6 +240,12 @@ Patch255: 0005-e1000-multi-buffer-packet-support.patch Patch256: 0006-e1000-clear-EOP-for-multi-buffer-descriptors.patch Patch257: 0007-e1000-verify-we-have-buffers-upfront.patch Patch258: 0008-e1000-check-buffer-availability.patch +Patch259: CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch +Patch260: CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch +Patch261: CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch +Patch262: CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch +Patch263: CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch +Patch264: CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch # Our platform specific patches Patch301: xen-destdir.patch Patch302: vif-bridge-no-iptables.patch @@ -294,6 +314,7 @@ Patch467: libxl.add-option-to-disable-disk-cache-flushes-in-qdisk.patch Patch470: qemu-xen-upstream-qdisk-cache-unsafe.patch Patch471: qemu-xen-enable-spice-support.patch Patch472: tigervnc-long-press.patch +Patch473: xendomains-libvirtd-conflict.patch # Hypervisor and PV driver Patches Patch501: x86-ioapic-ack-default.patch Patch502: x86-cpufreq-report.patch @@ -562,6 +583,21 @@ Authors: %patch12 -p1 %patch131 -p1 %patch137 -p1 +%patch139 -p1 +%patch14001 -p1 +%patch14002 -p1 +%patch14003 -p1 +%patch14004 -p1 +%patch14005 -p1 +%patch14006 -p1 +%patch14007 -p1 +%patch14011 -p1 +%patch14012 -p1 +%patch14013 -p1 +%patch14014 -p1 +%patch14015 -p1 +%patch14016 -p1 +%patch14017 -p1 # Upstream qemu patches %patch250 -p1 %patch251 -p1 @@ -572,6 +608,12 @@ Authors: %patch256 -p1 %patch257 -p1 %patch258 -p1 +%patch259 -p1 +%patch260 -p1 +%patch261 -p1 +%patch262 -p1 +%patch263 -p1 +%patch264 -p1 # Our platform specific patches %patch301 -p1 %patch302 -p1 @@ -639,6 +681,7 @@ Authors: %patch470 -p1 %patch471 -p1 %patch472 -p1 +%patch473 -p1 # Hypervisor and PV driver Patches %patch501 -p1 %patch502 -p1 @@ -956,7 +999,6 @@ mv $RPM_BUILD_ROOT/etc/udev/rules.d/xen-backend.rules $RPM_BUILD_ROOT/etc/udev/r mkdir -vp $RPM_BUILD_ROOT%_presetdir cat > $RPM_BUILD_ROOT%_presetdir/00-%{name}.preset < +Signed-off-by: Stefano Stabellini +--- + hw/ide/piix.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/piix.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/ide/piix.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/ide/piix.c +@@ -172,6 +172,7 @@ int pci_piix3_xen_ide_unplug(DeviceState + PCIIDEState *pci_ide; + DriveInfo *di; + int i = 0; ++ IDEDevice *idedev; + + pci_ide = PCI_IDE(dev); + +@@ -184,6 +185,12 @@ int pci_piix3_xen_ide_unplug(DeviceState + } + bdrv_close(di->bdrv); + pci_ide->bus[di->bus].ifs[di->unit].bs = NULL; ++ if (!(i % 2)) { ++ idedev = pci_ide->bus[di->bus].master; ++ } else { ++ idedev = pci_ide->bus[di->bus].slave; ++ } ++ idedev->conf.bs = NULL; + drive_put_ref(di); + } + } diff --git a/xsa140-qemut-1.patch b/xsa140-qemut-1.patch new file mode 100644 index 0000000..041ebbb --- /dev/null +++ b/xsa140-qemut-1.patch @@ -0,0 +1,78 @@ +References: bsc#939712 XSA-140 + +From 5e0c290415b9d57077a86e70c8e6a058868334d3 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:16:58 +0100 +Subject: [PATCH 1/7] rtl8139: avoid nested ifs in IP header parsing + +Transmit offload needs to parse packet headers. If header fields have +unexpected values the offload processing is skipped. + +The code currently uses nested ifs because there is relatively little +input validation. The next patches will add missing input validation +and a goto label is more appropriate to avoid deep if statement nesting. + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 41 ++++++++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 19 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2113,26 +2113,30 @@ static int rtl8139_cplus_transmit_one(RT + 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) + { +- DEBUG_PRINT(("RTL8139: +++ 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) { +- DEBUG_PRINT(("RTL8139: +++ 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; +- } ++ DEBUG_PRINT(("RTL8139: +++ 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) { ++ DEBUG_PRINT(("RTL8139: +++ 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); ++ ip_protocol = ip->ip_p; ++ ip_data_len = be16_to_cpu(ip->ip_len) - hlen; ++ + if (ip) + { + if (txdw0 & CP_TX_IPCS) +@@ -2315,6 +2319,7 @@ static int rtl8139_cplus_transmit_one(RT + } + } + ++skip_offload: + /* update tally counter */ + ++s->tally_counters.TxOk; + diff --git a/xsa140-qemut-2.patch b/xsa140-qemut-2.patch new file mode 100644 index 0000000..d659e37 --- /dev/null +++ b/xsa140-qemut-2.patch @@ -0,0 +1,339 @@ +References: bsc#939712 XSA-140 + +From 2d7d80e8dc160904fa7276cc05da26c062a50066 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:16:59 +0100 +Subject: [PATCH 2/7] rtl8139: drop tautologous if (ip) {...} statement + +The previous patch stopped using the ip pointer as an indicator that the +IP header is present. When we reach the if (ip) {...} statement we know +ip is always non-NULL. + +Remove the if statement to reduce nesting. + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 305 +++++++++++++++++++++++++++---------------------------- + 1 file changed, 151 insertions(+), 154 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2137,187 +2137,184 @@ static int rtl8139_cplus_transmit_one(RT + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; + +- if (ip) ++ if (txdw0 & CP_TX_IPCS) + { +- if (txdw0 & CP_TX_IPCS) +- { +- DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); ++ DEBUG_PRINT(("RTL8139: +++ 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); +- DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); +- } ++ if (hleneth_payload_len) {/* min header length */ ++ /* bad packet header len */ ++ /* or packet too short */ + } +- +- if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) ++ else + { +-#if defined (DEBUG_RTL8139) +- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; +-#endif +- DEBUG_PRINT(("RTL8139: +++ 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 tcp_send_offset = 0; +- int send_count = 0; ++ ip->ip_sum = 0; ++ ip->ip_sum = ip_checksum(ip, hlen); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); ++ } ++ } + +- /* maximum IP header length is 60 bytes */ +- uint8_t saved_ip_header[60]; ++ if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) ++ { ++ int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + +- /* save IP header template; data area is used in tcp checksum calculation */ +- memcpy(saved_ip_header, eth_payload_data, hlen); ++ DEBUG_PRINT(("RTL8139: +++ 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)); + +- /* 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_send_offset = 0; ++ int send_count = 0; + +- /* pointer to TCP header */ +- tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); ++ /* maximum IP header length is 60 bytes */ ++ uint8_t saved_ip_header[60]; + +- int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); ++ /* save IP header template; data area is used in tcp checksum calculation */ ++ memcpy(saved_ip_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; ++ /* 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; + +- DEBUG_PRINT(("RTL8139: +++ 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)); ++ /* pointer to TCP header */ ++ tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + +- /* note the cycle below overwrites IP header data, +- but restores it from saved_ip_header before sending packet */ ++ int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + +- int is_last_frame = 0; ++ /* 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; + +- for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) +- { +- uint16_t chunk_size = tcp_chunk_size; ++ DEBUG_PRINT(("RTL8139: +++ 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)); + +- /* 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; +- } ++ /* note the cycle below overwrites IP header data, ++ but restores it from saved_ip_header before sending packet */ + +- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); ++ int is_last_frame = 0; + +- /* add 4 TCP pseudoheader fields */ +- /* copy IP source and destination fields */ +- memcpy(data_to_checksum, saved_ip_header + 12, 8); ++ for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) ++ { ++ uint16_t chunk_size = tcp_chunk_size; + +- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); ++ /* 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; ++ } + +- if (tcp_send_offset) +- { +- memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); +- } ++ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); + +- /* 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); +- } ++ /* add 4 TCP pseudoheader fields */ ++ /* copy IP source and destination fields */ ++ memcpy(data_to_checksum, saved_ip_header + 12, 8); + +- /* 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); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); + +- p_tcp_hdr->th_sum = 0; ++ if (tcp_send_offset) ++ { ++ DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); ++ memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); ++ } + +- int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); +- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); ++ /* 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); ++ } + +- p_tcp_hdr->th_sum = tcp_checksum; ++ /* 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); + +- /* restore IP header */ +- memcpy(eth_payload_data, saved_ip_header, hlen); ++ p_tcp_hdr->th_sum = 0; + +- /* set IP data length and recalculate IP checksum */ +- ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); ++ int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); + +- /* increment IP id for subsequent frames */ +- ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); ++ p_tcp_hdr->th_sum = tcp_checksum; + +- ip->ip_sum = 0; +- ip->ip_sum = ip_checksum(eth_payload_data, hlen); +- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); ++ /* restore IP header */ ++ memcpy(eth_payload_data, saved_ip_header, hlen); + +- int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; +- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); +- rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); ++ /* set IP data length and recalculate IP checksum */ ++ ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); + +- /* 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; +- } ++ /* increment IP id for subsequent frames */ ++ ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + +- /* Stop sending this frame */ +- saved_size = 0; ++ ip->ip_sum = 0; ++ ip->ip_sum = ip_checksum(eth_payload_data, hlen); ++ DEBUG_PRINT(("RTL8139: +++ 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; ++ DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); ++ rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); ++ ++ /* 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; + } +- else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) +- { +- DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + +- /* maximum IP header length is 60 bytes */ +- uint8_t saved_ip_header[60]; +- memcpy(saved_ip_header, eth_payload_data, hlen); ++ /* Stop sending this frame */ ++ saved_size = 0; ++ } ++ else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) ++ { ++ DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + +- uint8_t *data_to_checksum = eth_payload_data + hlen - 12; +- // size_t data_to_checksum_len = eth_payload_len - hlen + 12; ++ /* maximum IP header length is 60 bytes */ ++ uint8_t saved_ip_header[60]; ++ memcpy(saved_ip_header, eth_payload_data, hlen); + +- /* add 4 TCP pseudoheader fields */ +- /* copy IP source and destination fields */ +- memcpy(data_to_checksum, saved_ip_header + 12, 8); ++ uint8_t *data_to_checksum = eth_payload_data + hlen - 12; ++ // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + +- if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) +- { +- DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); ++ /* add 4 TCP pseudoheader fields */ ++ /* copy IP source and destination fields */ ++ memcpy(data_to_checksum, saved_ip_header + 12, 8); + +- 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); ++ if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) ++ { ++ DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); + +- tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); ++ 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); + +- p_tcp_hdr->th_sum = 0; ++ tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + +- int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); +- DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); ++ p_tcp_hdr->th_sum = 0; + +- p_tcp_hdr->th_sum = tcp_checksum; +- } +- else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) +- { +- DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); ++ int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); + +- 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); ++ p_tcp_hdr->th_sum = tcp_checksum; ++ } ++ else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) ++ { ++ DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); + +- udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); ++ 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); + +- p_udp_hdr->uh_sum = 0; ++ udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + +- int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); +- DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); ++ p_udp_hdr->uh_sum = 0; + +- p_udp_hdr->uh_sum = udp_checksum; +- } ++ int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); + +- /* restore IP header */ +- memcpy(eth_payload_data, saved_ip_header, hlen); ++ p_udp_hdr->uh_sum = udp_checksum; + } ++ ++ /* restore IP header */ ++ memcpy(eth_payload_data, saved_ip_header, hlen); + } +- } ++ } + + skip_offload: + /* update tally counter */ diff --git a/xsa140-qemut-3.patch b/xsa140-qemut-3.patch new file mode 100644 index 0000000..a60e186 --- /dev/null +++ b/xsa140-qemut-3.patch @@ -0,0 +1,38 @@ +References: bsc#939712 XSA-140 + +From 043d28507ef7c5fdc34866f5e3b27a72bd0cd072 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:00 +0100 +Subject: [PATCH 3/7] rtl8139: skip offload on short Ethernet/IP header + +Transmit offload features access Ethernet and IP headers the packet. If +the packet is too short we must not attempt to access header fields: + + int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); + ... + eth_payload_data = saved_buffer + ETH_HLEN; + ... + ip = (ip_header*)eth_payload_data; + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2103,6 +2103,11 @@ static int rtl8139_cplus_transmit_one(RT + #define ETH_HLEN 14 + #define ETH_MTU 1500 + ++ /* Large enough for Ethernet and IP headers? */ ++ if (saved_size < ETH_HLEN + sizeof(ip_header)) { ++ goto skip_offload; ++ } ++ + /* ip packet header */ + ip_header *ip = 0; + int hlen = 0; diff --git a/xsa140-qemut-4.patch b/xsa140-qemut-4.patch new file mode 100644 index 0000000..d31890d --- /dev/null +++ b/xsa140-qemut-4.patch @@ -0,0 +1,50 @@ +References: bsc#939712 XSA-140 + +From 5a75d242fe019d05b46ef9bc330a6892525c84a7 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:01 +0100 +Subject: [PATCH 4/7] rtl8139: check IP Header Length field + +The IP Header Length field was only checked in the IP checksum case, but +is used in other cases too. + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2139,6 +2139,10 @@ static int rtl8139_cplus_transmit_one(RT + } + + hlen = IP_HEADER_LENGTH(ip); ++ if (hlen < sizeof(ip_header) || hlen > eth_payload_len) { ++ goto skip_offload; ++ } ++ + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; + +@@ -2146,16 +2150,9 @@ static int rtl8139_cplus_transmit_one(RT + { + DEBUG_PRINT(("RTL8139: +++ 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); +- DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); +- } ++ ip->ip_sum = 0; ++ ip->ip_sum = ip_checksum(ip, hlen); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + } + + if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) diff --git a/xsa140-qemut-5.patch b/xsa140-qemut-5.patch new file mode 100644 index 0000000..11e7b88 --- /dev/null +++ b/xsa140-qemut-5.patch @@ -0,0 +1,33 @@ +References: bsc#939712 XSA-140 + +From 6c79ea275d72bc1fd88bdcf1e7d231b2c9c865de Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:02 +0100 +Subject: [PATCH 5/7] rtl8139: check IP Total Length field + +The IP Total Length field includes the IP header and data. Make sure it +is valid and does not exceed the Ethernet payload size. + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2144,7 +2144,12 @@ static int rtl8139_cplus_transmit_one(RT + } + + ip_protocol = ip->ip_p; +- ip_data_len = be16_to_cpu(ip->ip_len) - hlen; ++ ++ ip_data_len = be16_to_cpu(ip->ip_len); ++ if (ip_data_len < hlen || ip_data_len > eth_payload_len) { ++ goto skip_offload; ++ } ++ ip_data_len -= hlen; + + if (txdw0 & CP_TX_IPCS) + { diff --git a/xsa140-qemut-6.patch b/xsa140-qemut-6.patch new file mode 100644 index 0000000..e24e11a --- /dev/null +++ b/xsa140-qemut-6.patch @@ -0,0 +1,34 @@ +References: bsc#939712 XSA-140 + +From 30aa7be430e7c982e9163f3bcc745d3aa57b6aa4 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:03 +0100 +Subject: [PATCH 6/7] rtl8139: skip offload on short TCP header + +TCP Large Segment Offload accesses the TCP header in the packet. If the +packet is too short we must not attempt to access header fields: + + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2162,6 +2162,11 @@ static int rtl8139_cplus_transmit_one(RT + + 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; ++ } ++ + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", diff --git a/xsa140-qemut-7.patch b/xsa140-qemut-7.patch new file mode 100644 index 0000000..5680e29 --- /dev/null +++ b/xsa140-qemut-7.patch @@ -0,0 +1,31 @@ +References: bsc#939712 XSA-140 + +From 9a084807bf6ca7c16d997a236d304111894a6539 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:04 +0100 +Subject: [PATCH 7/7] rtl8139: check TCP Data Offset field + +The TCP Data Offset field contains the length of the header. Make sure +it is valid and does not exceed the IP data length. + +Signed-off-by: Stefan Hajnoczi +--- + hw/rtl8139.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-traditional-dir-remote/hw/rtl8139.c +@@ -2190,6 +2190,11 @@ static int rtl8139_cplus_transmit_one(RT + + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + ++ /* Invalid TCP data offset? */ ++ if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) { ++ goto skip_offload; ++ } ++ + /* 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; diff --git a/xsa140-qemuu-1.patch b/xsa140-qemuu-1.patch new file mode 100644 index 0000000..9b515ff --- /dev/null +++ b/xsa140-qemuu-1.patch @@ -0,0 +1,80 @@ +References: bsc#939712 XSA-140 + +From 5e0c290415b9d57077a86e70c8e6a058868334d3 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:16:58 +0100 +Subject: [PATCH 1/7] rtl8139: avoid nested ifs in IP header parsing + +Transmit offload needs to parse packet headers. If header fields have +unexpected values the offload processing is skipped. + +The code currently uses nested ifs because there is relatively little +input validation. The next patches will add missing input validation +and a goto label is more appropriate to avoid deep if statement nesting. + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 41 ++++++++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 19 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2171,28 +2171,30 @@ static int rtl8139_cplus_transmit_one(RT + 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); ++ ip_protocol = ip->ip_p; ++ ip_data_len = be16_to_cpu(ip->ip_len) - hlen; ++ + if (ip) + { + if (txdw0 & CP_TX_IPCS) +@@ -2388,6 +2390,7 @@ static int rtl8139_cplus_transmit_one(RT + } + } + ++skip_offload: + /* update tally counter */ + ++s->tally_counters.TxOk; + diff --git a/xsa140-qemuu-2.patch b/xsa140-qemuu-2.patch new file mode 100644 index 0000000..ab6e2ae --- /dev/null +++ b/xsa140-qemuu-2.patch @@ -0,0 +1,372 @@ +References: bsc#939712 XSA-140 + +From 2d7d80e8dc160904fa7276cc05da26c062a50066 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:16:59 +0100 +Subject: [PATCH 2/7] rtl8139: drop tautologous if (ip) {...} statement + +The previous patch stopped using the ip pointer as an indicator that the +IP header is present. When we reach the if (ip) {...} statement we know +ip is always non-NULL. + +Remove the if statement to reduce nesting. + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 305 +++++++++++++++++++++++++++---------------------------- + 1 file changed, 151 insertions(+), 154 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2195,198 +2195,195 @@ static int rtl8139_cplus_transmit_one(RT + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; + +- if (ip) ++ 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); +- } ++ if (hleneth_payload_len) {/* min header length */ ++ /* bad packet header len */ ++ /* or packet too short */ + } +- +- if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) ++ else + { +- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; +- +- 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); ++ 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); ++ } ++ } + +- int tcp_send_offset = 0; +- int send_count = 0; ++ if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) ++ { ++ int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + +- /* maximum IP header length is 60 bytes */ +- uint8_t saved_ip_header[60]; ++ 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); + +- /* save IP header template; data area is used in tcp checksum calculation */ +- memcpy(saved_ip_header, eth_payload_data, hlen); ++ int tcp_send_offset = 0; ++ int send_count = 0; + +- /* 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; ++ /* maximum IP header length is 60 bytes */ ++ uint8_t saved_ip_header[60]; + +- /* pointer to TCP header */ +- tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); ++ /* save IP header template; data area is used in tcp checksum calculation */ ++ memcpy(saved_ip_header, eth_payload_data, hlen); + +- int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); ++ /* 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; + +- /* 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; ++ /* pointer to TCP header */ ++ tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + +- 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); ++ int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + +- /* 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) + { +- DPRINTF("+++ C+ mode calculating TCP checksum for " +- "packet with %d bytes data\n", ip_data_len); ++ memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); ++ } + +- 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); ++ /* 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); ++ } + +- tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); ++ /* 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 = 0; ++ p_tcp_hdr->th_sum = tcp_checksum; + +- int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); +- DPRINTF("+++ C+ mode TCP checksum %04x\n", +- tcp_checksum); ++ /* restore IP header */ ++ memcpy(eth_payload_data, saved_ip_header, hlen); + +- 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); ++ /* set IP data length and recalculate IP checksum */ ++ ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); + +- 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); ++ /* increment IP id for subsequent frames */ ++ ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + +- udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); ++ 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; ++ } + +- p_udp_hdr->uh_sum = 0; ++ /* 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"); + +- int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); +- DPRINTF("+++ C+ mode UDP checksum %04x\n", +- udp_checksum); ++ /* maximum IP header length is 60 bytes */ ++ uint8_t saved_ip_header[60]; ++ memcpy(saved_ip_header, eth_payload_data, hlen); + +- p_udp_hdr->uh_sum = udp_checksum; +- } ++ uint8_t *data_to_checksum = eth_payload_data + hlen - 12; ++ // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + +- /* restore IP header */ +- memcpy(eth_payload_data, saved_ip_header, hlen); ++ /* 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 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); + } + } + diff --git a/xsa140-qemuu-3.patch b/xsa140-qemuu-3.patch new file mode 100644 index 0000000..6335da1 --- /dev/null +++ b/xsa140-qemuu-3.patch @@ -0,0 +1,38 @@ +References: bsc#939712 XSA-140 + +From 043d28507ef7c5fdc34866f5e3b27a72bd0cd072 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:00 +0100 +Subject: [PATCH 3/7] rtl8139: skip offload on short Ethernet/IP header + +Transmit offload features access Ethernet and IP headers the packet. If +the packet is too short we must not attempt to access header fields: + + int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); + ... + eth_payload_data = saved_buffer + ETH_HLEN; + ... + ip = (ip_header*)eth_payload_data; + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2161,6 +2161,11 @@ static int rtl8139_cplus_transmit_one(RT + { + 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; diff --git a/xsa140-qemuu-4.patch b/xsa140-qemuu-4.patch new file mode 100644 index 0000000..d9466ba --- /dev/null +++ b/xsa140-qemuu-4.patch @@ -0,0 +1,52 @@ +References: bsc#939712 XSA-140 + +From 5a75d242fe019d05b46ef9bc330a6892525c84a7 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:01 +0100 +Subject: [PATCH 4/7] rtl8139: check IP Header Length field + +The IP Header Length field was only checked in the IP checksum case, but +is used in other cases too. + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2197,6 +2197,10 @@ static int rtl8139_cplus_transmit_one(RT + } + + hlen = IP_HEADER_LENGTH(ip); ++ if (hlen < sizeof(ip_header) || hlen > eth_payload_len) { ++ goto skip_offload; ++ } ++ + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; + +@@ -2204,17 +2208,10 @@ static int rtl8139_cplus_transmit_one(RT + { + 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) diff --git a/xsa140-qemuu-5.patch b/xsa140-qemuu-5.patch new file mode 100644 index 0000000..9f92ea3 --- /dev/null +++ b/xsa140-qemuu-5.patch @@ -0,0 +1,33 @@ +References: bsc#939712 XSA-140 + +From 6c79ea275d72bc1fd88bdcf1e7d231b2c9c865de Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:02 +0100 +Subject: [PATCH 5/7] rtl8139: check IP Total Length field + +The IP Total Length field includes the IP header and data. Make sure it +is valid and does not exceed the Ethernet payload size. + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2202,7 +2202,12 @@ static int rtl8139_cplus_transmit_one(RT + } + + ip_protocol = ip->ip_p; +- ip_data_len = be16_to_cpu(ip->ip_len) - hlen; ++ ++ ip_data_len = be16_to_cpu(ip->ip_len); ++ if (ip_data_len < hlen || ip_data_len > eth_payload_len) { ++ goto skip_offload; ++ } ++ ip_data_len -= hlen; + + if (txdw0 & CP_TX_IPCS) + { diff --git a/xsa140-qemuu-6.patch b/xsa140-qemuu-6.patch new file mode 100644 index 0000000..6fc2a64 --- /dev/null +++ b/xsa140-qemuu-6.patch @@ -0,0 +1,34 @@ +References: bsc#939712 XSA-140 + +From 30aa7be430e7c982e9163f3bcc745d3aa57b6aa4 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:03 +0100 +Subject: [PATCH 6/7] rtl8139: skip offload on short TCP header + +TCP Large Segment Offload accesses the TCP header in the packet. If the +packet is too short we must not attempt to access header fields: + + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2221,6 +2221,11 @@ static int rtl8139_cplus_transmit_one(RT + + 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; ++ } ++ + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; + + DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d " diff --git a/xsa140-qemuu-7.patch b/xsa140-qemuu-7.patch new file mode 100644 index 0000000..544c960 --- /dev/null +++ b/xsa140-qemuu-7.patch @@ -0,0 +1,31 @@ +References: bsc#939712 XSA-140 + +From 9a084807bf6ca7c16d997a236d304111894a6539 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Wed, 15 Jul 2015 18:17:04 +0100 +Subject: [PATCH 7/7] rtl8139: check TCP Data Offset field + +The TCP Data Offset field contains the length of the header. Make sure +it is valid and does not exceed the IP data length. + +Signed-off-by: Stefan Hajnoczi +--- + hw/net/rtl8139.c | 5 +++++ + 1 file changed, 5 insertions(+) + +Index: xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +=================================================================== +--- xen-4.5.1-testing.orig/tools/qemu-xen-dir-remote/hw/net/rtl8139.c ++++ xen-4.5.1-testing/tools/qemu-xen-dir-remote/hw/net/rtl8139.c +@@ -2250,6 +2250,11 @@ static int rtl8139_cplus_transmit_one(RT + + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + ++ /* Invalid TCP data offset? */ ++ if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) { ++ goto skip_offload; ++ } ++ + /* 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;