Hello community, here is the log from the commit of package xen for openSUSE:Factory checked in at 2015-08-21 08:24:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/xen (Old) and /work/SRC/openSUSE:Factory/.xen.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xen" Changes: -------- --- /work/SRC/openSUSE:Factory/xen/xen.changes 2015-07-16 17:15:55.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.xen.new/xen.changes 2015-08-21 08:24:25.000000000 +0200 @@ -1,0 +2,48 @@ +Tue Jul 28 09:04:13 MDT 2015 - [email protected] + +- 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 - [email protected] + +- bsc#937371 - xen vm's running after reboot + xendomains-libvirtd-conflict.patch + +------------------------------------------------------------------- +Thu Jul 16 10:14:12 MDT 2015 - [email protected] + +- 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 - [email protected] + +- 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 + +------------------------------------------------------------------- @@ -49,0 +98,5 @@ + +------------------------------------------------------------------- +Tue Jul 7 13:35:34 UTC 2015 - [email protected] + +- Adjust more places to use br0 instead of xenbr0 New: ---- CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch xendomains-libvirtd-conflict.patch xsa139-qemuu.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 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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xen.spec ++++++ --- /var/tmp/diff_new_pack.qbU3ym/_old 2015-08-21 08:24:28.000000000 +0200 +++ /var/tmp/diff_new_pack.qbU3ym/_new 2015-08-21 08:24:28.000000000 +0200 @@ -15,7 +15,6 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # - # needssslcertforbuild Name: xen @@ -216,6 +215,21 @@ 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 @@ 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 @@ 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 @@ %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 @@ %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 @@ %patch470 -p1 %patch471 -p1 %patch472 -p1 +%patch473 -p1 # Hypervisor and PV driver Patches %patch501 -p1 %patch502 -p1 @@ -956,7 +999,6 @@ mkdir -vp $RPM_BUILD_ROOT%_presetdir cat > $RPM_BUILD_ROOT%_presetdir/00-%{name}.preset <<EOF enable xencommons.service -enable xendomains.service EOF %endif cp -bavL %{S:41} $RPM_BUILD_ROOT%{_unitdir} ++++++ CVE-2015-5154-qemut-check-array-bounds-before-writing-to-io_buffer.patch ++++++ >From a9de14175548c04e0f8be7fae219246509ba46a9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <[email protected]> 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: [email protected] Signed-off-by: Kevin Wolf <[email protected]> --- 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; ++++++ CVE-2015-5154-qemut-clear-DRQ-after-handling-all-expected-accesses.patch ++++++ >From 1d3c2268f8708126a34064c2e0c1000b40e6f3e5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <[email protected]> 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 <[email protected]> --- 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; } ++++++ CVE-2015-5154-qemut-fix-START-STOP-UNIT-command-completion.patch ++++++ Subject: ATAPI: STARTSTOPUNIT only eject/load media if powercondition is 0 From: Ronnie Sahlberg [email protected] 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 <[email protected]> Signed-off-by: Kevin Wolf <[email protected]> >From aa851d30acfbb9580098ac1dc82885530cb8b3c1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <[email protected]> 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 <[email protected]> --- 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 */ ++++++ CVE-2015-5154-qemuu-check-array-bounds-before-writing-to-io_buffer.patch ++++++ >From a9de14175548c04e0f8be7fae219246509ba46a9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <[email protected]> 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: [email protected] Signed-off-by: Kevin Wolf <[email protected]> --- 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; ++++++ CVE-2015-5154-qemuu-clear-DRQ-after-handling-all-expected-accesses.patch ++++++ >From 1d3c2268f8708126a34064c2e0c1000b40e6f3e5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <[email protected]> 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 <[email protected]> --- 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; } ++++++ CVE-2015-5154-qemuu-fix-START-STOP-UNIT-command-completion.patch ++++++ >From aa851d30acfbb9580098ac1dc82885530cb8b3c1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf <[email protected]> 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 <[email protected]> --- 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; } ++++++ qemu-dm-segfault.patch ++++++ --- /var/tmp/diff_new_pack.qbU3ym/_old 2015-08-21 08:24:29.000000000 +0200 +++ /var/tmp/diff_new_pack.qbU3ym/_new 2015-08-21 08:24:29.000000000 +0200 @@ -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 @@ 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; ++++++ xendomains-libvirtd-conflict.patch ++++++ xendomains conflicts with libvirtd (bnc#937371) It saves domains without telling libvirt It restores domains without telling libvirt --- tools/hotplug/Linux/systemd/xendomains.service.in | 1 + 1 file changed, 1 insertion(+) Index: xen-4.5.1-testing/tools/hotplug/Linux/systemd/xendomains.service.in =================================================================== --- xen-4.5.1-testing.orig/tools/hotplug/Linux/systemd/xendomains.service.in +++ xen-4.5.1-testing/tools/hotplug/Linux/systemd/xendomains.service.in @@ -5,6 +5,7 @@ After=proc-xen.mount xenstored.service x After=network-online.target After=remote-fs.target ConditionPathExists=/proc/xen/capabilities +Conflicts=libvirtd.service [Service] Type=oneshot ++++++ xsa139-qemuu.patch ++++++ References: bsc#939709 XSA-139 pci_piix3_xen_ide_unplug should completely unhook the unplugged IDEDevice from the corresponding BlockBackend, otherwise the next call to release_drive will try to detach the drive again. Suggested-by: Kevin Wolf <[email protected]> Signed-off-by: Stefano Stabellini <[email protected]> --- 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); } } ++++++ xsa140-qemut-1.patch ++++++ References: bsc#939712 XSA-140 >From 5e0c290415b9d57077a86e70c8e6a058868334d3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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; ++++++ xsa140-qemut-2.patch ++++++ References: bsc#939712 XSA-140 >From 2d7d80e8dc160904fa7276cc05da26c062a50066 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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 (hlen<sizeof(ip_header) || hlen>eth_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 (hlen<sizeof(ip_header) || hlen>eth_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 */ ++++++ xsa140-qemut-3.patch ++++++ References: bsc#939712 XSA-140 >From 043d28507ef7c5fdc34866f5e3b27a72bd0cd072 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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; ++++++ xsa140-qemut-4.patch ++++++ References: bsc#939712 XSA-140 >From 5a75d242fe019d05b46ef9bc330a6892525c84a7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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 (hlen<sizeof(ip_header) || hlen>eth_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) ++++++ xsa140-qemut-5.patch ++++++ References: bsc#939712 XSA-140 >From 6c79ea275d72bc1fd88bdcf1e7d231b2c9c865de Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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) { ++++++ xsa140-qemut-6.patch ++++++ References: bsc#939712 XSA-140 >From 30aa7be430e7c982e9163f3bcc745d3aa57b6aa4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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", ++++++ xsa140-qemut-7.patch ++++++ References: bsc#939712 XSA-140 >From 9a084807bf6ca7c16d997a236d304111894a6539 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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; ++++++ xsa140-qemuu-1.patch ++++++ References: bsc#939712 XSA-140 >From 5e0c290415b9d57077a86e70c8e6a058868334d3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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; ++++++ xsa140-qemuu-2.patch ++++++ References: bsc#939712 XSA-140 >From 2d7d80e8dc160904fa7276cc05da26c062a50066 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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 (hlen<sizeof(ip_header) || hlen>eth_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 (hlen<sizeof(ip_header) || hlen>eth_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); } } ++++++ xsa140-qemuu-3.patch ++++++ References: bsc#939712 XSA-140 >From 043d28507ef7c5fdc34866f5e3b27a72bd0cd072 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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; ++++++ xsa140-qemuu-4.patch ++++++ References: bsc#939712 XSA-140 >From 5a75d242fe019d05b46ef9bc330a6892525c84a7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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 (hlen<sizeof(ip_header) || hlen>eth_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) ++++++ xsa140-qemuu-5.patch ++++++ References: bsc#939712 XSA-140 >From 6c79ea275d72bc1fd88bdcf1e7d231b2c9c865de Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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) { ++++++ xsa140-qemuu-6.patch ++++++ References: bsc#939712 XSA-140 >From 30aa7be430e7c982e9163f3bcc745d3aa57b6aa4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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 " ++++++ xsa140-qemuu-7.patch ++++++ References: bsc#939712 XSA-140 >From 9a084807bf6ca7c16d997a236d304111894a6539 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi <[email protected]> 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 <[email protected]> --- 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;
