- 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

- bsc#937371 - xen vm's running after reboot
  xendomains-libvirtd-conflict.patch

- 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

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=371
This commit is contained in:
Charles Arnold 2015-08-11 22:49:00 +00:00 committed by Git OBS Bridge
parent 763b78040d
commit b5fb5e90fb
25 changed files with 1764 additions and 6 deletions

View File

@ -0,0 +1,74 @@
From a9de14175548c04e0f8be7fae219246509ba46a9 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
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 <kwolf@redhat.com>
---
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;

View File

@ -0,0 +1,68 @@
From 1d3c2268f8708126a34064c2e0c1000b40e6f3e5 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
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 <kwolf@redhat.com>
---
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;
}

View File

@ -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 <ronniesahlberg@gmail.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
From aa851d30acfbb9580098ac1dc82885530cb8b3c1 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
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 <kwolf@redhat.com>
---
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 */

View File

@ -0,0 +1,74 @@
From a9de14175548c04e0f8be7fae219246509ba46a9 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
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 <kwolf@redhat.com>
---
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;

View File

@ -0,0 +1,68 @@
From 1d3c2268f8708126a34064c2e0c1000b40e6f3e5 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
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 <kwolf@redhat.com>
---
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;
}

View File

@ -0,0 +1,25 @@
From aa851d30acfbb9580098ac1dc82885530cb8b3c1 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
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 <kwolf@redhat.com>
---
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;
}

View File

@ -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;

View File

@ -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

View File

@ -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 <<EOF
enable xencommons.service
enable xendomains.service
EOF
%endif
cp -bavL %{S:41} $RPM_BUILD_ROOT%{_unitdir}

View File

@ -0,0 +1,20 @@
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

37
xsa139-qemuu.patch Normal file
View File

@ -0,0 +1,37 @@
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 <kwolf@redhat.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
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);
}
}

78
xsa140-qemut-1.patch Normal file
View File

@ -0,0 +1,78 @@
References: bsc#939712 XSA-140
From 5e0c290415b9d57077a86e70c8e6a058868334d3 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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;

339
xsa140-qemut-2.patch Normal file
View File

@ -0,0 +1,339 @@
References: bsc#939712 XSA-140
From 2d7d80e8dc160904fa7276cc05da26c062a50066 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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 */

38
xsa140-qemut-3.patch Normal file
View File

@ -0,0 +1,38 @@
References: bsc#939712 XSA-140
From 043d28507ef7c5fdc34866f5e3b27a72bd0cd072 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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;

50
xsa140-qemut-4.patch Normal file
View File

@ -0,0 +1,50 @@
References: bsc#939712 XSA-140
From 5a75d242fe019d05b46ef9bc330a6892525c84a7 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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)

33
xsa140-qemut-5.patch Normal file
View File

@ -0,0 +1,33 @@
References: bsc#939712 XSA-140
From 6c79ea275d72bc1fd88bdcf1e7d231b2c9c865de Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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)
{

34
xsa140-qemut-6.patch Normal file
View File

@ -0,0 +1,34 @@
References: bsc#939712 XSA-140
From 30aa7be430e7c982e9163f3bcc745d3aa57b6aa4 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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",

31
xsa140-qemut-7.patch Normal file
View File

@ -0,0 +1,31 @@
References: bsc#939712 XSA-140
From 9a084807bf6ca7c16d997a236d304111894a6539 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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;

80
xsa140-qemuu-1.patch Normal file
View File

@ -0,0 +1,80 @@
References: bsc#939712 XSA-140
From 5e0c290415b9d57077a86e70c8e6a058868334d3 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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;

372
xsa140-qemuu-2.patch Normal file
View File

@ -0,0 +1,372 @@
References: bsc#939712 XSA-140
From 2d7d80e8dc160904fa7276cc05da26c062a50066 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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);
}
}

38
xsa140-qemuu-3.patch Normal file
View File

@ -0,0 +1,38 @@
References: bsc#939712 XSA-140
From 043d28507ef7c5fdc34866f5e3b27a72bd0cd072 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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;

52
xsa140-qemuu-4.patch Normal file
View File

@ -0,0 +1,52 @@
References: bsc#939712 XSA-140
From 5a75d242fe019d05b46ef9bc330a6892525c84a7 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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)

33
xsa140-qemuu-5.patch Normal file
View File

@ -0,0 +1,33 @@
References: bsc#939712 XSA-140
From 6c79ea275d72bc1fd88bdcf1e7d231b2c9c865de Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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)
{

34
xsa140-qemuu-6.patch Normal file
View File

@ -0,0 +1,34 @@
References: bsc#939712 XSA-140
From 30aa7be430e7c982e9163f3bcc745d3aa57b6aa4 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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 "

31
xsa140-qemuu-7.patch Normal file
View File

@ -0,0 +1,31 @@
References: bsc#939712 XSA-140
From 9a084807bf6ca7c16d997a236d304111894a6539 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
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 <stefanha@redhat.com>
---
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;