- bsc#954872 - L3: script block-dmmd not working as expected -
libxl: error: libxl_dm.c block-dmmd - bsc#967101 - VUL-0: CVE-2016-2391: xen: usb: multiple eof_timers in ohci module leads to null pointer dereference CVE-2016-2391-qemuu-usb-null-pointer-dereference-in-ohci-module.patch - bsc#967090 - VUL-0: CVE-2016-2392: xen: usb: null pointer dereference in remote NDIS control message handling CVE-2016-2392-qemuu-usb-null-pointer-dereference-in-NDIS-message-handling.patch - bsc#965315 - VUL-0: CVE-2016-2270: xen: x86: inconsistent cachability flags on guest mappings (XSA-154) xsa154.patch xsa154-fix.patch - bsc#965317 - VUL-0: CVE-2016-2271: xen: VMX: guest user mode may crash guest with non-canonical RIP (XSA-170) xsa170.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=401
This commit is contained in:
parent
077467ba5e
commit
4f6abaa92b
@ -0,0 +1,80 @@
|
|||||||
|
References: bsc#967101 CVE-2016-2391
|
||||||
|
|
||||||
|
From d1b07becc481e09225cfe905ec357807ae07f095 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gerd Hoffmann <address@hidden>
|
||||||
|
Date: Tue, 16 Feb 2016 15:15:04 +0100
|
||||||
|
Subject: [PATCH] ohci timer fix
|
||||||
|
|
||||||
|
Signed-off-by: Gerd Hoffmann <address@hidden>
|
||||||
|
---
|
||||||
|
hw/usb/hcd-ohci.c | 31 +++++--------------------------
|
||||||
|
1 file changed, 5 insertions(+), 26 deletions(-)
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/tools/qemu-xen-dir-remote/hw/usb/hcd-ohci.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/tools/qemu-xen-dir-remote/hw/usb/hcd-ohci.c
|
||||||
|
+++ xen-4.6.1-testing/tools/qemu-xen-dir-remote/hw/usb/hcd-ohci.c
|
||||||
|
@@ -1331,16 +1331,6 @@ static void ohci_frame_boundary(void *op
|
||||||
|
*/
|
||||||
|
static int ohci_bus_start(OHCIState *ohci)
|
||||||
|
{
|
||||||
|
- ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
|
- ohci_frame_boundary,
|
||||||
|
- ohci);
|
||||||
|
-
|
||||||
|
- if (ohci->eof_timer == NULL) {
|
||||||
|
- trace_usb_ohci_bus_eof_timer_failed(ohci->name);
|
||||||
|
- ohci_die(ohci);
|
||||||
|
- return 0;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
trace_usb_ohci_start(ohci->name);
|
||||||
|
|
||||||
|
ohci_sof(ohci);
|
||||||
|
@@ -1352,11 +1342,7 @@ static int ohci_bus_start(OHCIState *ohc
|
||||||
|
static void ohci_bus_stop(OHCIState *ohci)
|
||||||
|
{
|
||||||
|
trace_usb_ohci_stop(ohci->name);
|
||||||
|
- if (ohci->eof_timer) {
|
||||||
|
- timer_del(ohci->eof_timer);
|
||||||
|
- timer_free(ohci->eof_timer);
|
||||||
|
- }
|
||||||
|
- ohci->eof_timer = NULL;
|
||||||
|
+ timer_del(ohci->eof_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets a flag in a port status register but only set it if the port is
|
||||||
|
@@ -1881,6 +1867,8 @@ static int usb_ohci_init(OHCIState *ohci
|
||||||
|
ohci->async_td = 0;
|
||||||
|
qemu_register_reset(ohci_reset, ohci);
|
||||||
|
|
||||||
|
+ ohci->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
|
+ ohci_frame_boundary, ohci);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1997,23 +1985,13 @@ static bool ohci_eof_timer_needed(void *
|
||||||
|
{
|
||||||
|
OHCIState *ohci = opaque;
|
||||||
|
|
||||||
|
- return ohci->eof_timer != NULL;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static int ohci_eof_timer_pre_load(void *opaque)
|
||||||
|
-{
|
||||||
|
- OHCIState *ohci = opaque;
|
||||||
|
-
|
||||||
|
- ohci_bus_start(ohci);
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
+ return timer_pending(ohci->eof_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_ohci_eof_timer = {
|
||||||
|
.name = "ohci-core/eof-timer",
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
- .pre_load = ohci_eof_timer_pre_load,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_TIMER(eof_timer, OHCIState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
@ -0,0 +1,27 @@
|
|||||||
|
References: bsc#967090 CVE-2016-2392
|
||||||
|
|
||||||
|
When processing remote NDIS control message packets, the USB Net
|
||||||
|
device emulator checks to see if the USB configuration descriptor
|
||||||
|
object is of RNDIS type(2). But it does not check if it is null,
|
||||||
|
which leads to a null dereference error. Add check to avoid it.
|
||||||
|
|
||||||
|
Reported-by: Qinghao Tang <address@hidden>
|
||||||
|
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||||
|
---
|
||||||
|
hw/usb/dev-network.c | 3 ++-
|
||||||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/tools/qemu-xen-dir-remote/hw/usb/dev-network.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/tools/qemu-xen-dir-remote/hw/usb/dev-network.c
|
||||||
|
+++ xen-4.6.1-testing/tools/qemu-xen-dir-remote/hw/usb/dev-network.c
|
||||||
|
@@ -650,7 +650,8 @@ typedef struct USBNetState {
|
||||||
|
|
||||||
|
static int is_rndis(USBNetState *s)
|
||||||
|
{
|
||||||
|
- return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE;
|
||||||
|
+ return s->dev.config ?
|
||||||
|
+ s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ndis_query(USBNetState *s, uint32_t oid,
|
90
block-dmmd
90
block-dmmd
@ -2,13 +2,22 @@
|
|||||||
|
|
||||||
# Usage: block-dmmd [add args | remove args]
|
# Usage: block-dmmd [add args | remove args]
|
||||||
#
|
#
|
||||||
# the xm config file should have something like:
|
# the dmmd device syntax (in xm commands/configs) is something like:
|
||||||
# dmmd:md;/dev/md0;md;/dev/md1;lvm;/dev/vg1/lv1
|
# dmmd:md;/dev/md0;md;/dev/md1;lvm;/dev/vg1/lv1
|
||||||
# or
|
# or
|
||||||
# dmmd:lvm;/dev/vg1/lv1;lvm;/dev/vg1/lv2;md;/dev/md0
|
# dmmd:lvm;/dev/vg1/lv1;lvm;/dev/vg1/lv2;md;/dev/md0
|
||||||
# note the last device will be used for VM
|
# device pairs (type;dev) are processed in order, with the last device
|
||||||
|
# assigned to the VM
|
||||||
|
#
|
||||||
|
# md devices can optionally:
|
||||||
|
# specify a config file through:
|
||||||
|
# md;/dev/md100(/var/xen/config/mdadm.conf)
|
||||||
|
# use an array name (mdadm -N option):
|
||||||
|
# dmmd:md;My-MD-name;lvm;/dev/vg1/lv1
|
||||||
|
#
|
||||||
# History:
|
# History:
|
||||||
|
# 2013-07-03, loic.devulder@mpsa.com:
|
||||||
|
# Partial rewrite of the script for supporting MD activation by name
|
||||||
# 2009-06-09, mh@novell.com:
|
# 2009-06-09, mh@novell.com:
|
||||||
# Emit debugging messages into a temporary file; if no longer needed,
|
# Emit debugging messages into a temporary file; if no longer needed,
|
||||||
# just comment the exec I/O redirection below
|
# just comment the exec I/O redirection below
|
||||||
@ -39,7 +48,7 @@ function run_mdadm()
|
|||||||
local msg
|
local msg
|
||||||
local rc
|
local rc
|
||||||
|
|
||||||
msg="`/sbin/mdadm $mdadm_cmd 2>&1`"
|
msg="$(/sbin/mdadm $mdadm_cmd 2>&1)"
|
||||||
rc=$?
|
rc=$?
|
||||||
case "$msg" in
|
case "$msg" in
|
||||||
*"has been started"* | *"already active"* )
|
*"has been started"* | *"already active"* )
|
||||||
@ -59,11 +68,12 @@ function run_mdadm()
|
|||||||
|
|
||||||
function activate_md()
|
function activate_md()
|
||||||
{
|
{
|
||||||
|
# Make it explicitly local
|
||||||
local par=$1
|
local par=$1
|
||||||
local already_active=0 cfg dev rc t
|
local cfg dev dev_path rc t mdadm_opts
|
||||||
|
|
||||||
if [ ${par} = ${par%%(*} ]; then
|
if [ ${par} = ${par%%(*} ]; then
|
||||||
# No configuration file specified:
|
# No configuration file specified
|
||||||
dev=$par
|
dev=$par
|
||||||
cfg=
|
cfg=
|
||||||
else
|
else
|
||||||
@ -71,23 +81,51 @@ function activate_md()
|
|||||||
t=${par#*(}
|
t=${par#*(}
|
||||||
cfg="-c ${t%%)*}"
|
cfg="-c ${t%%)*}"
|
||||||
fi
|
fi
|
||||||
if /sbin/mdadm -Q -D $dev; then
|
|
||||||
already_active=1
|
# Looking for device name or aliase
|
||||||
|
if [ ${dev:0:1} = / ]; then
|
||||||
|
dev_path=${dev%/*}
|
||||||
|
mdadm_opts=
|
||||||
|
else
|
||||||
|
dev_path=/dev/md
|
||||||
|
mdadm_opts="-s -N"
|
||||||
fi
|
fi
|
||||||
run_mdadm "-A $dev $cfg"
|
|
||||||
|
# Is md device already active?
|
||||||
|
# We need to use full path name, aliase is not possible...
|
||||||
|
if [ -e $dev_path/${dev##*/} ]; then
|
||||||
|
/sbin/mdadm -Q -D $dev_path/${dev##*/} 2>/dev/null | grep -iq state.*\:.*inactive || return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_mdadm "-A $mdadm_opts $dev $cfg"
|
||||||
rc=$?
|
rc=$?
|
||||||
if [ $already_active -eq 1 ] && [ $rc -eq 2 ]; then
|
[ $rc -eq 2 ] && return 0
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
function deactivate_md()
|
function deactivate_md()
|
||||||
{
|
{
|
||||||
local par=$1 # Make it explicitly local
|
local par=$1
|
||||||
|
local dev
|
||||||
|
|
||||||
|
if [ ${par} = ${par%%(*} ]; then
|
||||||
|
# No configuration file specified
|
||||||
|
dev=${par}
|
||||||
|
else
|
||||||
|
dev=${par%%(*}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Looking for device name or aliase
|
||||||
|
if [ ${dev:0:1} = / ]; then
|
||||||
|
dev_path=${dev%/*}
|
||||||
|
else
|
||||||
|
dev_path=/dev/md
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We need the device name only while deactivating
|
||||||
|
/sbin/mdadm -S ${dev_path}/${dev##*/} > /dev/null 2>&1
|
||||||
|
|
||||||
## We need the device name only while deactivating
|
|
||||||
/sbin/mdadm -S ${par%%(*}
|
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,9 +134,15 @@ function activate_lvm()
|
|||||||
local run_timeout=90
|
local run_timeout=90
|
||||||
local end_time
|
local end_time
|
||||||
|
|
||||||
|
# First scan for PVs and VGs
|
||||||
|
# We need this for using md device as PV
|
||||||
|
/sbin/pvscan > /dev/null 2>&1
|
||||||
|
# /sbin/vgscan --mknodes > /dev/null 2>&1
|
||||||
|
|
||||||
end_time=$(($(date +%s)+${run_timeout}))
|
end_time=$(($(date +%s)+${run_timeout}))
|
||||||
while true; do
|
while true; do
|
||||||
/sbin/lvchange -aey $1
|
/sbin/lvchange -aey $1 > /dev/null 2>&1
|
||||||
|
|
||||||
if [ $? -eq 0 -a -e $1 ]; then
|
if [ $? -eq 0 -a -e $1 ]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -114,7 +158,8 @@ function activate_lvm()
|
|||||||
|
|
||||||
function deactivate_lvm()
|
function deactivate_lvm()
|
||||||
{
|
{
|
||||||
/sbin/lvchange -aen $1
|
/sbin/lvchange -aen $1 > /dev/null 2>&1
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
# We may have to deactivate the VG now, but can ignore errors:
|
# We may have to deactivate the VG now, but can ignore errors:
|
||||||
# /sbin/vgchange -an ${1%/*} || :
|
# /sbin/vgchange -an ${1%/*} || :
|
||||||
@ -219,7 +264,6 @@ function parse_par()
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
push "$t $s"
|
push "$t $s"
|
||||||
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,11 +282,11 @@ case "$command" in
|
|||||||
fi
|
fi
|
||||||
lastparam=${dmmd##*;}
|
lastparam=${dmmd##*;}
|
||||||
usedevice=${lastparam%(*}
|
usedevice=${lastparam%(*}
|
||||||
xenstore-write $XENBUS_PATH/node "$usedevice"
|
xenstore-write $XENBUS_PATH/node "$usedevice"
|
||||||
write_dev "$usedevice"
|
write_dev "$usedevice"
|
||||||
release_lock "dmmd"
|
release_lock "dmmd"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
remove)
|
remove)
|
||||||
p=`xenstore-read $XENBUS_PATH/params` || true
|
p=`xenstore-read $XENBUS_PATH/params` || true
|
||||||
|
28
xen.changes
28
xen.changes
@ -1,3 +1,20 @@
|
|||||||
|
-------------------------------------------------------------------
|
||||||
|
Thu Feb 18 10:39:00 MST 2016 - carnold@suse.com
|
||||||
|
|
||||||
|
- bsc#954872 - L3: script block-dmmd not working as expected -
|
||||||
|
libxl: error: libxl_dm.c
|
||||||
|
block-dmmd
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Wed Feb 17 08:30:35 MST 2016 - carnold@suse.com
|
||||||
|
|
||||||
|
- bsc#967101 - VUL-0: CVE-2016-2391: xen: usb: multiple eof_timers
|
||||||
|
in ohci module leads to null pointer dereference
|
||||||
|
CVE-2016-2391-qemuu-usb-null-pointer-dereference-in-ohci-module.patch
|
||||||
|
- bsc#967090 - VUL-0: CVE-2016-2392: xen: usb: null pointer
|
||||||
|
dereference in remote NDIS control message handling
|
||||||
|
CVE-2016-2392-qemuu-usb-null-pointer-dereference-in-NDIS-message-handling.patch
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Thu Feb 11 09:29:01 MST 2016 - carnold@suse.com
|
Thu Feb 11 09:29:01 MST 2016 - carnold@suse.com
|
||||||
|
|
||||||
@ -35,6 +52,17 @@ Thu Feb 11 09:29:01 MST 2016 - carnold@suse.com
|
|||||||
xsa167.patch
|
xsa167.patch
|
||||||
xsa168.patch
|
xsa168.patch
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Fri Feb 5 13:07:53 MST 2016 - carnold@suse.com
|
||||||
|
|
||||||
|
- bsc#965315 - VUL-0: CVE-2016-2270: xen: x86: inconsistent
|
||||||
|
cachability flags on guest mappings (XSA-154)
|
||||||
|
xsa154.patch
|
||||||
|
xsa154-fix.patch
|
||||||
|
- bsc#965317 - VUL-0: CVE-2016-2271: xen: VMX: guest user mode may
|
||||||
|
crash guest with non-canonical RIP (XSA-170)
|
||||||
|
xsa170.patch
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
Fri Feb 5 08:51:16 MST 2016 - carnold@suse.com
|
Fri Feb 5 08:51:16 MST 2016 - carnold@suse.com
|
||||||
|
|
||||||
|
10
xen.spec
10
xen.spec
@ -207,11 +207,14 @@ Patch1: 55f7f9d2-libxl-slightly-refine-pci-assignable-add-remove-handlin
|
|||||||
Patch2: 5628fc67-libxl-No-emulated-disk-driver-for-xvdX-disk.patch
|
Patch2: 5628fc67-libxl-No-emulated-disk-driver-for-xvdX-disk.patch
|
||||||
Patch3: 5644b756-x86-HVM-don-t-inject-DB-with-error-code.patch
|
Patch3: 5644b756-x86-HVM-don-t-inject-DB-with-error-code.patch
|
||||||
Patch4: 5649bcbe-libxl-relax-readonly-check-introduced-by-XSA-142-fix.patch
|
Patch4: 5649bcbe-libxl-relax-readonly-check-introduced-by-XSA-142-fix.patch
|
||||||
|
Patch15401: xsa154.patch
|
||||||
|
Patch15402: xsa154-fix.patch
|
||||||
Patch15501: xsa155-xen-0001-xen-Add-RING_COPY_REQUEST.patch
|
Patch15501: xsa155-xen-0001-xen-Add-RING_COPY_REQUEST.patch
|
||||||
Patch15502: xsa155-xen-0002-blktap2-Use-RING_COPY_REQUEST.patch
|
Patch15502: xsa155-xen-0002-blktap2-Use-RING_COPY_REQUEST.patch
|
||||||
Patch15503: xsa155-xen-0003-libvchan-Read-prod-cons-only-once.patch
|
Patch15503: xsa155-xen-0003-libvchan-Read-prod-cons-only-once.patch
|
||||||
Patch162: xsa162-qemuu.patch
|
Patch162: xsa162-qemuu.patch
|
||||||
Patch164: xsa164.patch
|
Patch164: xsa164.patch
|
||||||
|
Patch170: xsa170.patch
|
||||||
# Upstream qemu
|
# Upstream qemu
|
||||||
Patch250: VNC-Support-for-ExtendedKeyEvent-client-message.patch
|
Patch250: VNC-Support-for-ExtendedKeyEvent-client-message.patch
|
||||||
Patch251: 0001-net-move-the-tap-buffer-into-TAPState.patch
|
Patch251: 0001-net-move-the-tap-buffer-into-TAPState.patch
|
||||||
@ -254,6 +257,8 @@ Patch288: CVE-2013-4533-qemut-pxa2xx-buffer-overrun-on-incoming-migration.
|
|||||||
Patch289: CVE-2015-5278-qemut-Infinite-loop-in-ne2000_receive-function.patch
|
Patch289: CVE-2015-5278-qemut-Infinite-loop-in-ne2000_receive-function.patch
|
||||||
Patch290: CVE-2015-6855-qemuu-ide-divide-by-zero-issue.patch
|
Patch290: CVE-2015-6855-qemuu-ide-divide-by-zero-issue.patch
|
||||||
Patch291: CVE-2015-8619-qemuu-stack-based-OOB-write-in-hmp_sendkey-routine.patch
|
Patch291: CVE-2015-8619-qemuu-stack-based-OOB-write-in-hmp_sendkey-routine.patch
|
||||||
|
Patch292: CVE-2016-2392-qemuu-usb-null-pointer-dereference-in-NDIS-message-handling.patch
|
||||||
|
Patch293: CVE-2016-2391-qemuu-usb-null-pointer-dereference-in-ohci-module.patch
|
||||||
# Our platform specific patches
|
# Our platform specific patches
|
||||||
Patch321: xen-destdir.patch
|
Patch321: xen-destdir.patch
|
||||||
Patch322: vif-bridge-no-iptables.patch
|
Patch322: vif-bridge-no-iptables.patch
|
||||||
@ -528,11 +533,14 @@ Authors:
|
|||||||
%patch2 -p1
|
%patch2 -p1
|
||||||
%patch3 -p1
|
%patch3 -p1
|
||||||
%patch4 -p1
|
%patch4 -p1
|
||||||
|
%patch15401 -p1
|
||||||
|
%patch15402 -p1
|
||||||
%patch15501 -p1
|
%patch15501 -p1
|
||||||
%patch15502 -p1
|
%patch15502 -p1
|
||||||
%patch15503 -p1
|
%patch15503 -p1
|
||||||
%patch162 -p1
|
%patch162 -p1
|
||||||
%patch164 -p1
|
%patch164 -p1
|
||||||
|
%patch170 -p1
|
||||||
# Upstream qemu patches
|
# Upstream qemu patches
|
||||||
%patch250 -p1
|
%patch250 -p1
|
||||||
%patch251 -p1
|
%patch251 -p1
|
||||||
@ -575,6 +583,8 @@ Authors:
|
|||||||
%patch289 -p1
|
%patch289 -p1
|
||||||
%patch290 -p1
|
%patch290 -p1
|
||||||
%patch291 -p1
|
%patch291 -p1
|
||||||
|
%patch292 -p1
|
||||||
|
%patch293 -p1
|
||||||
# Our platform specific patches
|
# Our platform specific patches
|
||||||
%patch321 -p1
|
%patch321 -p1
|
||||||
%patch322 -p1
|
%patch322 -p1
|
||||||
|
31
xsa154-fix.patch
Normal file
31
xsa154-fix.patch
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Subject: x86: fix unintended fallthrough case from XSA-154
|
||||||
|
From: Andrew Cooper andrew.cooper3@citrix.com Thu Feb 18 15:10:07 2016 +0100
|
||||||
|
Date: Thu Feb 18 15:10:07 2016 +0100:
|
||||||
|
Git: 8dd6d1c099865ee5f5916616a0ca79cd943c46f9
|
||||||
|
|
||||||
|
... and annotate the other deliberate one: Coverity objects otherwise.
|
||||||
|
|
||||||
|
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||||
|
|
||||||
|
One of the two instances was actually a bug.
|
||||||
|
|
||||||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/mm.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/mm.c
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/mm.c
|
||||||
|
@@ -853,9 +853,11 @@ get_page_from_l1e(
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
- if ( is_hardware_domain(l1e_owner) )
|
||||||
|
+ if ( !is_hardware_domain(l1e_owner) )
|
||||||
|
+ break;
|
||||||
|
+ /* fallthrough */
|
||||||
|
case -1:
|
||||||
|
- return 0;
|
||||||
|
+ return 0;
|
||||||
|
default:
|
||||||
|
ASSERT_UNREACHABLE();
|
||||||
|
}
|
375
xsa154.patch
Normal file
375
xsa154.patch
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
References: bsc#965315 - CVE-2016-2270 XSA-154
|
||||||
|
|
||||||
|
x86: enforce consistent cachability of MMIO mappings
|
||||||
|
|
||||||
|
We've been told by Intel that inconsistent cachability between
|
||||||
|
multiple mappings of the same page can affect system stability only
|
||||||
|
when the affected page is an MMIO one. Since the stale data issue is
|
||||||
|
of no relevance to the hypervisor (since all guest memory accesses go
|
||||||
|
through proper accessors and validation), handling of RAM pages
|
||||||
|
remains unchanged here. Any MMIO mapped by domains however needs to be
|
||||||
|
done consistently (all cachable mappings or all uncachable ones), in
|
||||||
|
order to avoid Machine Check exceptions. Since converting existing
|
||||||
|
cachable mappings to uncachable (at the time an uncachable mapping
|
||||||
|
gets established) would in the PV case require tracking all mappings,
|
||||||
|
allow MMIO to only get mapped uncachable (UC, UC-, or WC).
|
||||||
|
|
||||||
|
This also implies that in the PV case we mustn't use the L1 PTE update
|
||||||
|
fast path when cachability flags get altered.
|
||||||
|
|
||||||
|
Since in the HVM case at least for now we want to continue honoring
|
||||||
|
pinned cachability attributes for pages not mapped by the hypervisor,
|
||||||
|
special case handling of r/o MMIO pages (forcing UC) gets added there.
|
||||||
|
Arguably the counterpart change to p2m-pt.c may not be necessary, since
|
||||||
|
UC- (which already gets enforced there) is probably strict enough.
|
||||||
|
|
||||||
|
Note that the shadow code changes include fixing the write protection
|
||||||
|
of r/o MMIO ranges: shadow_l1e_remove_flags() and its siblings, other
|
||||||
|
than l1e_remove_flags() and alike, return the new PTE (and hence
|
||||||
|
ignoring their return values makes them no-ops).
|
||||||
|
|
||||||
|
This is CVE-2016-2270 / XSA-154.
|
||||||
|
|
||||||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||||
|
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/docs/misc/xen-command-line.markdown
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/docs/misc/xen-command-line.markdown
|
||||||
|
+++ xen-4.6.1-testing/docs/misc/xen-command-line.markdown
|
||||||
|
@@ -1080,6 +1080,15 @@ limit is ignored by Xen.
|
||||||
|
|
||||||
|
Specify if the MMConfig space should be enabled.
|
||||||
|
|
||||||
|
+### mmio-relax
|
||||||
|
+> `= <boolean> | all`
|
||||||
|
+
|
||||||
|
+> Default: `false`
|
||||||
|
+
|
||||||
|
+By default, domains may not create cached mappings to MMIO regions.
|
||||||
|
+This option relaxes the check for Domain 0 (or when using `all`, all PV
|
||||||
|
+domains), to permit the use of cacheable MMIO mappings.
|
||||||
|
+
|
||||||
|
### msi
|
||||||
|
> `= <boolean>`
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/hvm/mtrr.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/hvm/mtrr.c
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/hvm/mtrr.c
|
||||||
|
@@ -807,8 +807,17 @@ int epte_get_entry_emt(struct domain *d,
|
||||||
|
if ( v->domain != d )
|
||||||
|
v = d->vcpu ? d->vcpu[0] : NULL;
|
||||||
|
|
||||||
|
- if ( !mfn_valid(mfn_x(mfn)) )
|
||||||
|
+ if ( !mfn_valid(mfn_x(mfn)) ||
|
||||||
|
+ rangeset_contains_range(mmio_ro_ranges, mfn_x(mfn),
|
||||||
|
+ mfn_x(mfn) + (1UL << order) - 1) )
|
||||||
|
+ {
|
||||||
|
+ *ipat = 1;
|
||||||
|
return MTRR_TYPE_UNCACHABLE;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if ( rangeset_overlaps_range(mmio_ro_ranges, mfn_x(mfn),
|
||||||
|
+ mfn_x(mfn) + (1UL << order) - 1) )
|
||||||
|
+ return -1;
|
||||||
|
|
||||||
|
switch ( hvm_get_mem_pinned_cacheattr(d, gfn, order, &type) )
|
||||||
|
{
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/mm/p2m-pt.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/mm/p2m-pt.c
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/mm/p2m-pt.c
|
||||||
|
@@ -107,6 +107,8 @@ static unsigned long p2m_type_to_flags(p
|
||||||
|
case p2m_mmio_direct:
|
||||||
|
if ( !rangeset_contains_singleton(mmio_ro_ranges, mfn_x(mfn)) )
|
||||||
|
flags |= _PAGE_RW;
|
||||||
|
+ else
|
||||||
|
+ flags |= _PAGE_PWT;
|
||||||
|
return flags | P2M_BASE_FLAGS | _PAGE_PCD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/mm/shadow/multi.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/mm/shadow/multi.c
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/mm/shadow/multi.c
|
||||||
|
@@ -519,6 +519,7 @@ _sh_propagate(struct vcpu *v,
|
||||||
|
gfn_t target_gfn = guest_l1e_get_gfn(guest_entry);
|
||||||
|
u32 pass_thru_flags;
|
||||||
|
u32 gflags, sflags;
|
||||||
|
+ bool_t mmio_mfn;
|
||||||
|
|
||||||
|
/* We don't shadow PAE l3s */
|
||||||
|
ASSERT(GUEST_PAGING_LEVELS > 3 || level != 3);
|
||||||
|
@@ -559,7 +560,10 @@ _sh_propagate(struct vcpu *v,
|
||||||
|
// mfn means that we can not usefully shadow anything, and so we
|
||||||
|
// return early.
|
||||||
|
//
|
||||||
|
- if ( !mfn_valid(target_mfn)
|
||||||
|
+ mmio_mfn = !mfn_valid(target_mfn)
|
||||||
|
+ || (level == 1
|
||||||
|
+ && page_get_owner(mfn_to_page(target_mfn)) == dom_io);
|
||||||
|
+ if ( mmio_mfn
|
||||||
|
&& !(level == 1 && (!shadow_mode_refcounts(d)
|
||||||
|
|| p2mt == p2m_mmio_direct)) )
|
||||||
|
{
|
||||||
|
@@ -577,7 +581,7 @@ _sh_propagate(struct vcpu *v,
|
||||||
|
_PAGE_RW | _PAGE_PRESENT);
|
||||||
|
if ( guest_supports_nx(v) )
|
||||||
|
pass_thru_flags |= _PAGE_NX_BIT;
|
||||||
|
- if ( !shadow_mode_refcounts(d) && !mfn_valid(target_mfn) )
|
||||||
|
+ if ( level == 1 && !shadow_mode_refcounts(d) && mmio_mfn )
|
||||||
|
pass_thru_flags |= _PAGE_PAT | _PAGE_PCD | _PAGE_PWT;
|
||||||
|
sflags = gflags & pass_thru_flags;
|
||||||
|
|
||||||
|
@@ -676,10 +680,14 @@ _sh_propagate(struct vcpu *v,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read-only memory */
|
||||||
|
- if ( p2m_is_readonly(p2mt) ||
|
||||||
|
- (p2mt == p2m_mmio_direct &&
|
||||||
|
- rangeset_contains_singleton(mmio_ro_ranges, mfn_x(target_mfn))) )
|
||||||
|
+ if ( p2m_is_readonly(p2mt) )
|
||||||
|
sflags &= ~_PAGE_RW;
|
||||||
|
+ else if ( p2mt == p2m_mmio_direct &&
|
||||||
|
+ rangeset_contains_singleton(mmio_ro_ranges, mfn_x(target_mfn)) )
|
||||||
|
+ {
|
||||||
|
+ sflags &= ~(_PAGE_RW | _PAGE_PAT);
|
||||||
|
+ sflags |= _PAGE_PCD | _PAGE_PWT;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// protect guest page tables
|
||||||
|
//
|
||||||
|
@@ -1185,22 +1193,28 @@ static int shadow_set_l1e(struct domain
|
||||||
|
&& !sh_l1e_is_magic(new_sl1e) )
|
||||||
|
{
|
||||||
|
/* About to install a new reference */
|
||||||
|
- if ( shadow_mode_refcounts(d) ) {
|
||||||
|
+ if ( shadow_mode_refcounts(d) )
|
||||||
|
+ {
|
||||||
|
+#define PAGE_FLIPPABLE (_PAGE_RW | _PAGE_PWT | _PAGE_PCD | _PAGE_PAT)
|
||||||
|
+ int rc;
|
||||||
|
+
|
||||||
|
TRACE_SHADOW_PATH_FLAG(TRCE_SFLAG_SHADOW_L1_GET_REF);
|
||||||
|
- switch ( shadow_get_page_from_l1e(new_sl1e, d, new_type) )
|
||||||
|
+ switch ( rc = shadow_get_page_from_l1e(new_sl1e, d, new_type) )
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
/* Doesn't look like a pagetable. */
|
||||||
|
flags |= SHADOW_SET_ERROR;
|
||||||
|
new_sl1e = shadow_l1e_empty();
|
||||||
|
break;
|
||||||
|
- case 1:
|
||||||
|
- shadow_l1e_remove_flags(new_sl1e, _PAGE_RW);
|
||||||
|
+ case PAGE_FLIPPABLE & -PAGE_FLIPPABLE ... PAGE_FLIPPABLE:
|
||||||
|
+ ASSERT(!(rc & ~PAGE_FLIPPABLE));
|
||||||
|
+ new_sl1e = shadow_l1e_flip_flags(new_sl1e, rc);
|
||||||
|
/* fall through */
|
||||||
|
case 0:
|
||||||
|
shadow_vram_get_l1e(new_sl1e, sl1e, sl1mfn, d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
+#undef PAGE_FLIPPABLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/mm/shadow/types.h
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/mm/shadow/types.h
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/mm/shadow/types.h
|
||||||
|
@@ -99,6 +99,9 @@ static inline u32 shadow_l4e_get_flags(s
|
||||||
|
static inline shadow_l1e_t
|
||||||
|
shadow_l1e_remove_flags(shadow_l1e_t sl1e, u32 flags)
|
||||||
|
{ l1e_remove_flags(sl1e, flags); return sl1e; }
|
||||||
|
+static inline shadow_l1e_t
|
||||||
|
+shadow_l1e_flip_flags(shadow_l1e_t sl1e, u32 flags)
|
||||||
|
+{ l1e_flip_flags(sl1e, flags); return sl1e; }
|
||||||
|
|
||||||
|
static inline shadow_l1e_t shadow_l1e_empty(void)
|
||||||
|
{ return l1e_empty(); }
|
||||||
|
Index: xen-4.6.1-testing/xen/include/asm-x86/page.h
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/include/asm-x86/page.h
|
||||||
|
+++ xen-4.6.1-testing/xen/include/asm-x86/page.h
|
||||||
|
@@ -157,6 +157,9 @@ static inline l4_pgentry_t l4e_from_padd
|
||||||
|
#define l3e_remove_flags(x, flags) ((x).l3 &= ~put_pte_flags(flags))
|
||||||
|
#define l4e_remove_flags(x, flags) ((x).l4 &= ~put_pte_flags(flags))
|
||||||
|
|
||||||
|
+/* Flip flags in an existing L1 PTE. */
|
||||||
|
+#define l1e_flip_flags(x, flags) ((x).l1 ^= put_pte_flags(flags))
|
||||||
|
+
|
||||||
|
/* Check if a pte's page mapping or significant access flags have changed. */
|
||||||
|
#define l1e_has_changed(x,y,flags) \
|
||||||
|
( !!(((x).l1 ^ (y).l1) & ((PADDR_MASK&PAGE_MASK)|put_pte_flags(flags))) )
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/mm.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/mm.c
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/mm.c
|
||||||
|
@@ -178,6 +178,18 @@ static uint32_t base_disallow_mask;
|
||||||
|
is_pv_domain(d)) ? \
|
||||||
|
L1_DISALLOW_MASK : (L1_DISALLOW_MASK & ~PAGE_CACHE_ATTRS))
|
||||||
|
|
||||||
|
+static s8 __read_mostly opt_mmio_relax;
|
||||||
|
+static void __init parse_mmio_relax(const char *s)
|
||||||
|
+{
|
||||||
|
+ if ( !*s )
|
||||||
|
+ opt_mmio_relax = 1;
|
||||||
|
+ else
|
||||||
|
+ opt_mmio_relax = parse_bool(s);
|
||||||
|
+ if ( opt_mmio_relax < 0 && strcmp(s, "all") )
|
||||||
|
+ opt_mmio_relax = 0;
|
||||||
|
+}
|
||||||
|
+custom_param("mmio-relax", parse_mmio_relax);
|
||||||
|
+
|
||||||
|
static void __init init_frametable_chunk(void *start, void *end)
|
||||||
|
{
|
||||||
|
unsigned long s = (unsigned long)start;
|
||||||
|
@@ -799,10 +811,7 @@ get_page_from_l1e(
|
||||||
|
if ( !mfn_valid(mfn) ||
|
||||||
|
(real_pg_owner = page_get_owner_and_reference(page)) == dom_io )
|
||||||
|
{
|
||||||
|
-#ifndef NDEBUG
|
||||||
|
- const unsigned long *ro_map;
|
||||||
|
- unsigned int seg, bdf;
|
||||||
|
-#endif
|
||||||
|
+ int flip = 0;
|
||||||
|
|
||||||
|
/* Only needed the reference to confirm dom_io ownership. */
|
||||||
|
if ( mfn_valid(mfn) )
|
||||||
|
@@ -836,24 +845,55 @@ get_page_from_l1e(
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ( !(l1f & _PAGE_RW) ||
|
||||||
|
- !rangeset_contains_singleton(mmio_ro_ranges, mfn) )
|
||||||
|
- return 0;
|
||||||
|
+ if ( !rangeset_contains_singleton(mmio_ro_ranges, mfn) )
|
||||||
|
+ {
|
||||||
|
+ /* MMIO pages must not be mapped cachable unless requested so. */
|
||||||
|
+ switch ( opt_mmio_relax )
|
||||||
|
+ {
|
||||||
|
+ case 0:
|
||||||
|
+ break;
|
||||||
|
+ case 1:
|
||||||
|
+ if ( is_hardware_domain(l1e_owner) )
|
||||||
|
+ case -1:
|
||||||
|
+ return 0;
|
||||||
|
+ default:
|
||||||
|
+ ASSERT_UNREACHABLE();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else if ( l1f & _PAGE_RW )
|
||||||
|
+ {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
- if ( !pci_mmcfg_decode(mfn, &seg, &bdf) ||
|
||||||
|
- ((ro_map = pci_get_ro_map(seg)) != NULL &&
|
||||||
|
- test_bit(bdf, ro_map)) )
|
||||||
|
- printk(XENLOG_G_WARNING
|
||||||
|
- "d%d: Forcing read-only access to MFN %lx\n",
|
||||||
|
- l1e_owner->domain_id, mfn);
|
||||||
|
- else
|
||||||
|
- rangeset_report_ranges(mmio_ro_ranges, 0, ~0UL,
|
||||||
|
- print_mmio_emul_range,
|
||||||
|
- &(struct mmio_emul_range_ctxt){
|
||||||
|
- .d = l1e_owner,
|
||||||
|
- .mfn = mfn });
|
||||||
|
+ const unsigned long *ro_map;
|
||||||
|
+ unsigned int seg, bdf;
|
||||||
|
+
|
||||||
|
+ if ( !pci_mmcfg_decode(mfn, &seg, &bdf) ||
|
||||||
|
+ ((ro_map = pci_get_ro_map(seg)) != NULL &&
|
||||||
|
+ test_bit(bdf, ro_map)) )
|
||||||
|
+ printk(XENLOG_G_WARNING
|
||||||
|
+ "d%d: Forcing read-only access to MFN %lx\n",
|
||||||
|
+ l1e_owner->domain_id, mfn);
|
||||||
|
+ else
|
||||||
|
+ rangeset_report_ranges(mmio_ro_ranges, 0, ~0UL,
|
||||||
|
+ print_mmio_emul_range,
|
||||||
|
+ &(struct mmio_emul_range_ctxt){
|
||||||
|
+ .d = l1e_owner,
|
||||||
|
+ .mfn = mfn });
|
||||||
|
#endif
|
||||||
|
- return 1;
|
||||||
|
+ flip = _PAGE_RW;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ switch ( l1f & PAGE_CACHE_ATTRS )
|
||||||
|
+ {
|
||||||
|
+ case 0: /* WB */
|
||||||
|
+ flip |= _PAGE_PWT | _PAGE_PCD;
|
||||||
|
+ break;
|
||||||
|
+ case _PAGE_PWT: /* WT */
|
||||||
|
+ case _PAGE_PWT | _PAGE_PAT: /* WP */
|
||||||
|
+ flip |= _PAGE_PCD | (l1f & _PAGE_PAT);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return flip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( unlikely( (real_pg_owner != pg_owner) &&
|
||||||
|
@@ -1243,8 +1283,9 @@ static int alloc_l1_table(struct page_in
|
||||||
|
goto fail;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
- case 1:
|
||||||
|
- l1e_remove_flags(pl1e[i], _PAGE_RW);
|
||||||
|
+ case _PAGE_RW ... _PAGE_RW | PAGE_CACHE_ATTRS:
|
||||||
|
+ ASSERT(!(ret & ~(_PAGE_RW | PAGE_CACHE_ATTRS)));
|
||||||
|
+ l1e_flip_flags(pl1e[i], ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1759,8 +1800,9 @@ static int mod_l1_entry(l1_pgentry_t *pl
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Fast path for identical mapping, r/w and presence. */
|
||||||
|
- if ( !l1e_has_changed(ol1e, nl1e, _PAGE_RW | _PAGE_PRESENT) )
|
||||||
|
+ /* Fast path for identical mapping, r/w, presence, and cachability. */
|
||||||
|
+ if ( !l1e_has_changed(ol1e, nl1e,
|
||||||
|
+ PAGE_CACHE_ATTRS | _PAGE_RW | _PAGE_PRESENT) )
|
||||||
|
{
|
||||||
|
adjust_guest_l1e(nl1e, pt_dom);
|
||||||
|
if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu,
|
||||||
|
@@ -1783,8 +1825,9 @@ static int mod_l1_entry(l1_pgentry_t *pl
|
||||||
|
return rc;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
- case 1:
|
||||||
|
- l1e_remove_flags(nl1e, _PAGE_RW);
|
||||||
|
+ case _PAGE_RW ... _PAGE_RW | PAGE_CACHE_ATTRS:
|
||||||
|
+ ASSERT(!(rc & ~(_PAGE_RW | PAGE_CACHE_ATTRS)));
|
||||||
|
+ l1e_flip_flags(nl1e, rc);
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -5000,6 +5043,7 @@ static int ptwr_emulated_update(
|
||||||
|
l1_pgentry_t pte, ol1e, nl1e, *pl1e;
|
||||||
|
struct vcpu *v = current;
|
||||||
|
struct domain *d = v->domain;
|
||||||
|
+ int ret;
|
||||||
|
|
||||||
|
/* Only allow naturally-aligned stores within the original %cr2 page. */
|
||||||
|
if ( unlikely(((addr^ptwr_ctxt->cr2) & PAGE_MASK) || (addr & (bytes-1))) )
|
||||||
|
@@ -5047,7 +5091,7 @@ static int ptwr_emulated_update(
|
||||||
|
|
||||||
|
/* Check the new PTE. */
|
||||||
|
nl1e = l1e_from_intpte(val);
|
||||||
|
- switch ( get_page_from_l1e(nl1e, d, d) )
|
||||||
|
+ switch ( ret = get_page_from_l1e(nl1e, d, d) )
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if ( is_pv_32bit_domain(d) && (bytes == 4) && (unaligned_addr & 4) &&
|
||||||
|
@@ -5071,8 +5115,9 @@ static int ptwr_emulated_update(
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
- case 1:
|
||||||
|
- l1e_remove_flags(nl1e, _PAGE_RW);
|
||||||
|
+ case _PAGE_RW ... _PAGE_RW | PAGE_CACHE_ATTRS:
|
||||||
|
+ ASSERT(!(ret & ~(_PAGE_RW | PAGE_CACHE_ATTRS)));
|
||||||
|
+ l1e_flip_flags(nl1e, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
83
xsa170.patch
Normal file
83
xsa170.patch
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
References: bsc#965317 CVE-2016-2271 XSA-170
|
||||||
|
|
||||||
|
x86/VMX: sanitize rIP before re-entering guest
|
||||||
|
|
||||||
|
... to prevent guest user mode arranging for a guest crash (due to
|
||||||
|
failed VM entry). (On the AMD system I checked, hardware is doing
|
||||||
|
exactly the canonicalization being added here.)
|
||||||
|
|
||||||
|
Note that fixing this in an architecturally correct way would be quite
|
||||||
|
a bit more involved: Making the x86 instruction emulator check all
|
||||||
|
branch targets for validity, plus dealing with invalid rIP resulting
|
||||||
|
from update_guest_eip() or incoming directly during a VM exit. The only
|
||||||
|
way to get the latter right would be by not having hardware do the
|
||||||
|
injection.
|
||||||
|
|
||||||
|
Note further that there are a two early returns from
|
||||||
|
vmx_vmexit_handler(): One (through vmx_failed_vmentry()) leads to
|
||||||
|
domain_crash() anyway, and the other covers real mode only and can
|
||||||
|
neither occur with a non-canonical rIP nor result in an altered rIP,
|
||||||
|
so we don't need to force those paths through the checking logic.
|
||||||
|
|
||||||
|
This is XSA-170.
|
||||||
|
|
||||||
|
Reported-by: 刘令 <liuling-it@360.cn>
|
||||||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||||
|
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||||
|
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||||
|
|
||||||
|
Index: xen-4.6.1-testing/xen/arch/x86/hvm/vmx/vmx.c
|
||||||
|
===================================================================
|
||||||
|
--- xen-4.6.1-testing.orig/xen/arch/x86/hvm/vmx/vmx.c
|
||||||
|
+++ xen-4.6.1-testing/xen/arch/x86/hvm/vmx/vmx.c
|
||||||
|
@@ -2879,7 +2879,7 @@ static int vmx_handle_apic_write(void)
|
||||||
|
void vmx_vmexit_handler(struct cpu_user_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned long exit_qualification, exit_reason, idtv_info, intr_info = 0;
|
||||||
|
- unsigned int vector = 0;
|
||||||
|
+ unsigned int vector = 0, mode;
|
||||||
|
struct vcpu *v = current;
|
||||||
|
|
||||||
|
__vmread(GUEST_RIP, ®s->rip);
|
||||||
|
@@ -3468,6 +3468,41 @@ void vmx_vmexit_handler(struct cpu_user_
|
||||||
|
out:
|
||||||
|
if ( nestedhvm_vcpu_in_guestmode(v) )
|
||||||
|
nvmx_idtv_handling();
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * VM entry will fail (causing the guest to get crashed) if rIP (and
|
||||||
|
+ * rFLAGS, but we don't have an issue there) doesn't meet certain
|
||||||
|
+ * criteria. As we must not allow less than fully privileged mode to have
|
||||||
|
+ * such an effect on the domain, we correct rIP in that case (accepting
|
||||||
|
+ * this not being architecturally correct behavior, as the injected #GP
|
||||||
|
+ * fault will then not see the correct [invalid] return address).
|
||||||
|
+ * And since we know the guest will crash, we crash it right away if it
|
||||||
|
+ * already is in most privileged mode.
|
||||||
|
+ */
|
||||||
|
+ mode = vmx_guest_x86_mode(v);
|
||||||
|
+ if ( mode == 8 ? !is_canonical_address(regs->rip)
|
||||||
|
+ : regs->rip != regs->_eip )
|
||||||
|
+ {
|
||||||
|
+ struct segment_register ss;
|
||||||
|
+
|
||||||
|
+ gprintk(XENLOG_WARNING, "Bad rIP %lx for mode %u\n", regs->rip, mode);
|
||||||
|
+
|
||||||
|
+ vmx_get_segment_register(v, x86_seg_ss, &ss);
|
||||||
|
+ if ( ss.attr.fields.dpl )
|
||||||
|
+ {
|
||||||
|
+ __vmread(VM_ENTRY_INTR_INFO, &intr_info);
|
||||||
|
+ if ( !(intr_info & INTR_INFO_VALID_MASK) )
|
||||||
|
+ hvm_inject_hw_exception(TRAP_gp_fault, 0);
|
||||||
|
+ /* Need to fix rIP nevertheless. */
|
||||||
|
+ if ( mode == 8 )
|
||||||
|
+ regs->rip = (long)(regs->rip << (64 - VADDR_BITS)) >>
|
||||||
|
+ (64 - VADDR_BITS);
|
||||||
|
+ else
|
||||||
|
+ regs->rip = regs->_eip;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ domain_crash(v->domain);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmx_vmenter_helper(const struct cpu_user_regs *regs)
|
Loading…
x
Reference in New Issue
Block a user