Compare commits
11 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d5bea92a5 | ||
|
|
8cfa1f224d | ||
|
|
47e68f69a5 | ||
|
|
c1dd47a6db | ||
|
|
d1afe2704c | ||
|
|
9cb1314e73 | ||
|
|
7a127d3fbe | ||
|
|
ceaeefb05a | ||
|
|
ec4c2c59a0 | ||
|
|
d759d346c3 | ||
|
|
132ad1fbee |
117 changed files with 8367 additions and 5716 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -6,5 +6,4 @@ lwip-1.3.0.tar.gz
|
|||
pciutils-2.2.9.tar.bz2
|
||||
zlib-1.2.3.tar.gz
|
||||
polarssl-1.1.4-gpl.tgz
|
||||
/mini-os-4.21.0.tar.xz
|
||||
/xen-4.21.1.tar.xz
|
||||
/xen-4.12.3.tar.gz
|
||||
|
|
|
|||
11
CVE-2014-0150.patch
Normal file
11
CVE-2014-0150.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- xen-4.4.1/tools/qemu-xen-traditional/hw/virtio-net.c.orig 2014-07-02 15:54:37.000000000 +0100
|
||||
+++ xen-4.4.1/tools/qemu-xen-traditional/hw/virtio-net.c 2014-11-18 20:50:13.593122915 +0000
|
||||
@@ -192,7 +192,7 @@
|
||||
return VIRTIO_NET_ERR;
|
||||
|
||||
if (mac_data.entries) {
|
||||
- if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
+ if (n->mac_table.in_use <= MAC_TABLE_ENTRIES - mac_data.entries) {
|
||||
memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
|
||||
elem->out_sg[2].iov_base + sizeof(mac_data),
|
||||
mac_data.entries * ETH_ALEN);
|
||||
11
qemu.trad.CVE-2015-5278.patch
Normal file
11
qemu.trad.CVE-2015-5278.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c.orig 2015-09-26 17:27:49.494334726 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c 2015-09-26 17:31:53.107474932 +0100
|
||||
@@ -331,7 +331,7 @@
|
||||
if (index <= s->stop)
|
||||
avail = s->stop - index;
|
||||
else
|
||||
- avail = 0;
|
||||
+ break;
|
||||
len = size;
|
||||
if (len > avail)
|
||||
len = avail;
|
||||
48
qemu.trad.CVE-2015-5279.patch
Normal file
48
qemu.trad.CVE-2015-5279.patch
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c 2015-09-26 17:27:49.494334726 +0100
|
||||
@@ -304,6 +304,9 @@
|
||||
}
|
||||
|
||||
index = s->curpag << 8;
|
||||
+ if (index >= NE2000_PMEM_END) {
|
||||
+ index = s->start;
|
||||
+ }
|
||||
/* 4 bytes for header */
|
||||
total_len = size + 4;
|
||||
/* address for next packet (4 bytes for CRC) */
|
||||
@@ -387,15 +390,21 @@
|
||||
offset = addr | (page << 4);
|
||||
switch(offset) {
|
||||
case EN0_STARTPG:
|
||||
- s->start = val << 8;
|
||||
+ if (val << 8 <= NE2000_PMEM_END) {
|
||||
+ s->start = val << 8;
|
||||
+ }
|
||||
s->tainted = 1;
|
||||
break;
|
||||
case EN0_STOPPG:
|
||||
- s->stop = val << 8;
|
||||
+ if (val << 8 <= NE2000_PMEM_END) {
|
||||
+ s->stop = val << 8;
|
||||
+ }
|
||||
s->tainted = 1;
|
||||
break;
|
||||
case EN0_BOUNDARY:
|
||||
- s->boundary = val;
|
||||
+ if (val << 8 < NE2000_PMEM_END) {
|
||||
+ s->boundary = val;
|
||||
+ }
|
||||
break;
|
||||
case EN0_IMR:
|
||||
s->imr = val;
|
||||
@@ -436,7 +445,9 @@
|
||||
s->phys[offset - EN1_PHYS] = val;
|
||||
break;
|
||||
case EN1_CURPAG:
|
||||
- s->curpag = val;
|
||||
+ if (val << 8 < NE2000_PMEM_END) {
|
||||
+ s->curpag = val;
|
||||
+ }
|
||||
s->tainted = 1;
|
||||
break;
|
||||
case EN1_MULT ... EN1_MULT + 7:
|
||||
12
qemu.trad.CVE-2015-6815.patch
Normal file
12
qemu.trad.CVE-2015-6815.patch
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/e1000.c.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/e1000.c 2015-09-26 17:16:36.406544380 +0100
|
||||
@@ -461,7 +461,8 @@
|
||||
memmove(tp->data, tp->header, hdr);
|
||||
tp->size = hdr;
|
||||
}
|
||||
- } while (split_size -= bytes);
|
||||
+ split_size -= bytes;
|
||||
+ } while (bytes && split_size);
|
||||
} else if (!tp->tse && tp->cptse) {
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentaion Error\n");
|
||||
63
qemu.trad.CVE-2015-7295.patch
Normal file
63
qemu.trad.CVE-2015-7295.patch
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.c.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.c 2015-10-10 16:57:01.806370020 +0100
|
||||
@@ -268,8 +268,8 @@
|
||||
return vring_avail_idx(vq) == vq->last_avail_idx;
|
||||
}
|
||||
|
||||
-void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
- unsigned int len, unsigned int idx)
|
||||
+static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len)
|
||||
{
|
||||
unsigned int offset;
|
||||
int i;
|
||||
@@ -302,7 +302,19 @@
|
||||
|
||||
offset += size;
|
||||
}
|
||||
+}
|
||||
|
||||
+void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len)
|
||||
+{
|
||||
+ vq->last_avail_idx--;
|
||||
+ virtqueue_unmap_sg(vq, elem, len);
|
||||
+}
|
||||
+
|
||||
+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len, unsigned int idx)
|
||||
+{
|
||||
+ virtqueue_unmap_sg(vq, elem, len);
|
||||
idx = (idx + vring_used_idx(vq)) % vq->vring.num;
|
||||
|
||||
/* Get a pointer to the next entry in the used ring. */
|
||||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.h.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.h 2015-10-10 16:57:53.146216039 +0100
|
||||
@@ -105,6 +105,8 @@
|
||||
void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len);
|
||||
void virtqueue_flush(VirtQueue *vq, unsigned int count);
|
||||
+void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len);
|
||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio-net.c.orig 2015-10-10 16:10:05.071786348 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio-net.c 2015-10-10 19:05:34.510029916 +0100
|
||||
@@ -424,11 +424,15 @@
|
||||
len = iov_fill(sg, elem.in_num,
|
||||
buf + offset, size - offset);
|
||||
total += len;
|
||||
+ offset += len;
|
||||
+ if (!n->mergeable_rx_bufs && offset < size) {
|
||||
+ virtqueue_discard(n->rx_vq, &elem, total);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
/* signal other side */
|
||||
virtqueue_fill(n->rx_vq, &elem, total, i++);
|
||||
|
||||
- offset += len;
|
||||
}
|
||||
|
||||
if (mhdr)
|
||||
37
qemu.trad.CVE-2015-7512.patch
Normal file
37
qemu.trad.CVE-2015-7512.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
From 8b98a2f07175d46c3f7217639bd5e03f2ec56343 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Wang <jasowang@redhat.com>
|
||||
Date: Mon, 30 Nov 2015 15:00:06 +0800
|
||||
Subject: [PATCH] pcnet: fix rx buffer overflow(CVE-2015-7512)
|
||||
|
||||
Backends could provide a packet whose length is greater than buffer
|
||||
size. Check for this and truncate the packet to avoid rx buffer
|
||||
overflow in this case.
|
||||
|
||||
Cc: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/pcnet.c | 6 ++++++
|
||||
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/pcnet.c b/tools/qemu-xen-traditional/hw/pcnet.c
|
||||
index 309c40b..1f4a3db 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/pcnet.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/pcnet.c
|
||||
@@ -1064,6 +1064,12 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
int pktcount = 0;
|
||||
|
||||
if (!s->looptest) {
|
||||
+ if (size > 4092) {
|
||||
+#ifdef PCNET_DEBUG_RMD
|
||||
+ fprintf(stderr, "pcnet: truncates rx packet.\n");
|
||||
+#endif
|
||||
+ size = 4092;
|
||||
+ }
|
||||
memcpy(src, buf, size);
|
||||
/* no need to compute the CRC */
|
||||
src[size] = 0;
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
38
qemu.trad.CVE-2015-8345.patch
Normal file
38
qemu.trad.CVE-2015-8345.patch
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
From 00837731d254908a841d69298a4f9f077babaf24 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Weil <sw@weilnetz.de>
|
||||
Date: Fri, 20 Nov 2015 08:42:33 +0100
|
||||
Subject: [PATCH] eepro100: Prevent two endless loops
|
||||
|
||||
http://lists.nongnu.org/archive/html/qemu-devel/2015-11/msg04592.html
|
||||
shows an example how an endless loop in function action_command can
|
||||
be achieved.
|
||||
|
||||
During my code review, I noticed a 2nd case which can result in an
|
||||
endless loop.
|
||||
|
||||
Reported-by: Qinghao Tang <luodalongde@gmail.com>
|
||||
Signed-off-by: Stefan Weil <sw@weilnetz.de>
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/eepro100.c | 16 ++++++++++++++++
|
||||
1 files changed, 16 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/eepro100.c b/tools/qemu-xen-traditional/hw/eepro100.c
|
||||
index 60333b7..685a478 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/eepro100.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/eepro100.c
|
||||
@@ -774,6 +774,11 @@ static void tx_command(EEPRO100State *s)
|
||||
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
||||
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
||||
//~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
||||
+ if (tx_buffer_size == 0) {
|
||||
+ /* Prevent an endless loop. */
|
||||
+ logout("loop in %s:%u\n", __FILE__, __LINE__);
|
||||
+ break;
|
||||
+ }
|
||||
tbd_address += 8;
|
||||
logout
|
||||
("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
44
qemu.trad.CVE-2015-8504.patch
Normal file
44
qemu.trad.CVE-2015-8504.patch
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
From 4c65fed8bdf96780735dbdb92a8bd0d6b6526cc3 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 3 Dec 2015 18:54:17 +0530
|
||||
Subject: [PATCH] ui: vnc: avoid floating point exception
|
||||
|
||||
While sending 'SetPixelFormat' messages to a VNC server,
|
||||
the client could set the 'red-max', 'green-max' and 'blue-max'
|
||||
values to be zero. This leads to a floating point exception in
|
||||
write_png_palette while doing frame buffer updates.
|
||||
|
||||
Reported-by: Lian Yihan <lianyihan@360.cn>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
---
|
||||
tools/qemu-xen-traditional/vnc.c | 6 +++---
|
||||
1 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/vnc.c b/tools/qemu-xen-traditional/vnc.c
|
||||
index 7538405..cbe4d33 100644
|
||||
--- a/tools/qemu-xen-traditional/vnc.c
|
||||
+++ b/tools/qemu-xen-traditional/vnc.c
|
||||
@@ -2198,15 +2198,15 @@ static void set_pixel_format(VncState *vs,
|
||||
}
|
||||
|
||||
vs->clientds = vs->serverds;
|
||||
- vs->clientds.pf.rmax = red_max;
|
||||
+ vs->clientds.pf.rmax = red_max ? red_max : 0xFF;
|
||||
count_bits(vs->clientds.pf.rbits, red_max);
|
||||
vs->clientds.pf.rshift = red_shift;
|
||||
vs->clientds.pf.rmask = red_max << red_shift;
|
||||
- vs->clientds.pf.gmax = green_max;
|
||||
+ vs->clientds.pf.gmax = green_max ? green_max : 0xFF;
|
||||
count_bits(vs->clientds.pf.gbits, green_max);
|
||||
vs->clientds.pf.gshift = green_shift;
|
||||
vs->clientds.pf.gmask = green_max << green_shift;
|
||||
- vs->clientds.pf.bmax = blue_max;
|
||||
+ vs->clientds.pf.bmax = blue_max ? blue_max : 0xFF;
|
||||
count_bits(vs->clientds.pf.bbits, blue_max);
|
||||
vs->clientds.pf.bshift = blue_shift;
|
||||
vs->clientds.pf.bmask = blue_max << blue_shift;
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
30
qemu.trad.CVE-2016-1714.patch
Normal file
30
qemu.trad.CVE-2016-1714.patch
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
--- xen-4.6.1/tools/qemu-xen-traditional/hw/fw_cfg.c.orig 2016-01-04 15:35:42.000000000 +0000
|
||||
+++ xen-4.6.1/tools/qemu-xen-traditional/hw/fw_cfg.c 2016-03-06 16:42:33.464296362 +0000
|
||||
@@ -54,11 +54,15 @@
|
||||
static void fw_cfg_write(FWCfgState *s, uint8_t value)
|
||||
{
|
||||
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
||||
- FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
+ FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
|
||||
+ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
|
||||
FW_CFG_DPRINTF("write %d\n", value);
|
||||
|
||||
- if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
|
||||
+ if (s->cur_entry & FW_CFG_WRITE_CHANNEL
|
||||
+ && e != NULL
|
||||
+ && e->callback
|
||||
+ && s->cur_offset < e->len) {
|
||||
e->data[s->cur_offset++] = value;
|
||||
if (s->cur_offset == e->len) {
|
||||
e->callback(e->callback_opaque, e->data);
|
||||
@@ -88,7 +92,8 @@
|
||||
static uint8_t fw_cfg_read(FWCfgState *s)
|
||||
{
|
||||
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
||||
- FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
+ FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
|
||||
+ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
uint8_t ret;
|
||||
|
||||
if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
|
||||
104
qemu.trad.CVE-2016-1981.patch
Normal file
104
qemu.trad.CVE-2016-1981.patch
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: Laszlo Ersek
|
||||
*Subject*: [Qemu-devel] [PATCH] e1000: eliminate infinite loops on
|
||||
out-of-bounds transfer start
|
||||
*Date*: Tue, 19 Jan 2016 14:17:20 +0100
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The start_xmit() and e1000_receive_iov() functions implement DMA transfers
|
||||
iterating over a set of descriptors that the guest's e1000 driver
|
||||
prepares:
|
||||
|
||||
- the TDLEN and RDLEN registers store the total size of the descriptor
|
||||
area,
|
||||
|
||||
- while the TDH and RDH registers store the offset (in whole tx / rx
|
||||
descriptors) into the area where the transfer is supposed to start.
|
||||
|
||||
Each time a descriptor is processed, the TDH and RDH register is bumped
|
||||
(as appropriate for the transfer direction).
|
||||
|
||||
QEMU already contains logic to deal with bogus transfers submitted by the
|
||||
guest:
|
||||
|
||||
- Normally, the transmit case wants to increase TDH from its initial value
|
||||
to TDT. (TDT is allowed to be numerically smaller than the initial TDH
|
||||
value; wrapping at or above TDLEN bytes to zero is normal.) The failsafe
|
||||
that QEMU currently has here is a check against reaching the original
|
||||
TDH value again -- a complete wraparound, which should never happen.
|
||||
|
||||
- In the receive case RDH is increased from its initial value until
|
||||
"total_size" bytes have been received; preferably in a single step, or
|
||||
in "s->rxbuf_size" byte steps, if the latter is smaller. However, null
|
||||
RX descriptors are skipped without receiving data, while RDH is
|
||||
incremented just the same. QEMU tries to prevent an infinite loop
|
||||
(processing only null RX descriptors) by detecting whether RDH assumes
|
||||
its original value during the loop. (Again, wrapping from RDLEN to 0 is
|
||||
normal.)
|
||||
|
||||
What both directions miss is that the guest could program TDLEN and RDLEN
|
||||
so low, and the initial TDH and RDH so high, that these registers will
|
||||
immediately be truncated to zero, and then never reassume their initial
|
||||
values in the loop -- a full wraparound will never occur.
|
||||
|
||||
The condition that expresses this is:
|
||||
|
||||
xdh_start >= s->mac_reg[XDLEN] / sizeof(desc)
|
||||
|
||||
i.e., TDH or RDH start out after the last whole rx or tx descriptor that
|
||||
fits into the TDLEN or RDLEN sized area.
|
||||
|
||||
This condition could be checked before we enter the loops, but
|
||||
pci_dma_read() / pci_dma_write() knows how to fill in buffers safely for
|
||||
bogus DMA addresses, so we just extend the existing failsafes with the
|
||||
above condition.
|
||||
|
||||
Cc: "Michael S. Tsirkin" <address@hidden>
|
||||
Cc: Petr Matousek <address@hidden>
|
||||
Cc: Stefano Stabellini <address@hidden>
|
||||
Cc: Prasad Pandit <address@hidden>
|
||||
Cc: Michael Roth <address@hidden>
|
||||
Cc: Jason Wang <address@hidden>
|
||||
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044
|
||||
Signed-off-by: Laszlo Ersek <address@hidden>
|
||||
Reviewed-by: Jason Wang <address@hidden>
|
||||
---
|
||||
|
||||
Notes:
|
||||
Regarding the public posting: we made an honest effort to vet this
|
||||
vulnerability, and the impact seems low -- no host side reads/writes,
|
||||
"just" a DoS (infinite loop). We decided the patch could be posted
|
||||
publicly, for the usual review process. Jason and Prasad checked the
|
||||
patch in the internal discussion already, but comments, improvements
|
||||
etc. are clearly welcome. The CVE request is underway. Thanks.
|
||||
|
||||
hw/net/e1000.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
|
||||
index bec06e9..34d0823 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/e1000.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/e1000.c
|
||||
@@ -908,7 +908,8 @@ start_xmit(E1000State *s)
|
||||
* bogus values to TDT/TDLEN.
|
||||
* there's nothing too intelligent we could do about this.
|
||||
*/
|
||||
- if (s->mac_reg[TDH] == tdh_start) {
|
||||
+ if (s->mac_reg[TDH] == tdh_start ||
|
||||
+ tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
|
||||
DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
|
||||
tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
|
||||
break;
|
||||
@@ -1165,7 +1166,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
s->mac_reg[RDH] = 0;
|
||||
s->check_rxov = 1;
|
||||
/* see comment in start_xmit; same here */
|
||||
- if (s->mac_reg[RDH] == rdh_start) {
|
||||
+ if (s->mac_reg[RDH] == rdh_start ||
|
||||
+ rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
|
||||
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
||||
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
|
||||
set_ics(s, 0, E1000_ICS_RXO);
|
||||
--
|
||||
1.8.3.1
|
||||
56
qemu.trad.CVE-2016-2538.patch
Normal file
56
qemu.trad.CVE-2016-2538.patch
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
When processing remote NDIS control message packets,
|
||||
the USB Net device emulator uses a fixed length(4096) data buffer.
|
||||
The incoming informationBufferOffset & Length combination could
|
||||
overflow and cross that range. Check control message buffer
|
||||
offsets and length to avoid it.
|
||||
|
||||
Reported-by: Qinghao Tang <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/usb/dev-network.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
Update as per review
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg03475.html
|
||||
|
||||
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
|
||||
index 8a4ff49..180adce 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/usb-net.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/usb-net.c
|
||||
@@ -915,8 +915,9 @@ static int rndis_query_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
- if (bufoffs + buflen > length)
|
||||
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
+ }
|
||||
|
||||
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
||||
@@ -961,8 +962,9 @@ static int rndis_set_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
- if (bufoffs + buflen > length)
|
||||
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
+ }
|
||||
|
||||
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen);
|
||||
@@ -1212,8 +1214,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
||||
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
||||
uint32_t size = le32_to_cpu(msg->DataLength);
|
||||
- if (offs + size <= len)
|
||||
+ if (offs < len && size < len && offs + size <= len) {
|
||||
qemu_send_packet(s->vc, s->out_buf + offs, size);
|
||||
+ }
|
||||
}
|
||||
s->out_ptr -= len;
|
||||
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
||||
--
|
||||
2.5.0
|
||||
34
qemu.trad.CVE-2016-2841.patch
Normal file
34
qemu.trad.CVE-2016-2841.patch
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152)
|
||||
bytes to process network packets. Registers PSTART & PSTOP
|
||||
define ring buffer size & location. Setting these registers
|
||||
to invalid values could lead to infinite loop or OOB r/w
|
||||
access issues. Add check to avoid it.
|
||||
|
||||
Reported-by: Yang Hongke <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/net/ne2000.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
Update per review:
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg05522.html
|
||||
|
||||
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
|
||||
index b032212..ced4666 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/ne2000.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/ne2000.c
|
||||
@@ -154,6 +154,10 @@ static int ne2000_buffer_full(NE2000State *s)
|
||||
{
|
||||
int avail, index, boundary;
|
||||
|
||||
+ if (s->stop <= s->start) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
index = s->curpag << 8;
|
||||
boundary = s->boundary << 8;
|
||||
if (index < boundary)
|
||||
--
|
||||
2.5.0
|
||||
45
qemu.trad.CVE-2016-2857.patch
Normal file
45
qemu.trad.CVE-2016-2857.patch
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
While computing IP checksum, 'net_checksum_calculate' reads
|
||||
payload length from the packet. It could exceed the given 'data'
|
||||
buffer size. Add a check to avoid it.
|
||||
|
||||
Reported-by: Liu Ling <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
net/checksum.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
Update as per review:
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg06121.html
|
||||
|
||||
diff --git a/net/checksum.c b/net/checksum.c
|
||||
index 14c0855..0942437 100644
|
||||
--- a/tools/qemu-xen-traditional/net-checksum.c
|
||||
+++ b/tools/qemu-xen-traditional/net-checksum.c
|
||||
@@ -59,6 +59,11 @@ void net_checksum_calculate(uint8_t *data, int length)
|
||||
int hlen, plen, proto, csum_offset;
|
||||
uint16_t csum;
|
||||
|
||||
+ /* Ensure data has complete L2 & L3 headers. */
|
||||
+ if (length < 14 + 20) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if ((data[14] & 0xf0) != 0x40)
|
||||
return; /* not IPv4 */
|
||||
hlen = (data[14] & 0x0f) * 4;
|
||||
@@ -76,8 +81,9 @@ void net_checksum_calculate(uint8_t *data, int length)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (plen < csum_offset+2)
|
||||
- return;
|
||||
+ if (plen < csum_offset + 2 || 14 + hlen + plen > length) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
data[14+hlen+csum_offset] = 0;
|
||||
data[14+hlen+csum_offset+1] = 0;
|
||||
--
|
||||
2.5.0
|
||||
46
qemu.trad.CVE-2016-4001.patch
Normal file
46
qemu.trad.CVE-2016-4001.patch
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
From 3a15cc0e1ee7168db0782133d2607a6bfa422d66 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Fri, 8 Apr 2016 11:33:48 +0530
|
||||
Subject: [PATCH] net: stellaris_enet: check packet length against receive buffer
|
||||
|
||||
When receiving packets over Stellaris ethernet controller, it
|
||||
uses receive buffer of size 2048 bytes. In case the controller
|
||||
accepts large(MTU) packets, it could lead to memory corruption.
|
||||
Add check to avoid it.
|
||||
|
||||
Reported-by: Oleksandr Bazhaniuk <oleksandr.bazhaniuk@intel.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-id: 1460095428-22698-1-git-send-email-ppandit@redhat.com
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/stellaris_enet.c | 12 +++++++++++-
|
||||
1 files changed, 11 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/stellaris_enet.c b/tools/qemu-xen-traditional/hw/stellaris_enet.c
|
||||
index 84cf60b..6880894 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/stellaris_enet.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/stellaris_enet.c
|
||||
@@ -236,8 +236,18 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
|
||||
n = s->next_packet + s->np;
|
||||
if (n >= 31)
|
||||
n -= 31;
|
||||
- s->np++;
|
||||
|
||||
+ if (size >= sizeof(s->rx[n].data) - 6) {
|
||||
+ /* If the packet won't fit into the
|
||||
+ * emulated 2K RAM, this is reported
|
||||
+ * as a FIFO overrun error.
|
||||
+ */
|
||||
+ s->ris |= SE_INT_FOV;
|
||||
+ stellaris_enet_update(s);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ s->np++;
|
||||
s->rx[n].len = size + 6;
|
||||
p = s->rx[n].data;
|
||||
*(p++) = (size + 6);
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
31
qemu.trad.CVE-2016-4002.patch
Normal file
31
qemu.trad.CVE-2016-4002.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
When receiving packets over MIPSnet network device, it uses
|
||||
receive buffer of size 1514 bytes. In case the controller
|
||||
accepts large(MTU) packets, it could lead to memory corruption.
|
||||
Add check to avoid it.
|
||||
|
||||
Reported by: Oleksandr Bazhaniuk <address@hidden>
|
||||
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/mipsnet.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/mipsnet.c b/tools/qemu-xen-traditional/hw/mipsnet.c
|
||||
index f261011..e134b31 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/mipsnet.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/mipsnet.c
|
||||
@@ -82,6 +82,9 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
if (!mipsnet_can_receive(opaque))
|
||||
return;
|
||||
|
||||
+ if (size >= sizeof(s->rx_buffer)) {
|
||||
+ return;
|
||||
+ }
|
||||
s->busy = 1;
|
||||
|
||||
/* Just accept everything. */
|
||||
--
|
||||
2.5.5
|
||||
|
||||
44
qemu.trad.CVE-2016-4439.patch
Normal file
44
qemu.trad.CVE-2016-4439.patch
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: P J P
|
||||
*Subject*: [Qemu-devel] [PATCH 1/2] scsi: check command buffer length
|
||||
before write(CVE-2016-4439)
|
||||
*Date*: Thu, 19 May 2016 16:09:30 +0530
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte
|
||||
FIFO buffer. It is used to handle command and data transfer. While
|
||||
writing to this command buffer 's->cmdbuf[TI_BUFSZ=16]', a check
|
||||
was missing to validate input length. Add check to avoid OOB write
|
||||
access.
|
||||
|
||||
Fixes CVE-2016-4439
|
||||
Reported-by: Li Qiang <address@hidden>
|
||||
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/scsi/esp.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index 8961be2..01497e6 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -448,7 +448,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
|
||||
break;
|
||||
case ESP_FIFO:
|
||||
if (s->do_cmd) {
|
||||
- s->cmdbuf[s->cmdlen++] = val & 0xff;
|
||||
+ if (s->cmdlen < TI_BUFSZ) {
|
||||
+ s->cmdbuf[s->cmdlen++] = val & 0xff;
|
||||
+ } else {
|
||||
+ ESP_ERROR("fifo overrun\n");
|
||||
+ }
|
||||
} else if (s->ti_size == TI_BUFSZ - 1) {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
} else {
|
||||
--
|
||||
2.5.5
|
||||
|
||||
68
qemu.trad.CVE-2016-4441.patch
Normal file
68
qemu.trad.CVE-2016-4441.patch
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: P J P
|
||||
*Subject*: [Qemu-devel] [PATCH 2/2] scsi: check dma length before
|
||||
reading scsi command(CVE-2016-4441)
|
||||
*Date*: Thu, 19 May 2016 16:09:31 +0530
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte
|
||||
FIFO buffer. It is used to handle command and data transfer.
|
||||
Routine get_cmd() uses DMA to read scsi commands into this buffer.
|
||||
Add check to validate DMA length against buffer size to avoid any
|
||||
overrun.
|
||||
|
||||
Fixes CVE-2016-4441
|
||||
Reported-by: Li Qiang <address@hidden>
|
||||
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/scsi/esp.c | 11 +++++++----
|
||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index 01497e6..591c817 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -82,7 +82,7 @@ void esp_request_cancelled(SCSIRequest *req)
|
||||
}
|
||||
}
|
||||
|
||||
-static uint32_t get_cmd(ESPState *s, uint8_t *buf)
|
||||
+static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
|
||||
{
|
||||
uint32_t dmalen;
|
||||
int target;
|
||||
@@ -92,6 +92,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
|
||||
target = s->wregs[ESP_WBUSID] & BUSID_DID;
|
||||
if (s->dma) {
|
||||
dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
|
||||
+ if (dmalen > buflen) {
|
||||
+ return 0;
|
||||
+ }
|
||||
s->dma_memory_read(s->dma_opaque, buf, dmalen);
|
||||
} else {
|
||||
dmalen = s->ti_size;
|
||||
@@ -166,7 +169,7 @@ static void handle_satn(ESPState *s)
|
||||
uint8_t buf[32];
|
||||
int len;
|
||||
|
||||
- len = get_cmd(s, buf);
|
||||
+ len = get_cmd(s, buf, sizeof(buf));
|
||||
if (len)
|
||||
do_cmd(s, buf);
|
||||
}
|
||||
@@ -192,7 +195,7 @@ static void handle_satn_stop(ESPState *s)
|
||||
|
||||
static void handle_satn_stop(ESPState *s)
|
||||
{
|
||||
- s->cmdlen = get_cmd(s, s->cmdbuf);
|
||||
+ s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
|
||||
if (s->cmdlen) {
|
||||
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
|
||||
s->do_cmd = 1;
|
||||
--
|
||||
2.5.5
|
||||
|
||||
65
qemu.trad.CVE-2016-5238.patch
Normal file
65
qemu.trad.CVE-2016-5238.patch
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: Paolo Bonzini
|
||||
*Subject*: Re: [Qemu-devel] [PATCH] scsi: check buffer length before
|
||||
reading scsi command
|
||||
*Date*: Wed, 1 Jun 2016 15:10:16 +0200
|
||||
*User-agent*: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
|
||||
Thunderbird/45.1.0
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
On 31/05/2016 19:53, P J P wrote:
|
||||
>/ From: Prasad J Pandit <address@hidden>/
|
||||
>/ /
|
||||
>/ The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte/
|
||||
>/ FIFO buffer. It is used to handle command and data transfer./
|
||||
>/ Routine get_cmd() in non-DMA mode, uses 'ti_size' to read scsi/
|
||||
>/ command into a buffer. Add check to validate command length against/
|
||||
>/ buffer size to avoid any overrun./
|
||||
>/ /
|
||||
>/ Reported-by: Li Qiang <address@hidden>/
|
||||
>/ Signed-off-by: Prasad J Pandit <address@hidden>/
|
||||
>/ ---/
|
||||
>/ hw/scsi/esp.c | 3 +++/
|
||||
>/ 1 file changed, 3 insertions(+)/
|
||||
>/ /
|
||||
>/ diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c/
|
||||
>/ index 60c1b28..953027a 100644/
|
||||
>/ --- a/tools/qemu-xen-traditional/hw/esp.c/
|
||||
>/ +++ b/tools/qemu-xen-traditional/hw/esp.c/
|
||||
>/ @@ -98,6 +98,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t /
|
||||
>/ buflen)/
|
||||
>/ s->dma_memory_read(s->dma_opaque, buf, dmalen);/
|
||||
>/ } else {/
|
||||
>/ dmalen = s->ti_size;/
|
||||
>/ + if (dmalen > TI_BUFSZ) {/
|
||||
>/ + return 0;/
|
||||
>/ + }/
|
||||
>/ memcpy(buf, s->ti_buf, dmalen);/
|
||||
>/ buf[0] = buf[2] >> 5;/
|
||||
>/ }/
|
||||
>/ /
|
||||
|
||||
In theory this shouldn't happen, but I agree that it is better to be
|
||||
defensive. I'm queuing this patch.
|
||||
|
||||
At least the following patch is needed to ensure that ti_size always
|
||||
matches ti_rptr/ti_wptr (Hervé, what do you think about it? should I
|
||||
resubmit it formally?). Also, things are more complicated than
|
||||
necessary due to ti_size being used for both DMA and FIFO transfers.
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index c2f6f8f..6407844 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -222,7 +222,7 @@ static void write_response(ESPState *s)
|
||||
} else {
|
||||
s->ti_size = 2;
|
||||
s->ti_rptr = 0;
|
||||
- s->ti_wptr = 0;
|
||||
+ s->ti_wptr = 2;
|
||||
s->rregs[ESP_RFLAGS] = 2;
|
||||
}
|
||||
esp_raise_irq(s);
|
||||
|
||||
76
qemu.trad.CVE-2016-5338.patch
Normal file
76
qemu.trad.CVE-2016-5338.patch
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: P J P
|
||||
*Subject*: [Qemu-devel] [PATCH v3] scsi: esp: check TI buffer index
|
||||
before read/write
|
||||
*Date*: Mon, 6 Jun 2016 22:04:43 +0530
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
The 53C9X Fast SCSI Controller(FSC) comes with internal 16-byte
|
||||
FIFO buffers. One is used to handle commands and other is for
|
||||
information transfer. Three control variables 'ti_rptr',
|
||||
'ti_wptr' and 'ti_size' are used to control r/w access to the
|
||||
information transfer buffer ti_buf[TI_BUFSZ=16]. In that,
|
||||
|
||||
'ti_rptr' is used as read index, where read occurs.
|
||||
'ti_wptr' is a write index, where write would occur.
|
||||
'ti_size' indicates total bytes to be read from the buffer.
|
||||
|
||||
While reading/writing to this buffer, index could exceed its
|
||||
size. Add check to avoid OOB r/w access.
|
||||
|
||||
Reported-by: Huawei PSIRT <address@hidden>
|
||||
Reported-by: Li Qiang <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/scsi/esp.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
Update as per:
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-06/msg01326.html
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index c2f6f8f..4b94bbc 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -403,18 +403,17 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
|
||||
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
|
||||
switch (saddr) {
|
||||
case ESP_FIFO:
|
||||
- if (s->ti_size > 0) {
|
||||
+ if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
|
||||
+ /* Data out. */
|
||||
+ ESP_ERROR("PIO data read not implemented\n");
|
||||
+ s->rregs[ESP_FIFO] = 0;
|
||||
+ esp_raise_irq(s);
|
||||
+ } else if (s->ti_rptr < s->ti_wptr) {
|
||||
s->ti_size--;
|
||||
- if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
|
||||
- /* Data out. */
|
||||
- ESP_ERROR("PIO data read not implemented\n");
|
||||
- s->rregs[ESP_FIFO] = 0;
|
||||
- } else {
|
||||
- s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
|
||||
- }
|
||||
+ s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
|
||||
esp_raise_irq(s);
|
||||
}
|
||||
- if (s->ti_size == 0) {
|
||||
+ if (s->ti_rptr == s->ti_wptr) {
|
||||
s->ti_rptr = 0;
|
||||
s->ti_wptr = 0;
|
||||
}
|
||||
@@ -459,7 +457,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
|
||||
} else {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
}
|
||||
- } else if (s->ti_size == TI_BUFSZ - 1) {
|
||||
+ } else if (s->ti_wptr == TI_BUFSZ - 1) {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
} else {
|
||||
s->ti_size++;
|
||||
--
|
||||
2.5.5
|
||||
|
||||
81
qemu.trad.CVE-2016-6351.patch
Normal file
81
qemu.trad.CVE-2016-6351.patch
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
From 926cde5f3e4d2504ed161ed0cb771ac7cad6fd11 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 16 Jun 2016 00:22:35 +0200
|
||||
Subject: [PATCH] scsi: esp: make cmdbuf big enough for maximum CDB size
|
||||
|
||||
While doing DMA read into ESP command buffer 's->cmdbuf', it could
|
||||
write past the 's->cmdbuf' area, if it was transferring more than 16
|
||||
bytes. Increase the command buffer size to 32, which is maximum when
|
||||
's->do_cmd' is set, and add a check on 'len' to avoid OOB access.
|
||||
|
||||
Reported-by: Li Qiang <liqiang6-s@360.cn>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
hw/esp.c | 6 ++++--
|
||||
hw/esp.c | 3 ++-
|
||||
2 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/esp.c b/hw/esp.c
|
||||
index 64680b3..baa0a2c 100644
|
||||
--- a/hw/esp.c
|
||||
+++ b/hw/esp.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "hw.h"
|
||||
#include "scsi-disk.h"
|
||||
#include "scsi.h"
|
||||
+#include <assert.h>
|
||||
|
||||
/* debug ESP card */
|
||||
//#define DEBUG_ESP
|
||||
@@ -248,6 +248,8 @@ static void esp_do_dma(ESPState *s)
|
||||
len = s->dma_left;
|
||||
if (s->do_cmd) {
|
||||
DPRINTF("command len %d + %d\n", s->cmdlen, len);
|
||||
+ assert (s->cmdlen <= sizeof(s->cmdbuf) &&
|
||||
+ len <= sizeof(s->cmdbuf) - s->cmdlen);
|
||||
s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
|
||||
s->ti_size = 0;
|
||||
s->cmdlen = 0;
|
||||
@@ -345,7 +347,7 @@ static void handle_ti(ESPState *s)
|
||||
s->dma_counter = dmalen;
|
||||
|
||||
if (s->do_cmd)
|
||||
- minlen = (dmalen < 32) ? dmalen : 32;
|
||||
+ minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
|
||||
else if (s->ti_size < 0)
|
||||
minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
|
||||
else
|
||||
@@ -449,7 +451,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
|
||||
break;
|
||||
case ESP_FIFO:
|
||||
if (s->do_cmd) {
|
||||
- if (s->cmdlen < TI_BUFSZ) {
|
||||
+ if (s->cmdlen < ESP_CMDBUF_SZ) {
|
||||
s->cmdbuf[s->cmdlen++] = val & 0xff;
|
||||
} else {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
diff --git a/hw/esp.c b/hw/esp.c
|
||||
index 6c79527..d2c4886 100644
|
||||
--- a/hw/esp.c
|
||||
+++ b/hw/esp.c
|
||||
@@ -14,6 +14,7 @@ void esp_init(hwaddr espaddr, int it_shift,
|
||||
|
||||
#define ESP_REGS 16
|
||||
#define TI_BUFSZ 16
|
||||
+#define ESP_CMDBUF_SZ 32
|
||||
|
||||
typedef struct ESPState ESPState;
|
||||
|
||||
@@ -31,7 +32,7 @@ struct ESPState {
|
||||
uint32_t dma;
|
||||
SCSIDevice *scsi_dev[ESP_MAX_DEVS];
|
||||
SCSIDevice *current_dev;
|
||||
- uint8_t cmdbuf[TI_BUFSZ];
|
||||
+ uint8_t cmdbuf[ESP_CMDBUF_SZ];
|
||||
uint32_t cmdlen;
|
||||
uint32_t do_cmd;
|
||||
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
37
qemu.trad.CVE-2016-8669.patch
Normal file
37
qemu.trad.CVE-2016-8669.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
From 3592fe0c919cf27a81d8e9f9b4f269553418bb01 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Wed, 12 Oct 2016 11:28:08 +0530
|
||||
Subject: [PATCH] char: serial: check divider value against baud base
|
||||
|
||||
16550A UART device uses an oscillator to generate frequencies
|
||||
(baud base), which decide communication speed. This speed could
|
||||
be changed by dividing it by a divider. If the divider is
|
||||
greater than the baud base, speed is set to zero, leading to a
|
||||
divide by zero error. Add check to avoid it.
|
||||
|
||||
Reported-by: Huawei PSIRT <psirt@huawei.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-Id: <1476251888-20238-1-git-send-email-ppandit@redhat.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
hw/char/serial.c | 3 ++-
|
||||
1 files changed, 2 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/serial.c b/hw/serial.c
|
||||
index 3442f47..eec72b7 100644
|
||||
--- a/hw/serial.c
|
||||
+++ b/hw/serial.c
|
||||
@@ -153,8 +153,9 @@ static void serial_update_parameters(SerialState *s)
|
||||
int speed, parity, data_bits, stop_bits, frame_size;
|
||||
QEMUSerialSetParams ssp;
|
||||
|
||||
- if (s->divider == 0)
|
||||
+ if (s->divider == 0 || s->divider > s->baudbase) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
frame_size = 1;
|
||||
if (s->lcr & 0x08) {
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
29
qemu.trad.CVE-2016-8910.patch
Normal file
29
qemu.trad.CVE-2016-8910.patch
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
RTL8139 ethernet controller in C+ mode supports multiple
|
||||
descriptor rings, each with maximum of 64 descriptors. While
|
||||
processing transmit descriptor ring in 'rtl8139_cplus_transmit',
|
||||
it does not limit the descriptor count and runs forever. Add
|
||||
check to avoid it.
|
||||
|
||||
Reported-by: Andrew Henderson <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/net/rtl8139.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
|
||||
index 3345bc6..f05e59c 100644
|
||||
--- a/hw/rtl8139.c
|
||||
+++ b/hw/rtl8139.c
|
||||
@@ -2350,7 +2350,7 @@ static void rtl8139_cplus_transmit(RTL8139State *s)
|
||||
{
|
||||
int txcount = 0;
|
||||
|
||||
- while (rtl8139_cplus_transmit_one(s))
|
||||
+ while (txcount < 64 && rtl8139_cplus_transmit_one(s))
|
||||
{
|
||||
++txcount;
|
||||
}
|
||||
--
|
||||
2.7.4
|
||||
34
qemu.trad.CVE-2016-9776.patch
Normal file
34
qemu.trad.CVE-2016-9776.patch
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
From 77d54985b85a0cb760330ec2bd92505e0a2a97a9 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Tue, 29 Nov 2016 00:38:39 +0530
|
||||
Subject: [PATCH] net: mcf: check receive buffer size register value
|
||||
|
||||
ColdFire Fast Ethernet Controller uses a receive buffer size
|
||||
register(EMRBR) to hold maximum size of all receive buffers.
|
||||
It is set by a user before any operation. If it was set to be
|
||||
zero, ColdFire emulator would go into an infinite loop while
|
||||
receiving data in mcf_fec_receive. Add check to avoid it.
|
||||
|
||||
Reported-by: Wjjzhang <wjjzhang@tencent.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
---
|
||||
hw/net/mcf_fec.c | 2 +-
|
||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
|
||||
index dc61bac..4025eb3 100644
|
||||
--- a/hw/mcf_fec.c
|
||||
+++ b/hw/mcf_fec.c
|
||||
@@ -393,7 +393,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
||||
s->tx_descriptor = s->etdsr;
|
||||
break;
|
||||
case 0x188:
|
||||
- s->emrbr = value & 0x7f0;
|
||||
+ s->emrbr = value > 0 ? value & 0x7F0 : 0x7F0;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n",
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
51
qemu.trad.CVE-2017-6505.patch
Normal file
51
qemu.trad.CVE-2017-6505.patch
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
From 95ed56939eb2eaa4e2f349fe6dcd13ca4edfd8fb Mon Sep 17 00:00:00 2001
|
||||
From: Li Qiang <liqiang6-s@360.cn>
|
||||
Date: Tue, 7 Feb 2017 02:23:33 -0800
|
||||
Subject: [PATCH] usb: ohci: limit the number of link eds
|
||||
|
||||
The guest may builds an infinite loop with link eds. This patch
|
||||
limit the number of linked ed to avoid this.
|
||||
|
||||
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
|
||||
Message-id: 5899a02e.45ca240a.6c373.93c1@mx.google.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb-ohci.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
|
||||
index 2cba3e3..21c93e0 100644
|
||||
--- a/hw/usb-ohci.c
|
||||
+++ b/hw/usb-ohci.c
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#define OHCI_MAX_PORTS 15
|
||||
|
||||
+#define ED_LINK_LIMIT 4
|
||||
+
|
||||
static int64_t usb_frame_time;
|
||||
static int64_t usb_bit_time;
|
||||
|
||||
@@ -1184,7 +1186,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
||||
uint32_t next_ed;
|
||||
uint32_t cur;
|
||||
int active;
|
||||
-
|
||||
+ uint32_t link_cnt = 0;
|
||||
active = 0;
|
||||
|
||||
if (head == 0)
|
||||
@@ -1199,6 +1201,10 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
||||
|
||||
next_ed = ed.next & OHCI_DPTR_MASK;
|
||||
|
||||
+ if (++link_cnt > ED_LINK_LIMIT) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
|
||||
uint32_t addr;
|
||||
/* Cancel pending packets for ED that have been paused. */
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
51
qemu.trad.CVE-2017-7718.patch
Normal file
51
qemu.trad.CVE-2017-7718.patch
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
From 215902d7b6fb50c6fc216fc74f770858278ed904 Mon Sep 17 00:00:00 2001
|
||||
From: hangaohuai <hangaohuai@huawei.com>
|
||||
Date: Tue, 14 Mar 2017 14:39:19 +0800
|
||||
Subject: [PATCH] fix :cirrus_vga fix OOB read case qemu Segmentation fault
|
||||
|
||||
check the validity of parameters in cirrus_bitblt_rop_fwd_transp_xxx
|
||||
and cirrus_bitblt_rop_fwd_xxx to avoid the OOB read which causes qemu Segmentation fault.
|
||||
|
||||
After the fix, we will touch the assert in
|
||||
cirrus_invalidate_region:
|
||||
assert(off_cur_end >= off_cur);
|
||||
|
||||
Signed-off-by: fangying <fangying1@huawei.com>
|
||||
Signed-off-by: hangaohuai <hangaohuai@huawei.com>
|
||||
Message-id: 20170314063919.16200-1-hangaohuai@huawei.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/cirrus_vga_rop.h | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
|
||||
index 0925a00..b7447f8 100644
|
||||
--- a/hw/cirrus_vga_rop.h
|
||||
+++ b/hw/cirrus_vga_rop.h
|
||||
@@ -97,6 +97,11 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||
src = src_ - src_base;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
+
|
||||
+ if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
p = *(dst_base + m(dst));
|
||||
@@ -143,6 +148,11 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||
src = src_ - src_base;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
+
|
||||
+ if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x+=2) {
|
||||
p1 = *(dst_base + m(dst));
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
38
qemu.trad.CVE-2017-8309.patch
Normal file
38
qemu.trad.CVE-2017-8309.patch
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
From 3268a845f41253fb55852a8429c32b50f36f349a Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 28 Apr 2017 09:56:12 +0200
|
||||
Subject: [PATCH] audio: release capture buffers
|
||||
|
||||
AUD_add_capture() allocates two buffers which are never released.
|
||||
Add the missing calls to AUD_del_capture().
|
||||
|
||||
Impact: Allows vnc clients to exhaust host memory by repeatedly
|
||||
starting and stopping audio capture.
|
||||
|
||||
Fixes: CVE-2017-8309
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Cc: Huawei PSIRT <PSIRT@huawei.com>
|
||||
Reported-by: "Jiangxin (hunter, SCC)" <jiangxin1@huawei.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Reviewed-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-id: 20170428075612.9997-1-kraxel@redhat.com
|
||||
---
|
||||
audio/audio.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/audio/audio.c b/audio/audio.c
|
||||
index c8898d8..beafed2 100644
|
||||
--- a/audio/audio.c
|
||||
+++ b/audio/audio.c
|
||||
@@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
||||
sw = sw1;
|
||||
}
|
||||
LIST_REMOVE (cap, entries);
|
||||
+ qemu_free (cap->hw.mix_buf);
|
||||
+ qemu_free (cap->buf);
|
||||
qemu_free (cap);
|
||||
}
|
||||
return;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
31
qemu.trad.CVE-2017-9330.patch
Normal file
31
qemu.trad.CVE-2017-9330.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
From 26f670a244982335cc08943fb1ec099a2c81e42d Mon Sep 17 00:00:00 2001
|
||||
From: Li Qiang <liqiang6-s@360.cn>
|
||||
Date: Tue, 7 Feb 2017 03:15:03 -0800
|
||||
Subject: [PATCH] usb: ohci: fix error return code in servicing iso td
|
||||
|
||||
It should return 1 if an error occurs when reading iso td.
|
||||
This will avoid an infinite loop issue in ohci_service_ed_list.
|
||||
|
||||
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
|
||||
Message-id: 5899ac3e.1033240a.944d5.9a2d@mx.google.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb-ohci.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
|
||||
index c82a92f..2cba3e3 100644
|
||||
--- a/hw/usb-ohci.c
|
||||
+++ b/hw/usb-ohci.c
|
||||
@@ -725,7 +725,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
||||
|
||||
if (!ohci_read_iso_td(addr, &iso_td)) {
|
||||
printf("usb-ohci: ISO_TD read error at %x\n", addr);
|
||||
- return 0;
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
starting_frame = OHCI_BM(iso_td.flags, TD_SF);
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
76
qemu.trad.bug1399055.patch
Normal file
76
qemu.trad.bug1399055.patch
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
From 4299b90e9ba9ce5ca9024572804ba751aa1a7e70 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Tue, 18 Oct 2016 13:15:17 +0530
|
||||
Subject: [PATCH] display: cirrus: check vga bits per pixel(bpp) value
|
||||
|
||||
In Cirrus CLGD 54xx VGA Emulator, if cirrus graphics mode is VGA,
|
||||
'cirrus_get_bpp' returns zero(0), which could lead to a divide
|
||||
by zero error in while copying pixel data. The same could occur
|
||||
via blit pitch values. Add check to avoid it.
|
||||
|
||||
Reported-by: Huawei PSIRT <psirt@huawei.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-id: 1476776717-24807-1-git-send-email-ppandit@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/cirrus_vga.c | 14 ++++++++++----
|
||||
1 files changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
|
||||
index 3d712d5..bdb092e 100644
|
||||
--- a/hw/cirrus_vga.c
|
||||
+++ b/hw/cirrus_vga.c
|
||||
@@ -272,6 +272,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
|
||||
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
int32_t pitch, int32_t addr)
|
||||
{
|
||||
+ if (!pitch) {
|
||||
+ return true;
|
||||
+ }
|
||||
if (pitch < 0) {
|
||||
int64_t min = addr
|
||||
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||
@@ -715,7 +718,7 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||
s->cirrus_addr_mask));
|
||||
}
|
||||
|
||||
-static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
+static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
{
|
||||
int sx = 0, sy = 0;
|
||||
int dx = 0, dy = 0;
|
||||
@@ -729,6 +732,9 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
int width, height;
|
||||
|
||||
depth = s->get_bpp((VGAState *)s) / 8;
|
||||
+ if (!depth) {
|
||||
+ return 0;
|
||||
+ }
|
||||
s->get_resolution((VGAState *)s, &width, &height);
|
||||
|
||||
/* extra x, y */
|
||||
@@ -783,6 +789,8 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||
s->cirrus_blt_dstpitch, s->cirrus_blt_width,
|
||||
s->cirrus_blt_height);
|
||||
+
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
@@ -790,11 +798,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
if (blit_is_unsafe(s))
|
||||
return 0;
|
||||
|
||||
- cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
|
||||
+ return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
|
||||
s->cirrus_blt_srcaddr - s->start_addr,
|
||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||
-
|
||||
- return 1;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
3
sources
3
sources
|
|
@ -4,5 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77
|
|||
SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e
|
||||
SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad
|
||||
SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5
|
||||
SHA512 (mini-os-4.21.0.tar.xz) = 7543774d15da84476d93d04154990923c82209cb3fa125574c0383652c5a310957200f54b63b34502161f9c3afce4907e0060d9036f3eaf3a7cb6b1b3119b546
|
||||
SHA512 (xen-4.21.1.tar.xz) = 8dfe65255e202b3dacf9d0d7265636bc1f97627c11b08babc13a5b8e74c7c65e7e2c6a1513e28b3c713fe512edb6702a73b2bf667e2a8f2ce825b196a2cd5aab
|
||||
SHA512 (xen-4.12.3.tar.gz) = 7bbf4e752477f18143ac9a62fb633b1fbe115a1a9b03d0132f33dfca025bc9b76d9c2e9b66a3e407d14aff161b940b1a82e3e3ca43213798e9dd38b6970194e0
|
||||
|
|
|
|||
27
xen-net-disable-iptables-on-bridge.patch
Normal file
27
xen-net-disable-iptables-on-bridge.patch
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
--- xen-4.1.0-orig/tools/hotplug/Linux/vif-bridge 2008-08-22 10:49:07.000000000 +0100
|
||||
+++ xen-4.1.0-new/tools/hotplug/Linux/vif-bridge 2008-08-29 11:29:38.000000000 +0100
|
||||
@@ -96,8 +96,6 @@ case "$command" in
|
||||
;;
|
||||
esac
|
||||
|
||||
-handle_iptable
|
||||
-
|
||||
call_hooks vif post
|
||||
|
||||
log debug "Successful vif-bridge $command for $dev, bridge $bridge."
|
||||
--- xen-3.3.0-orig/tools/hotplug/Linux/xen-network-common.sh 2008-08-22 10:49:07.000000000 +0100
|
||||
+++ xen-3.3.0-new/tools/hotplug/Linux/xen-network-common.sh 2008-08-29 11:29:38.000000000 +0100
|
||||
@@ -99,6 +99,13 @@ create_bridge () {
|
||||
brctl addbr ${bridge}
|
||||
brctl stp ${bridge} off
|
||||
brctl setfd ${bridge} 0
|
||||
+ # Setting these to zero stops guest<->LAN traffic
|
||||
+ # traversing the bridge from hitting the *tables
|
||||
+ # rulesets. guest<->host traffic still gets processed
|
||||
+ # by the host's iptables rules so this isn't a hole
|
||||
+ sysctl -q -w "net.bridge.bridge-nf-call-arptables=0"
|
||||
+ sysctl -q -w "net.bridge.bridge-nf-call-ip6tables=0"
|
||||
+ sysctl -q -w "net.bridge.bridge-nf-call-iptables=0"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -1,54 +1,56 @@
|
|||
--- xen-4.18.0-rc1/tools/xenstored/watch.c.orig 2023-09-29 09:09:29.000000000 +0100
|
||||
+++ xen-4.18.0-rc1/tools/xenstored/watch.c 2023-10-02 16:12:14.971264769 +0100
|
||||
@@ -164,7 +164,7 @@
|
||||
const char **path, bool *relative)
|
||||
{
|
||||
*relative = !strstarts(*path, "/") && !strstarts(*path, "@");
|
||||
- *path = canonicalize(conn, ctx, *path, true);
|
||||
+ *path = xenstore_canonicalize(conn, ctx, *path, true);
|
||||
|
||||
return *path ? 0 : errno;
|
||||
}
|
||||
@@ -250,7 +250,7 @@
|
||||
--- xen-4.9.0-rc1.2/tools/xenstore/xenstored_watch.c.orig 2017-04-12 16:18:57.000000000 +0100
|
||||
+++ xen-4.9.0-rc1.2/tools/xenstore/xenstored_watch.c 2017-04-13 21:17:12.255231094 +0100
|
||||
@@ -166,7 +166,7 @@
|
||||
/* check if valid event */
|
||||
} else {
|
||||
relative = !strstarts(vec[0], "/");
|
||||
- vec[0] = canonicalize(conn, in, vec[0]);
|
||||
+ vec[0] = xenstore_canonicalize(conn, in, vec[0]);
|
||||
if (!vec[0])
|
||||
return ENOMEM;
|
||||
if (!is_valid_nodename(vec[0]))
|
||||
@@ -219,7 +219,7 @@
|
||||
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
|
||||
return EINVAL;
|
||||
|
||||
- node = canonicalize(conn, ctx, vec[0], true);
|
||||
+ node = xenstore_canonicalize(conn, ctx, vec[0], true);
|
||||
- node = canonicalize(conn, in, vec[0]);
|
||||
+ node = xenstore_canonicalize(conn, in, vec[0]);
|
||||
if (!node)
|
||||
return errno;
|
||||
return ENOMEM;
|
||||
list_for_each_entry(watch, &conn->watches, list) {
|
||||
--- xen-4.18.0-rc1/tools/xenstored/core.c.orig 2023-09-29 09:09:29.000000000 +0100
|
||||
+++ xen-4.18.0-rc1/tools/xenstored/core.c 2023-10-02 16:12:14.993264626 +0100
|
||||
@@ -1249,7 +1249,7 @@
|
||||
--- xen-4.9.0-rc1.2/tools/xenstore/xenstored_core.c.orig 2017-04-12 16:18:57.000000000 +0100
|
||||
+++ xen-4.9.0-rc1.2/tools/xenstore/xenstored_core.c 2017-04-13 21:19:35.668429881 +0100
|
||||
@@ -777,7 +777,7 @@
|
||||
return strings;
|
||||
}
|
||||
|
||||
-const char *canonicalize(struct connection *conn, const void *ctx,
|
||||
+const char *xenstore_canonicalize(struct connection *conn, const void *ctx,
|
||||
const char *node, bool allow_special)
|
||||
-char *canonicalize(struct connection *conn, const void *ctx, const char *node)
|
||||
+char *xenstore_canonicalize(struct connection *conn, const void *ctx, const char *node)
|
||||
{
|
||||
const char *name;
|
||||
@@ -1303,7 +1303,7 @@
|
||||
{
|
||||
struct node *node;
|
||||
const char *prefix;
|
||||
|
||||
- *canonical_name = canonicalize(conn, ctx, name, allow_special);
|
||||
+ *canonical_name = xenstore_canonicalize(conn, ctx, name, allow_special);
|
||||
if (!*canonical_name)
|
||||
return NULL;
|
||||
@@ -799,7 +799,7 @@
|
||||
|
||||
@@ -1320,7 +1320,7 @@
|
||||
const char *tmp_name;
|
||||
const struct node *node;
|
||||
if (!canonical_name)
|
||||
canonical_name = &tmp_name;
|
||||
- *canonical_name = canonicalize(conn, ctx, name);
|
||||
+ *canonical_name = xenstore_canonicalize(conn, ctx, name);
|
||||
return get_node(conn, ctx, *canonical_name, perm);
|
||||
}
|
||||
|
||||
- tmp_name = canonicalize(conn, ctx, name, allow_special);
|
||||
+ tmp_name = xenstore_canonicalize(conn, ctx, name, allow_special);
|
||||
if (!tmp_name)
|
||||
return NULL;
|
||||
--- xen-4.9.0-rc1.2/tools/xenstore/xenstored_core.h.orig 2017-04-12 16:18:57.000000000 +0100
|
||||
+++ xen-4.9.0-rc1.2/tools/xenstore/xenstored_core.h 2017-04-13 21:20:29.146368478 +0100
|
||||
@@ -148,7 +148,7 @@
|
||||
void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
|
||||
|
||||
--- xen-4.18.0-rc1/tools/console/testsuite/console-dom0.c.orig 2023-09-29 09:09:29.000000000 +0100
|
||||
+++ xen-4.18.0-rc1/tools/console/testsuite/console-dom0.c 2023-10-02 16:12:15.001264574 +0100
|
||||
/* Canonicalize this path if possible. */
|
||||
-char *canonicalize(struct connection *conn, const void *ctx, const char *node);
|
||||
+char *xenstore_canonicalize(struct connection *conn, const void *ctx, const char *node);
|
||||
|
||||
/* Write a node to the tdb data base. */
|
||||
int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *node);
|
||||
--- xen-4.8.0/tools/console/testsuite/console-dom0.c.orig 2016-12-05 12:03:27.000000000 +0000
|
||||
+++ xen-4.8.0/tools/console/testsuite/console-dom0.c 2017-02-26 21:52:24.554678631 +0000
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
}
|
||||
|
|
@ -85,8 +87,8 @@
|
|||
fprintf(stderr, "%s", line);
|
||||
} while (strcmp(line, "Okay.\n") != 0);
|
||||
|
||||
--- xen-4.18.0-rc1/tools/console/testsuite/console-domU.c.orig 2023-09-29 09:09:29.000000000 +0100
|
||||
+++ xen-4.18.0-rc1/tools/console/testsuite/console-domU.c 2023-10-02 16:12:15.008264528 +0100
|
||||
--- xen-4.8.0/tools/console/testsuite/console-domU.c.orig 2016-12-05 12:03:27.000000000 +0000
|
||||
+++ xen-4.8.0/tools/console/testsuite/console-domU.c 2017-02-26 21:52:50.320622804 +0000
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -105,14 +107,3 @@
|
|||
seed = strtoul(line, 0, 0);
|
||||
|
||||
printf("Seed Okay.\n"); fflush(stdout);
|
||||
--- xen-4.18.0-rc1/tools/xenstored/core.h.orig 2023-09-29 09:09:29.000000000 +0100
|
||||
+++ xen-4.18.0-rc1/tools/xenstored/core.h 2023-10-02 16:12:15.015264482 +0100
|
||||
@@ -240,7 +240,7 @@
|
||||
void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
|
||||
|
||||
/* Canonicalize this path if possible. */
|
||||
-const char *canonicalize(struct connection *conn, const void *ctx,
|
||||
+const char *xenstore_canonicalize(struct connection *conn, const void *ctx,
|
||||
const char *node, bool allow_special);
|
||||
|
||||
/* Get access permissions. */
|
||||
|
|
|
|||
100
xen.drop.brctl.patch
Normal file
100
xen.drop.brctl.patch
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
--- xen-4.11.0-rc7/tools/hotplug/Linux/colo-proxy-setup.orig 2018-06-28 08:39:45.000000000 +0100
|
||||
+++ xen-4.11.0-rc7/tools/hotplug/Linux/colo-proxy-setup 2018-07-03 20:09:26.637017216 +0100
|
||||
@@ -76,10 +76,10 @@
|
||||
|
||||
function setup_secondary()
|
||||
{
|
||||
- do_without_error brctl delif $bridge $vifname
|
||||
- do_without_error brctl addbr $forwardbr
|
||||
- do_without_error brctl addif $forwardbr $vifname
|
||||
- do_without_error brctl addif $forwardbr $forwarddev
|
||||
+ do_without_error ip link set $vifname nomaster
|
||||
+ do_without_error ip link add name $forwardbr type bridge
|
||||
+ do_without_error ip link set $vifname master $forwardbr
|
||||
+ do_without_error ip link set $forwarddev master $forwardbr
|
||||
do_without_error ip link set dev $forwardbr up
|
||||
do_without_error modprobe xt_SECCOLO
|
||||
|
||||
@@ -91,10 +91,10 @@
|
||||
|
||||
function teardown_secondary()
|
||||
{
|
||||
- do_without_error brctl delif $forwardbr $forwarddev
|
||||
- do_without_error brctl delif $forwardbr $vifname
|
||||
- do_without_error brctl delbr $forwardbr
|
||||
- do_without_error brctl addif $bridge $vifname
|
||||
+ do_without_error ip link set $forwarddev nomaster
|
||||
+ do_without_error ip link set $vifname nomaster
|
||||
+ do_without_error ip link delete $forwardbr type bridge
|
||||
+ do_without_error ip link set $vifname master $bridge
|
||||
|
||||
do_without_error iptables -t mangle -D PREROUTING -m physdev --physdev-in \
|
||||
$vifname -j SECCOLO --index $index
|
||||
--- xen-4.11.0-rc7/tools/hotplug/Linux/vif2.orig 2018-06-28 08:39:45.000000000 +0100
|
||||
+++ xen-4.11.0-rc7/tools/hotplug/Linux/vif2 2018-07-03 20:11:07.558757301 +0100
|
||||
@@ -7,13 +7,12 @@
|
||||
bridge=$(xenstore_read_default "$XENBUS_PATH/bridge" "$bridge")
|
||||
if [ -z "$bridge" ]
|
||||
then
|
||||
- nr_bridges=$(($(brctl show | cut -f 1 | grep -v "^$" | wc -l) - 1))
|
||||
+ nr_bridges=$(bridge link | wc -l)
|
||||
if [ "$nr_bridges" != 1 ]
|
||||
then
|
||||
fatal "no bridge specified, and don't know which one to use ($nr_bridges found)"
|
||||
fi
|
||||
- bridge=$(brctl show | cut -d "
|
||||
-" -f 2 | cut -f 1)
|
||||
+ bridge=$(bridge link | cut -d" " -f10)
|
||||
fi
|
||||
|
||||
command="$1"
|
||||
--- xen-4.11.0-rc7/tools/hotplug/Linux/vif-bridge.orig 2018-07-03 19:59:18.499474117 +0100
|
||||
+++ xen-4.11.0-rc7/tools/hotplug/Linux/vif-bridge 2018-07-03 20:12:31.088852864 +0100
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
if [ -z "$bridge" ]
|
||||
then
|
||||
- bridge=$(brctl show | awk 'NR==2{print$1}')
|
||||
+ bridge=$(bridge link | cut -d" " -f10)
|
||||
|
||||
if [ -z "$bridge" ]
|
||||
then
|
||||
@@ -82,7 +82,7 @@
|
||||
;;
|
||||
|
||||
offline)
|
||||
- do_without_error brctl delif "$bridge" "$dev"
|
||||
+ do_without_error ip link set "$dev" nomaster
|
||||
do_without_error ifconfig "$dev" down
|
||||
;;
|
||||
|
||||
--- xen-4.11.0-rc7/tools/hotplug/Linux/xen-network-common.sh.orig 2018-07-03 19:59:18.500474154 +0100
|
||||
+++ xen-4.11.0-rc7/tools/hotplug/Linux/xen-network-common.sh 2018-07-03 20:16:16.466205182 +0100
|
||||
@@ -111,9 +111,7 @@
|
||||
|
||||
# Don't create the bridge if it already exists.
|
||||
if [ ! -e "/sys/class/net/${bridge}/bridge" ]; then
|
||||
- brctl addbr ${bridge}
|
||||
- brctl stp ${bridge} off
|
||||
- brctl setfd ${bridge} 0
|
||||
+ ip link add name ${bridge} type bridge stp_state 0 forward_delay 0
|
||||
# Setting these to zero stops guest<->LAN traffic
|
||||
# traversing the bridge from hitting the *tables
|
||||
# rulesets. guest<->host traffic still gets processed
|
||||
@@ -134,7 +132,7 @@
|
||||
ip link set dev ${dev} up || true
|
||||
return
|
||||
fi
|
||||
- brctl addif ${bridge} ${dev}
|
||||
+ ip link set ${dev} master ${bridge}
|
||||
ip link set dev ${dev} up
|
||||
}
|
||||
|
||||
--- xen-4.11.0-rc7/tools/qemu-xen-traditional/i386-dm/qemu-ifup-Linux.orig 2017-09-15 19:37:27.000000000 +0100
|
||||
+++ xen-4.11.0-rc7/tools/qemu-xen-traditional/i386-dm/qemu-ifup-Linux 2018-07-03 20:17:52.934780235 +0100
|
||||
@@ -34,4 +34,4 @@
|
||||
fi
|
||||
|
||||
ifconfig $1 0.0.0.0 up
|
||||
-brctl addif $bridge $1 || true
|
||||
+ip link set $1 master $bridge || true
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
--- xen-4.20.0-rc4/xen/arch/x86/arch.mk.orig 2025-02-07 11:56:01.000000000 +0000
|
||||
+++ xen-4.20.0-rc4/xen/arch/x86/arch.mk 2025-02-09 22:56:05.579507311 +0000
|
||||
@@ -95,7 +95,9 @@
|
||||
-c $(srctree)/$(efi-check).c -o $(efi-check).o,y)
|
||||
|
||||
# Check if the linker supports PE.
|
||||
-EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names
|
||||
+#EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names
|
||||
+# use a reduced set of options from LDFLAGS
|
||||
+EFI_LDFLAGS = --as-needed --build-id=sha1 -mi386pep --subsystem=10 --enable-long-section-names
|
||||
LD_PE_check_cmd = $(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o $(efi-check).efi $(efi-check).o)
|
||||
XEN_BUILD_PE := $(LD_PE_check_cmd)
|
||||
|
||||
11
xen.fedora.crypt.patch
Normal file
11
xen.fedora.crypt.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/vnc.c.orig 2015-07-12 21:55:32.875504811 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/vnc.c 2015-07-12 22:03:03.860005391 +0100
|
||||
@@ -2140,7 +2140,7 @@
|
||||
GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
|
||||
static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
|
||||
{
|
||||
- const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
|
||||
+ const char *priority = x509 ? "@SYSTEM" : "@SYSTEM:+ANON-DH";
|
||||
int rc;
|
||||
|
||||
rc = gnutls_priority_set_direct(s, priority, NULL);
|
||||
10
xen.fedora.efi.build.patch
Normal file
10
xen.fedora.efi.build.patch
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
--- xen-4.8.0/xen/Makefile.orig 2016-12-05 12:03:27.000000000 +0000
|
||||
+++ xen-4.8.0/xen/Makefile 2017-02-28 00:02:54.080529810 +0000
|
||||
@@ -20,6 +20,7 @@
|
||||
MAKEFLAGS += -rR
|
||||
|
||||
EFI_MOUNTPOINT ?= $(BOOT_DIR)/efi
|
||||
+EFI_VENDOR=fedora
|
||||
|
||||
ARCH=$(XEN_TARGET_ARCH)
|
||||
SRCARCH=$(shell echo $(ARCH) | sed -e 's/x86.*/x86/' -e s'/arm\(32\|64\)/arm/g')
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
--- xen-4.17.0/tools/hotplug/Linux/systemd/Makefile.orig 2022-12-08 18:03:08.000000000 +0000
|
||||
+++ xen-4.17.0/tools/hotplug/Linux/systemd/Makefile 2022-12-09 19:47:53.227189371 +0000
|
||||
@@ -10,7 +10,8 @@
|
||||
diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/Makefile xen-4.5.0/tools/hotplug/Linux/systemd/Makefile
|
||||
--- xen-4.5.0/tools/hotplug/Linux/systemd.orig/Makefile 2015-01-12 16:53:24.000000000 +0000
|
||||
+++ xen-4.5.0/tools/hotplug/Linux/systemd/Makefile 2015-01-25 22:23:26.000000000 +0000
|
||||
@@ -14,7 +14,8 @@
|
||||
XEN_SYSTEMD_SERVICE += xen-qemu-dom0-disk-backend.service
|
||||
XEN_SYSTEMD_SERVICE += xendomains.service
|
||||
XEN_SYSTEMD_SERVICE += xen-watchdog.service
|
||||
|
|
@ -9,7 +10,16 @@
|
|||
+XEN_SYSTEMD_SERVICE += oxenstored.service
|
||||
XEN_SYSTEMD_SERVICE += xendriverdomain.service
|
||||
|
||||
ALL_XEN_SYSTEMD := $(XEN_SYSTEMD_MODULES) \
|
||||
ALL_XEN_SYSTEMD = $(XEN_SYSTEMD_MODULES) \
|
||||
diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/var-lib-xenstored.mount.in xen-4.5.0/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in
|
||||
--- xen-4.5.0/tools/hotplug/Linux/systemd.orig/var-lib-xenstored.mount.in 2015-01-12 16:53:24.000000000 +0000
|
||||
+++ xen-4.5.0/tools/hotplug/Linux/systemd/var-lib-xenstored.mount.in 2015-01-25 22:28:59.000000000 +0000
|
||||
@@ -9,4 +9,4 @@
|
||||
What=xenstore
|
||||
Where=@XEN_LIB_STORED@
|
||||
Type=tmpfs
|
||||
-Options=mode=755
|
||||
+Options=mode=755,context="system_u:object_r:xenstored_var_lib_t:s0"
|
||||
diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/xenconsoled.service.in xen-4.5.0/tools/hotplug/Linux/systemd/xenconsoled.service.in
|
||||
--- xen-4.5.0/tools/hotplug/Linux/systemd.orig/xenconsoled.service.in 2015-01-12 16:53:24.000000000 +0000
|
||||
+++ xen-4.5.0/tools/hotplug/Linux/systemd/xenconsoled.service.in 2015-01-25 22:30:26.000000000 +0000
|
||||
|
|
@ -49,26 +59,27 @@ diff -uN xen-4.5.0/tools/hotplug/Linux/systemd.orig/xen-qemu-dom0-disk-backend.s
|
|||
Before=xendomains.service libvirtd.service libvirt-guests.service
|
||||
RefuseManualStop=true
|
||||
ConditionPathExists=/proc/xen/capabilities
|
||||
--- xen-4.17.0/tools/configure.ac.orig 2022-12-08 18:03:08.000000000 +0000
|
||||
+++ xen-4.17.0/tools/configure.ac 2022-12-09 19:50:24.773193862 +0000
|
||||
@@ -481,8 +481,8 @@
|
||||
--- xen-4.6.0/tools/configure.ac.orig 2015-02-15 16:47:22.000000000 +0000
|
||||
+++ xen-4.6.0/tools/configure.ac 2015-03-01 16:18:30.493647587 +0000
|
||||
@@ -382,9 +382,9 @@
|
||||
|
||||
AS_IF([test "x$systemd" = "xy"], [
|
||||
AC_CONFIG_FILES([
|
||||
+ hotplug/Linux/systemd/oxenstored.service
|
||||
hotplug/Linux/systemd/proc-xen.mount
|
||||
hotplug/Linux/systemd/var-lib-xenstored.mount
|
||||
- hotplug/Linux/systemd/xen-init-dom0.service
|
||||
hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service
|
||||
hotplug/Linux/systemd/xen-watchdog.service
|
||||
hotplug/Linux/systemd/xenconsoled.service
|
||||
--- xen-4.17.0/tools/configure.orig 2022-12-08 18:03:08.000000000 +0000
|
||||
+++ xen-4.17.0/tools/configure 2022-12-09 19:51:43.278708226 +0000
|
||||
@@ -10081,7 +10081,7 @@
|
||||
if test "x$systemd" = "xy"
|
||||
then :
|
||||
--- xen-4.6.0/tools/configure.orig 2015-02-15 16:47:22.000000000 +0000
|
||||
+++ xen-4.6.0/tools/configure 2015-03-01 16:20:10.648285840 +0000
|
||||
@@ -8995,7 +8995,7 @@
|
||||
|
||||
- ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
|
||||
+ ac_config_files="$ac_config_files hotplug/Linux/systemd/oxenstored.service hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
|
||||
if test "x$systemd" = "xy"; then :
|
||||
|
||||
- ac_config_files="$ac_config_files hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/var-lib-xenstored.mount hotplug/Linux/systemd/xen-init-dom0.service hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
|
||||
+ ac_config_files="$ac_config_files hotplug/Linux/systemd/oxenstored.service hotplug/Linux/systemd/proc-xen.mount hotplug/Linux/systemd/var-lib-xenstored.mount hotplug/Linux/systemd/xen-qemu-dom0-disk-backend.service hotplug/Linux/systemd/xen-watchdog.service hotplug/Linux/systemd/xenconsoled.service hotplug/Linux/systemd/xendomains.service hotplug/Linux/systemd/xendriverdomain.service hotplug/Linux/systemd/xenstored.service"
|
||||
|
||||
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
--- xen-4.14.0/xen/include/crypto/vmac.h.orig 2020-07-23 16:07:51.000000000 +0100
|
||||
+++ xen-4.14.0/xen/include/crypto/vmac.h 2020-10-24 15:45:49.246467465 +0100
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
#define vmac_update vhash_update
|
||||
|
||||
-void vhash_update(unsigned char m[],
|
||||
+void vhash_update(uint8_t *m,
|
||||
unsigned int mbytes,
|
||||
vmac_ctx_t *ctx);
|
||||
|
||||
diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c
|
||||
index 320e06f..618ae92 100644
|
||||
--- a/xen/arch/x86/tboot.c
|
||||
+++ b/xen/arch/x86/tboot.c
|
||||
@@ -91,7 +91,7 @@ static void __init tboot_copy_memory(unsigned char *va, uint32_t size,
|
||||
|
||||
void __init tboot_probe(void)
|
||||
{
|
||||
- tboot_shared_t *tboot_shared;
|
||||
+ tboot_shared_t * volatile tboot_shared;
|
||||
static const uuid_t __initconst tboot_shared_uuid = TBOOT_SHARED_UUID;
|
||||
|
||||
/* Look for valid page-aligned address for shared page. */
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
--- xen-4.16.0/Config.mk.orig 2021-11-30 11:42:42.000000000 +0000
|
||||
+++ xen-4.16.0/Config.mk 2022-01-24 20:25:16.687125822 +0000
|
||||
@@ -186,6 +186,7 @@
|
||||
|
||||
$(call cc-option-add,CFLAGS,CC,-Wno-unused-but-set-variable)
|
||||
$(call cc-option-add,CFLAGS,CC,-Wno-unused-local-typedefs)
|
||||
+$(call cc-option-add,CFLAGS,CC,-Wno-error=array-bounds)
|
||||
|
||||
LDFLAGS += $(foreach i, $(EXTRA_LIB), -L$(i))
|
||||
CFLAGS += $(foreach i, $(EXTRA_INCLUDES), -I$(i))
|
||||
12
xen.gcc7.fix.patch
Normal file
12
xen.gcc7.fix.patch
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
--- xen-4.8.0/extras/mini-os/Makefile.orig 2016-09-28 12:09:38.000000000 +0100
|
||||
+++ xen-4.8.0/extras/mini-os/Makefile 2017-02-15 21:15:19.340197960 +0000
|
||||
@@ -142,6 +142,9 @@
|
||||
APP_LDLIBS += -lz
|
||||
APP_LDLIBS += -lm
|
||||
LDLIBS += -lc
|
||||
+ifeq ($(MINIOS_TARGET_ARCH),x86_32)
|
||||
+LDLIBS += -L$(shell dirname `gcc -m32 -print-libgcc-file-name`) -lgcc
|
||||
+endif
|
||||
endif
|
||||
|
||||
ifneq ($(APP_OBJS)-$(lwip),-y)
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
From 90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Date: Fri, 10 Apr 2026 21:55:46 +0100
|
||||
Subject: [PATCH] x86/amd: Mitigate AMD-SN-7053 / FP-DSS
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This is XSA-488 / CVE-2025-54505
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
(cherry picked from commit 99912d346009fda1e7fb1510c9501fbab17e92a0)
|
||||
---
|
||||
xen/arch/x86/cpu/amd.c | 37 ++++++++++++++++++++++++++++
|
||||
xen/arch/x86/include/asm/msr-index.h | 1 +
|
||||
2 files changed, 38 insertions(+)
|
||||
|
||||
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
|
||||
index 8c55d233f3..1bb0766ebf 100644
|
||||
--- a/xen/arch/x86/cpu/amd.c
|
||||
+++ b/xen/arch/x86/cpu/amd.c
|
||||
@@ -1048,6 +1048,42 @@ void amd_init_de_cfg(const struct cpuinfo_x86 *c)
|
||||
wrmsrl(MSR_AMD64_DE_CFG, val | new);
|
||||
}
|
||||
|
||||
+static void amd_init_fp_cfg(const struct cpuinfo_x86 *c)
|
||||
+{
|
||||
+ uint64_t val, new = 0;
|
||||
+
|
||||
+ /* If virtualised, we won't have mutable access even if we can read it. */
|
||||
+ if ( cpu_has_hypervisor )
|
||||
+ return;
|
||||
+
|
||||
+ /*
|
||||
+ * On Zen1, mitigate SB-7053 / FP-DSS Floating Point Divider State
|
||||
+ * Sampling by setting bit 9 as instructed.
|
||||
+ */
|
||||
+ if ( c->family == 0x17 && is_zen1_uarch() )
|
||||
+ new |= 1 << 9;
|
||||
+
|
||||
+ /*
|
||||
+ * Avoid reading FP_CFG if we don't intend to change anything. The
|
||||
+ * register doesn't exist on all families.
|
||||
+ */
|
||||
+ if ( !new )
|
||||
+ return;
|
||||
+
|
||||
+ val = rdmsr(MSR_AMD64_FP_CFG);
|
||||
+
|
||||
+ if ( (val & new) == new )
|
||||
+ return;
|
||||
+
|
||||
+ /*
|
||||
+ * FP_CFG is a Core-scoped MSR, and this write is racy. However, both
|
||||
+ * threads calculate the new value from state which expected to be
|
||||
+ * consistent across CPUs and unrelated to the old value, so the result
|
||||
+ * should be consistent.
|
||||
+ */
|
||||
+ wrmsr(MSR_AMD64_FP_CFG, val | new);
|
||||
+}
|
||||
+
|
||||
void __init amd_init_lfence_dispatch(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
@@ -1120,6 +1156,7 @@ static void cf_check init_amd(struct cpuinfo_x86 *c)
|
||||
uint64_t value;
|
||||
|
||||
amd_init_de_cfg(c);
|
||||
+ amd_init_fp_cfg(c);
|
||||
|
||||
if (c == &boot_cpu_data)
|
||||
amd_init_lfence_dispatch(); /* Needs amd_init_de_cfg() */
|
||||
diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h
|
||||
index df52587c85..6c5b2569e1 100644
|
||||
--- a/xen/arch/x86/include/asm/msr-index.h
|
||||
+++ b/xen/arch/x86/include/asm/msr-index.h
|
||||
@@ -428,6 +428,7 @@
|
||||
#define MSR_AMD64_LS_CFG 0xc0011020U
|
||||
#define MSR_AMD64_IC_CFG 0xc0011021U
|
||||
#define MSR_AMD64_DC_CFG 0xc0011022U
|
||||
+#define MSR_AMD64_FP_CFG 0xc0011028U
|
||||
#define MSR_AMD64_DE_CFG 0xc0011029U
|
||||
#define AMD64_DE_CFG_LFENCE_SERIALISE (_AC(1, ULL) << 1)
|
||||
#define MSR_AMD64_EX_CFG 0xc001102cU
|
||||
--
|
||||
2.39.5
|
||||
|
||||
|
|
@ -1,172 +1,92 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Xen/x86 4.20 Configuration
|
||||
# Xen/x86 4.12.0 Configuration
|
||||
#
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=150001
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_LD_IS_GNU=y
|
||||
CONFIG_CC_HAS_VISIBILITY_ATTRIBUTE=y
|
||||
CONFIG_CC_SPLIT_SECTIONS=y
|
||||
CONFIG_FUNCTION_ALIGNMENT_16B=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=16
|
||||
CONFIG_X86_64=y
|
||||
CONFIG_X86=y
|
||||
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
|
||||
CONFIG_CC_HAS_INDIRECT_THUNK=y
|
||||
CONFIG_HAS_AS_CET_SS=y
|
||||
CONFIG_HAS_CC_CET_IBT=y
|
||||
|
||||
#
|
||||
# Architecture Features
|
||||
#
|
||||
CONFIG_AMD=y
|
||||
CONFIG_INTEL=y
|
||||
CONFIG_64BIT=y
|
||||
CONFIG_NR_CPUS=256
|
||||
CONFIG_NR_NUMA_NODES=64
|
||||
CONFIG_PV=y
|
||||
CONFIG_PV32=y
|
||||
CONFIG_PV_LINEAR_PT=y
|
||||
CONFIG_HVM=y
|
||||
CONFIG_AMD_SVM=y
|
||||
CONFIG_INTEL_VMX=y
|
||||
CONFIG_XEN_SHSTK=y
|
||||
CONFIG_XEN_IBT=y
|
||||
CONFIG_SHADOW_PAGING=y
|
||||
# CONFIG_BIGMEM is not set
|
||||
CONFIG_HVM_FEP=y
|
||||
CONFIG_X86_PSR=y
|
||||
CONFIG_XEN_ALIGN_DEFAULT=y
|
||||
# CONFIG_XEN_ALIGN_2M is not set
|
||||
# CONFIG_X2APIC_PHYSICAL is not set
|
||||
CONFIG_X2APIC_MIXED=y
|
||||
# CONFIG_HVM_FEP is not set
|
||||
CONFIG_TBOOT=y
|
||||
# CONFIG_XEN_GUEST is not set
|
||||
# CONFIG_HYPERV_GUEST is not set
|
||||
# CONFIG_REQUIRE_NX is not set
|
||||
CONFIG_ALTP2M=y
|
||||
# end of Architecture Features
|
||||
|
||||
#
|
||||
# Common Features
|
||||
#
|
||||
CONFIG_COMPAT=y
|
||||
CONFIG_CORE_PARKING=y
|
||||
CONFIG_GRANT_TABLE=y
|
||||
CONFIG_ALTERNATIVE_CALL=y
|
||||
CONFIG_ARCH_MAP_DOMAIN_PAGE=y
|
||||
CONFIG_GENERIC_BUG_FRAME=y
|
||||
CONFIG_HAS_ALTERNATIVE=y
|
||||
CONFIG_HAS_COMPAT=y
|
||||
CONFIG_HAS_DIT=y
|
||||
CONFIG_HAS_EX_TABLE=y
|
||||
CONFIG_HAS_FAST_MULTIPLY=y
|
||||
CONFIG_HAS_IOPORTS=y
|
||||
CONFIG_HAS_KEXEC=y
|
||||
CONFIG_HAS_PIRQ=y
|
||||
CONFIG_HAS_SCHED_GRANULARITY=y
|
||||
CONFIG_HAS_UBSAN=y
|
||||
CONFIG_HAS_VMAP=y
|
||||
CONFIG_MEM_ACCESS_ALWAYS_ON=y
|
||||
CONFIG_MEM_ACCESS=y
|
||||
CONFIG_HAS_MEM_PAGING=y
|
||||
CONFIG_HAS_MEM_SHARING=y
|
||||
CONFIG_HAS_PDX=y
|
||||
CONFIG_HAS_UBSAN=y
|
||||
CONFIG_HAS_KEXEC=y
|
||||
CONFIG_HAS_GDBSX=y
|
||||
CONFIG_HAS_IOPORTS=y
|
||||
CONFIG_NEEDS_LIBELF=y
|
||||
CONFIG_NUMA=y
|
||||
|
||||
#
|
||||
# Speculative hardening
|
||||
#
|
||||
CONFIG_INDIRECT_THUNK=y
|
||||
CONFIG_RETURN_THUNK=y
|
||||
CONFIG_SPECULATIVE_HARDEN_ARRAY=y
|
||||
CONFIG_SPECULATIVE_HARDEN_BRANCH=y
|
||||
CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS=y
|
||||
CONFIG_SPECULATIVE_HARDEN_LOCK=y
|
||||
# end of Speculative hardening
|
||||
|
||||
# CONFIG_DIT_DEFAULT is not set
|
||||
CONFIG_HYPFS=y
|
||||
CONFIG_HYPFS_CONFIG=y
|
||||
CONFIG_IOREQ_SERVER=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_XENOPROF=y
|
||||
# CONFIG_XSM is not set
|
||||
CONFIG_SCHED_CREDIT=y
|
||||
CONFIG_SCHED_CREDIT2=y
|
||||
CONFIG_SCHED_RTDS=y
|
||||
CONFIG_SCHED_ARINC653=y
|
||||
# CONFIG_SCHED_ARINC653 is not set
|
||||
CONFIG_SCHED_NULL=y
|
||||
CONFIG_SCHED_DEFAULT="credit2"
|
||||
# CONFIG_BOOT_TIME_CPUPOOLS is not set
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_LIVEPATCH=y
|
||||
CONFIG_FAST_SYMBOL_LOOKUP=y
|
||||
CONFIG_ENFORCE_UNIQUE_SYMBOLS=y
|
||||
CONFIG_CMDLINE=""
|
||||
CONFIG_DOM0_MEM=""
|
||||
CONFIG_DTB_FILE=""
|
||||
CONFIG_TRACEBUFFER=y
|
||||
# end of Common Features
|
||||
|
||||
#
|
||||
# Device Drivers
|
||||
#
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
|
||||
CONFIG_ACPI_NUMA=y
|
||||
CONFIG_NUMA=y
|
||||
CONFIG_HAS_NS16550=y
|
||||
CONFIG_HAS_EHCI=y
|
||||
CONFIG_SERIAL_TX_BUFSIZE=32768
|
||||
# CONFIG_XHCI is not set
|
||||
CONFIG_HAS_CPUFREQ=y
|
||||
CONFIG_HAS_PASSTHROUGH=y
|
||||
CONFIG_AMD_IOMMU=y
|
||||
CONFIG_INTEL_IOMMU=y
|
||||
# CONFIG_IOMMU_QUARANTINE_NONE is not set
|
||||
CONFIG_IOMMU_QUARANTINE_BASIC=y
|
||||
# CONFIG_IOMMU_QUARANTINE_SCRATCH_PAGE is not set
|
||||
CONFIG_HAS_PCI=y
|
||||
CONFIG_HAS_PCI_MSI=y
|
||||
CONFIG_VIDEO=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_HAS_VPCI=y
|
||||
# end of Device Drivers
|
||||
|
||||
# CONFIG_EXPERT is not set
|
||||
# CONFIG_UNSUPPORTED is not set
|
||||
#
|
||||
# Deprecated Functionality
|
||||
#
|
||||
# CONFIG_PV_LDT_PAGING is not set
|
||||
CONFIG_DEFCONFIG_LIST="$ARCH_DEFCONFIG"
|
||||
CONFIG_ARCH_SUPPORTS_INT128=y
|
||||
CONFIG_ARCH_VCPU_IOREQ_COMPLETION=y
|
||||
|
||||
#
|
||||
# Debugging Options
|
||||
#
|
||||
# CONFIG_DEBUG is not set
|
||||
CONFIG_GDBSX=y
|
||||
CONFIG_FRAME_POINTER=y
|
||||
CONFIG_SELF_TESTS=y
|
||||
# CONFIG_DEBUG_LOCK_PROFILE is not set
|
||||
CONFIG_DEBUG_LOCKS=y
|
||||
# CONFIG_PERF_COUNTERS is not set
|
||||
CONFIG_VERBOSE_DEBUG=y
|
||||
CONFIG_SCRUB_DEBUG=y
|
||||
# CONFIG_UBSAN is not set
|
||||
# CONFIG_DEBUG_TRACE is not set
|
||||
CONFIG_XMEM_POOL_POISON=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# end of Debugging Options
|
||||
|
||||
# ARM64 settings
|
||||
CONFIG_MMU=y
|
||||
CONFIG_64BIT=y
|
||||
CONFIG_ARM_64=y
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARM_EFI=y
|
||||
CONFIG_GICV2=y
|
||||
CONFIG_GICV3=y
|
||||
CONFIG_VGICV2=y
|
||||
# CONFIG_NEW_VGIC is not set
|
||||
CONFIG_SBSA_VUART_CONSOLE=y
|
||||
CONFIG_HWDOM_VUART=y
|
||||
CONFIG_ARM_SSBD=y
|
||||
CONFIG_HARDEN_BRANCH_PREDICTOR=y
|
||||
CONFIG_STATIC_EVTCHN=y
|
||||
CONFIG_PARTIAL_EMULATION=y
|
||||
|
||||
#
|
||||
# ARM errata workaround via the alternative framework
|
||||
|
|
@ -174,15 +94,8 @@ CONFIG_PARTIAL_EMULATION=y
|
|||
CONFIG_ARM64_ERRATUM_827319=y
|
||||
CONFIG_ARM64_ERRATUM_824069=y
|
||||
CONFIG_ARM64_ERRATUM_819472=y
|
||||
CONFIG_ARM64_ERRATUM_843419=y
|
||||
CONFIG_ARM64_ERRATUM_832075=y
|
||||
CONFIG_ARM64_ERRATUM_834220=y
|
||||
CONFIG_ARM_ERRATUM_858921=y
|
||||
CONFIG_ARM64_WORKAROUND_REPEAT_TLBI=y
|
||||
CONFIG_ARM64_ERRATUM_1286807=y
|
||||
CONFIG_ARM64_ERRATUM_1508412=y
|
||||
|
||||
# end of ARM errata workaround via the alternative framework
|
||||
CONFIG_ARM64_HARDEN_BRANCH_PREDICTOR=y
|
||||
CONFIG_ALL_PLAT=y
|
||||
# CONFIG_QEMU is not set
|
||||
|
|
@ -191,18 +104,16 @@ CONFIG_ALL_PLAT=y
|
|||
# CONFIG_NO_PLAT is not set
|
||||
CONFIG_ALL64_PLAT=y
|
||||
CONFIG_MPSOC_PLATFORM=y
|
||||
|
||||
#
|
||||
# Common Features
|
||||
#
|
||||
CONFIG_HAS_DEVICE_TREE=y
|
||||
CONFIG_HAS_CADENCE_UART=y
|
||||
CONFIG_HAS_LINFLEX=y
|
||||
CONFIG_HAS_IMX_LPUART=y
|
||||
CONFIG_HAS_MVEBU=y
|
||||
CONFIG_HAS_MESON=y
|
||||
CONFIG_HAS_PL011=y
|
||||
CONFIG_HAS_OMAP=y
|
||||
CONFIG_HAS_SCIF=y
|
||||
CONFIG_ARM_SMMU=y
|
||||
# CONFIG_IPMMU_VMSA is not set
|
||||
|
||||
# ARM32 settings
|
||||
CONFIG_ALL32_PLAT=y
|
||||
CONFIG_ARM32_HARDEN_BRANCH_PREDICTOR=y
|
||||
CONFIG_ARM_32=y
|
||||
CONFIG_HAS_EXYNOS4210=y
|
||||
CONFIG_HAS_OMAP=y
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
--- xen-4.21.0/tools/libs/light/libxl_nocpuid.c.orig 2025-11-18 18:02:13.000000000 +0000
|
||||
+++ xen-4.21.0/tools/libs/light/libxl_nocpuid.c 2025-11-20 09:03:56.517804514 +0000
|
||||
@@ -40,11 +40,24 @@
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#ifdef HAVE_LIBJSONC
|
||||
+#ifndef _hidden
|
||||
+#define _hidden
|
||||
+#endif
|
||||
+_hidden int libxl_cpuid_policy_list_gen_jso(json_object **jso_r,
|
||||
+ libxl_cpuid_policy_list *pcpuid)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+#if defined(HAVE_LIBYAJL)
|
||||
yajl_gen_status libxl_cpuid_policy_list_gen_json(yajl_gen hand,
|
||||
libxl_cpuid_policy_list *pcpuid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
+#endif
|
||||
|
||||
int libxl__cpuid_policy_list_parse_json(libxl__gc *gc,
|
||||
const libxl__json_object *o,
|
||||
43
xen.python.env.patch
Normal file
43
xen.python.env.patch
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
--- xen-4.11.0/tools/xenmon/Makefile.orig 2018-07-09 14:47:19.000000000 +0100
|
||||
+++ xen-4.11.0/tools/xenmon/Makefile 2018-09-10 21:13:15.200655105 +0100
|
||||
@@ -32,7 +32,7 @@
|
||||
$(INSTALL_DIR) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL_PROG) xenbaked $(DESTDIR)$(sbindir)/xenbaked
|
||||
$(INSTALL_PROG) xentrace_setmask $(DESTDIR)$(sbindir)/xentrace_setmask
|
||||
- $(INSTALL_PROG) xenmon.py $(DESTDIR)$(sbindir)/xenmon
|
||||
+ $(INSTALL_PYTHON_PROG) xenmon.py $(DESTDIR)$(sbindir)/xenmon
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
--- xen-4.11.0/tools/python/Makefile.orig 2018-07-09 14:47:19.000000000 +0100
|
||||
+++ xen-4.11.0/tools/python/Makefile 2018-09-10 21:21:07.097979007 +0100
|
||||
@@ -20,8 +20,8 @@
|
||||
setup.py install --record $(INSTALL_LOG) $(PYTHON_PREFIX_ARG) \
|
||||
--root="$(DESTDIR)" --force
|
||||
|
||||
- $(INSTALL_PROG) scripts/convert-legacy-stream $(DESTDIR)$(LIBEXEC_BIN)
|
||||
- $(INSTALL_PROG) scripts/verify-stream-v2 $(DESTDIR)$(LIBEXEC_BIN)
|
||||
+ $(INSTALL_PYTHON_PROG) scripts/convert-legacy-stream $(DESTDIR)$(LIBEXEC_BIN)
|
||||
+ $(INSTALL_PYTHON_PROG) scripts/verify-stream-v2 $(DESTDIR)$(LIBEXEC_BIN)
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
--- xen-4.11.0/tools/python/install-wrap.orig 2018-07-09 14:47:19.000000000 +0100
|
||||
+++ xen-4.11.0/tools/python/install-wrap 2018-09-11 20:09:57.803655357 +0100
|
||||
@@ -44,7 +44,7 @@
|
||||
destf="$dest"
|
||||
for srcf in ${srcs}; do
|
||||
if test -d "$dest"; then
|
||||
- destf="$dest/${srcf%%*/}"
|
||||
+ destf="$dest/${srcf##*/}"
|
||||
fi
|
||||
org="$(sed -n '2q; /^#! *\/usr\/bin\/env python *$/p' $srcf)"
|
||||
if test "x$org" = x; then
|
||||
--- xen-4.11.0/tools/misc/xencov_split.orig 2018-07-09 14:47:19.000000000 +0100
|
||||
+++ xen-4.11.0/tools/misc/xencov_split 2018-09-18 21:56:07.397893895 +0100
|
||||
@@ -1,4 +1,4 @@
|
||||
-#!/usr/bin/python
|
||||
+#!/usr/bin/python3
|
||||
|
||||
import sys, os, os.path as path, struct, errno
|
||||
from optparse import OptionParser
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
--- xen-4.17.1/tools/python/Makefile.orig 2023-04-27 13:53:19.000000000 +0100
|
||||
+++ xen-4.17.1/tools/python/Makefile 2023-06-22 22:21:25.287486906 +0100
|
||||
@@ -4,7 +4,7 @@
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
-PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS)
|
||||
+PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS) -Wno-error=declaration-after-statement
|
||||
PY_LDFLAGS = $(SHLIB_LDFLAGS) $(APPEND_LDFLAGS)
|
||||
INSTALL_LOG = build/installed_files.txt
|
||||
|
||||
--- xen-4.17.1/tools/pygrub/Makefile.orig 2023-04-27 13:53:19.000000000 +0100
|
||||
+++ xen-4.17.1/tools/pygrub/Makefile 2023-06-22 22:52:52.803047401 +0100
|
||||
@@ -2,7 +2,7 @@
|
||||
XEN_ROOT = $(CURDIR)/../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
-PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS)
|
||||
+PY_CFLAGS = $(CFLAGS) $(PY_NOOPT_CFLAGS) -Wno-error=declaration-after-statement
|
||||
PY_LDFLAGS = $(SHLIB_LDFLAGS) $(APPEND_LDFLAGS)
|
||||
INSTALL_LOG = build/installed_files.txt
|
||||
|
||||
1749
xen.python3.patch
Normal file
1749
xen.python3.patch
Normal file
File diff suppressed because it is too large
Load diff
94
xen.python38.patch
Normal file
94
xen.python38.patch
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
--- xen-4.12.0/m4/python_devel.m4.orig 2019-05-31 23:30:42.489738121 +0100
|
||||
+++ xen-4.12.0/m4/python_devel.m4 2019-06-01 17:02:38.886934441 +0100
|
||||
@@ -24,7 +24,8 @@
|
||||
dnl If python-config is found use it
|
||||
CPPFLAGS="$CFLAGS `$PYTHON-config --cflags`"
|
||||
LDFLAGS="$LDFLAGS `$PYTHON-config --ldflags`"
|
||||
- LIBS="$LIBS `$PYTHON-config --libs`"
|
||||
+ LIBSTMP="`$PYTHON-config --libs --embed`" || LIBSTMP="`$PYTHON-config --libs`"
|
||||
+ LIBS="$LIBS $LIBSTMP"
|
||||
])
|
||||
|
||||
AC_CHECK_HEADER([Python.h], [],
|
||||
--- xen-4.12.0/tools/configure.orig 2019-05-31 23:30:42.498738452 +0100
|
||||
+++ xen-4.12.0/tools/configure 2019-06-01 17:08:26.100727658 +0100
|
||||
@@ -7482,7 +7482,8 @@
|
||||
|
||||
CPPFLAGS="$CFLAGS `$PYTHON-config --cflags`"
|
||||
LDFLAGS="$LDFLAGS `$PYTHON-config --ldflags`"
|
||||
- LIBS="$LIBS `$PYTHON-config --libs`"
|
||||
+ LIBSTMP="`$PYTHON-config --libs --embed`" || LIBSTMP="`$PYTHON-config --libs`"
|
||||
+ LIBS="$LIBS $LIBSTMP"
|
||||
|
||||
fi
|
||||
|
||||
--- xen-4.12.0/tools/python/xen/lowlevel/xc/xc.c.orig 2019-04-01 12:03:23.000000000 +0100
|
||||
+++ xen-4.12.0/tools/python/xen/lowlevel/xc/xc.c 2019-06-01 17:58:39.567729630 +0100
|
||||
@@ -118,7 +118,8 @@
|
||||
PyObject *kwds)
|
||||
{
|
||||
uint32_t dom = 0, target = 0;
|
||||
- int ret, i;
|
||||
+ int ret;
|
||||
+ unsigned int i;
|
||||
PyObject *pyhandle = NULL;
|
||||
struct xen_domctl_createdomain config = {
|
||||
.handle = {
|
||||
@@ -296,7 +297,7 @@
|
||||
|
||||
static PyObject *pyxc_domain_sethandle(XcObject *self, PyObject *args)
|
||||
{
|
||||
- int i;
|
||||
+ unsigned int i;
|
||||
uint32_t dom;
|
||||
PyObject *pyhandle;
|
||||
xen_domain_handle_t handle;
|
||||
@@ -337,7 +338,8 @@
|
||||
PyObject *list, *info_dict, *pyhandle;
|
||||
|
||||
uint32_t first_dom = 0;
|
||||
- int max_doms = 1024, nr_doms, i, j;
|
||||
+ int max_doms = 1024, nr_doms, i;
|
||||
+ unsigned int j;
|
||||
xc_dominfo_t *info;
|
||||
|
||||
static char *kwd_list[] = { "first_dom", "max_doms", NULL };
|
||||
@@ -632,7 +634,8 @@
|
||||
{
|
||||
uint32_t sbdf;
|
||||
uint32_t max_sdevs, num_sdevs;
|
||||
- int domid, seg, bus, dev, func, rc, i;
|
||||
+ int domid, seg, bus, dev, func, rc;
|
||||
+ unsigned int i;
|
||||
PyObject *Pystr;
|
||||
char *group_str;
|
||||
char dev_str[9];
|
||||
@@ -972,7 +975,7 @@
|
||||
{
|
||||
xc_physinfo_t pinfo;
|
||||
char cpu_cap[128], virt_caps[128], *p;
|
||||
- int i;
|
||||
+ unsigned int i;
|
||||
const char *virtcap_names[] = { "hvm", "hvm_directio" };
|
||||
|
||||
if ( xc_physinfo(self->xc_handle, &pinfo) != 0 )
|
||||
--- xen-4.12.0/tools/python/xen/lowlevel/xs/xs.c.orig 2019-04-01 12:03:23.000000000 +0100
|
||||
+++ xen-4.12.0/tools/python/xen/lowlevel/xs/xs.c 2019-06-01 18:59:46.316760561 +0100
|
||||
@@ -186,7 +186,7 @@
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (xsval) {
|
||||
- int i;
|
||||
+ unsigned int i;
|
||||
PyObject *val = PyList_New(xsval_n);
|
||||
for (i = 0; i < xsval_n; i++)
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
@@ -276,7 +276,7 @@
|
||||
struct xs_handle *xh = xshandle(self);
|
||||
struct xs_permissions *perms;
|
||||
unsigned int perms_n = 0;
|
||||
- int i;
|
||||
+ unsigned int i;
|
||||
|
||||
xs_transaction_t th;
|
||||
char *thstr;
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
From b1d6f37aa5aa9f3fc5a269b9dd21b7feb7444be0 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Date: Thu, 22 Oct 2020 11:28:58 +0100
|
||||
Subject: [PATCH 1/2] x86/pv: Drop FLUSH_TLB_GLOBAL in do_mmu_update() for XPTI
|
||||
|
||||
c/s 9d1d31ad9498 "x86: slightly reduce Meltdown band-aid overhead" removed the
|
||||
use of Global TLB flushes on the Xen entry path, but added a FLUSH_TLB_GLOBAL
|
||||
to the L4 path in do_mmu_update().
|
||||
|
||||
However, this was unnecessary.
|
||||
|
||||
It is the guests responsibility to perform appropriate TLB flushing if the L4
|
||||
modification altered an established mapping in a flush-relevant way. In this
|
||||
case, an MMUEXT_OP hypercall will follow. The case which Xen needs to cover
|
||||
is when new mappings are created, and the resync on the exit-to-guest path
|
||||
covers this correctly.
|
||||
|
||||
There is a corner case with multiple vCPUs in hypercalls at the same time,
|
||||
which 9d1d31ad9498 changed, and this patch changes back to its original XPTI
|
||||
behaviour.
|
||||
|
||||
Architecturally, established TLB entries can continue to be used until the
|
||||
broadcast flush has completed. Therefore, even with concurrent hypercalls,
|
||||
the guest cannot depend on older mappings not being used until an MMUEXT_OP
|
||||
hypercall completes. Xen's implementation of guest-initiated flushes will
|
||||
take correct effect on top of an in-progress hypercall, picking up new mapping
|
||||
setting before the other vCPU's MMUEXT_OP completes.
|
||||
|
||||
Note: The correctness of this change is not impacted by whether XPTI uses
|
||||
global mappings or not. Correctness there depends on the behaviour of Xen on
|
||||
the entry/exit paths when switching two/from the XPTI "shadow" pagetables.
|
||||
|
||||
This is (not really) XSA-286 (but necessary to simplify the logic).
|
||||
|
||||
Fixes: 9d1d31ad9498 ("x86: slightly reduce Meltdown band-aid overhead")
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
(cherry picked from commit 055e1c3a3d95b1e753148369fbc4ba48782dd602)
|
||||
---
|
||||
xen/arch/x86/mm.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
|
||||
index e7b8f4ee4b..86f31b334f 100644
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -4301,7 +4301,7 @@ long do_mmu_update(
|
||||
|
||||
cpumask_andnot(mask, pt_owner->dirty_cpumask, cpumask_of(cpu));
|
||||
if ( !cpumask_empty(mask) )
|
||||
- flush_mask(mask, FLUSH_TLB_GLOBAL | FLUSH_ROOT_PGTBL);
|
||||
+ flush_mask(mask, FLUSH_ROOT_PGTBL);
|
||||
}
|
||||
|
||||
perfc_add(num_page_updates, i);
|
||||
--
|
||||
2.20.1
|
||||
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
From 4100d463dbdd95d85fabe387dd5676bed75f65f7 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Date: Mon, 19 Oct 2020 15:51:22 +0100
|
||||
Subject: [PATCH 2/2] x86/pv: Flush TLB in response to paging structure changes
|
||||
|
||||
With MMU_UPDATE, a PV guest can make changes to higher level pagetables. This
|
||||
is safe from Xen's point of view (as the update only affects guest mappings),
|
||||
and the guest is required to flush (if necessary) after making updates.
|
||||
|
||||
However, Xen's use of linear pagetables (UPDATE_VA_MAPPING, GNTTABOP_map,
|
||||
writeable pagetables, etc.) is an implementation detail outside of the
|
||||
API/ABI.
|
||||
|
||||
Changes in the paging structure require invalidations in the linear pagetable
|
||||
range for subsequent accesses into the linear pagetables to access non-stale
|
||||
mappings. Xen must provide suitable flushing to prevent intermixed guest
|
||||
actions from accidentally accessing/modifying the wrong pagetable.
|
||||
|
||||
For all L2 and higher modifications, flush the TLB. PV guests cannot create
|
||||
L2 or higher entries with the Global bit set, so no mappings established in
|
||||
the linear range can be global. (This could in principle be an order 39 flush
|
||||
starting at LINEAR_PT_VIRT_START, but no such mechanism exists in practice.)
|
||||
|
||||
Express the necessary flushes as a set of booleans which accumulate across the
|
||||
operation. Comment the flushing logic extensively.
|
||||
|
||||
This is XSA-286.
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
(cherry picked from commit 16a20963b3209788f2c0d3a3eebb7d92f03f5883)
|
||||
---
|
||||
xen/arch/x86/mm.c | 69 ++++++++++++++++++++++++++++++++++++++++-------
|
||||
1 file changed, 59 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
|
||||
index 86f31b334f..db4cfdf20b 100644
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -4005,7 +4005,8 @@ long do_mmu_update(
|
||||
struct vcpu *curr = current, *v = curr;
|
||||
struct domain *d = v->domain, *pt_owner = d, *pg_owner;
|
||||
mfn_t map_mfn = INVALID_MFN;
|
||||
- bool sync_guest = false;
|
||||
+ bool flush_linear_pt = false, flush_root_pt_local = false,
|
||||
+ flush_root_pt_others = false;
|
||||
uint32_t xsm_needed = 0;
|
||||
uint32_t xsm_checked = 0;
|
||||
int rc = put_old_guest_table(curr);
|
||||
@@ -4155,6 +4156,8 @@ long do_mmu_update(
|
||||
break;
|
||||
rc = mod_l2_entry(va, l2e_from_intpte(req.val), mfn,
|
||||
cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
|
||||
+ if ( !rc )
|
||||
+ flush_linear_pt = true;
|
||||
break;
|
||||
|
||||
case PGT_l3_page_table:
|
||||
@@ -4162,6 +4165,8 @@ long do_mmu_update(
|
||||
break;
|
||||
rc = mod_l3_entry(va, l3e_from_intpte(req.val), mfn,
|
||||
cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
|
||||
+ if ( !rc )
|
||||
+ flush_linear_pt = true;
|
||||
break;
|
||||
|
||||
case PGT_l4_page_table:
|
||||
@@ -4169,6 +4174,8 @@ long do_mmu_update(
|
||||
break;
|
||||
rc = mod_l4_entry(va, l4e_from_intpte(req.val), mfn,
|
||||
cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
|
||||
+ if ( !rc )
|
||||
+ flush_linear_pt = true;
|
||||
if ( !rc && pt_owner->arch.pv.xpti )
|
||||
{
|
||||
bool local_in_use = false;
|
||||
@@ -4176,7 +4183,7 @@ long do_mmu_update(
|
||||
if ( pagetable_get_pfn(curr->arch.guest_table) == mfn )
|
||||
{
|
||||
local_in_use = true;
|
||||
- get_cpu_info()->root_pgt_changed = true;
|
||||
+ flush_root_pt_local = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4188,7 +4195,7 @@ long do_mmu_update(
|
||||
(1 + !!(page->u.inuse.type_info & PGT_pinned) +
|
||||
(pagetable_get_pfn(curr->arch.guest_table_user) ==
|
||||
mfn) + local_in_use) )
|
||||
- sync_guest = true;
|
||||
+ flush_root_pt_others = true;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -4290,19 +4297,61 @@ long do_mmu_update(
|
||||
if ( va )
|
||||
unmap_domain_page(va);
|
||||
|
||||
- if ( sync_guest )
|
||||
+ /*
|
||||
+ * Perform required TLB maintenance.
|
||||
+ *
|
||||
+ * This logic currently depend on flush_linear_pt being a superset of the
|
||||
+ * flush_root_pt_* conditions.
|
||||
+ *
|
||||
+ * pt_owner may not be current->domain. This may occur during
|
||||
+ * construction of 32bit PV guests, or debugging of PV guests. The
|
||||
+ * behaviour cannot be correct with domain unpaused. We therefore expect
|
||||
+ * pt_owner->dirty_cpumask to be empty, but it is a waste of effort to
|
||||
+ * explicitly check for, and exclude, this corner case.
|
||||
+ *
|
||||
+ * flush_linear_pt requires a FLUSH_TLB to all dirty CPUs. The flush must
|
||||
+ * be performed now to maintain correct behaviour across a multicall.
|
||||
+ * i.e. we cannot relax FLUSH_TLB to FLUSH_ROOT_PGTBL, given that the
|
||||
+ * former is a side effect of the latter, because the resync (which is in
|
||||
+ * the return-to-guest path) happens too late.
|
||||
+ *
|
||||
+ * flush_root_pt_* requires FLUSH_ROOT_PGTBL on either the local CPU
|
||||
+ * (implies pt_owner == current->domain and current->processor set in
|
||||
+ * pt_owner->dirty_cpumask), and/or all *other* dirty CPUs as there are
|
||||
+ * references we can't account for locally.
|
||||
+ */
|
||||
+ if ( flush_linear_pt /* || flush_root_pt_local || flush_root_pt_others */ )
|
||||
{
|
||||
+ unsigned int cpu = smp_processor_id();
|
||||
+ cpumask_t *mask = pt_owner->dirty_cpumask;
|
||||
+
|
||||
/*
|
||||
- * Force other vCPU-s of the affected guest to pick up L4 entry
|
||||
- * changes (if any).
|
||||
+ * Always handle local flushing separately (if applicable), to
|
||||
+ * separate the flush invocations appropriately for scope of the two
|
||||
+ * flush_root_pt_* variables.
|
||||
*/
|
||||
- unsigned int cpu = smp_processor_id();
|
||||
- cpumask_t *mask = per_cpu(scratch_cpumask, cpu);
|
||||
+ if ( likely(cpumask_test_cpu(cpu, mask)) )
|
||||
+ {
|
||||
+ mask = per_cpu(scratch_cpumask, cpu);
|
||||
|
||||
- cpumask_andnot(mask, pt_owner->dirty_cpumask, cpumask_of(cpu));
|
||||
+ cpumask_copy(mask, pt_owner->dirty_cpumask);
|
||||
+ __cpumask_clear_cpu(cpu, mask);
|
||||
+
|
||||
+ flush_local(FLUSH_TLB |
|
||||
+ (flush_root_pt_local ? FLUSH_ROOT_PGTBL : 0));
|
||||
+ }
|
||||
+ else
|
||||
+ /* Sanity check. flush_root_pt_local implies local cpu is dirty. */
|
||||
+ ASSERT(!flush_root_pt_local);
|
||||
+
|
||||
+ /* Flush the remote dirty CPUs. Does not include the local CPU. */
|
||||
if ( !cpumask_empty(mask) )
|
||||
- flush_mask(mask, FLUSH_ROOT_PGTBL);
|
||||
+ flush_mask(mask, FLUSH_TLB |
|
||||
+ (flush_root_pt_others ? FLUSH_ROOT_PGTBL : 0));
|
||||
}
|
||||
+ else
|
||||
+ /* Sanity check. flush_root_pt_* implies flush_linear_pt. */
|
||||
+ ASSERT(!flush_root_pt_local && !flush_root_pt_others);
|
||||
|
||||
perfc_add(num_page_updates, i);
|
||||
|
||||
--
|
||||
2.20.1
|
||||
|
||||
50
xsa317.patch
Normal file
50
xsa317.patch
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
From aeb46e92f915f19a61d5a8a1f4b696793f64e6fb Mon Sep 17 00:00:00 2001
|
||||
From: Julien Grall <jgrall@amazon.com>
|
||||
Date: Thu, 19 Mar 2020 13:17:31 +0000
|
||||
Subject: [PATCH] xen/common: event_channel: Don't ignore error in
|
||||
get_free_port()
|
||||
|
||||
Currently, get_free_port() is assuming that the port has been allocated
|
||||
when evtchn_allocate_port() is not return -EBUSY.
|
||||
|
||||
However, the function may return an error when:
|
||||
- We exhausted all the event channels. This can happen if the limit
|
||||
configured by the administrator for the guest ('max_event_channels'
|
||||
in xl cfg) is higher than the ABI used by the guest. For instance,
|
||||
if the guest is using 2L, the limit should not be higher than 4095.
|
||||
- We cannot allocate memory (e.g Xen has not more memory).
|
||||
|
||||
Users of get_free_port() (such as EVTCHNOP_alloc_unbound) will validly
|
||||
assuming the port was valid and will next call evtchn_from_port(). This
|
||||
will result to a crash as the memory backing the event channel structure
|
||||
is not present.
|
||||
|
||||
Fixes: 368ae9a05fe ("xen/pvshim: forward evtchn ops between L0 Xen and L2 DomU")
|
||||
Signed-off-by: Julien Grall <jgrall@amazon.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
---
|
||||
xen/common/event_channel.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
|
||||
index e86e2bfab0..a8d182b584 100644
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -195,10 +195,10 @@ static int get_free_port(struct domain *d)
|
||||
{
|
||||
int rc = evtchn_allocate_port(d, port);
|
||||
|
||||
- if ( rc == -EBUSY )
|
||||
- continue;
|
||||
-
|
||||
- return port;
|
||||
+ if ( rc == 0 )
|
||||
+ return port;
|
||||
+ else if ( rc != -EBUSY )
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
--
|
||||
2.17.1
|
||||
|
||||
27
xsa319.patch
Normal file
27
xsa319.patch
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/shadow: correct an inverted conditional in dirty VRAM tracking
|
||||
|
||||
This originally was "mfn_x(mfn) == INVALID_MFN". Make it like this
|
||||
again, taking the opportunity to also drop the unnecessary nearby
|
||||
braces.
|
||||
|
||||
This is XSA-319.
|
||||
|
||||
Fixes: 246a5a3377c2 ("xen: Use a typesafe to define INVALID_MFN")
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
|
||||
--- a/xen/arch/x86/mm/shadow/common.c
|
||||
+++ b/xen/arch/x86/mm/shadow/common.c
|
||||
@@ -3252,10 +3252,8 @@ int shadow_track_dirty_vram(struct domai
|
||||
int dirty = 0;
|
||||
paddr_t sl1ma = dirty_vram->sl1ma[i];
|
||||
|
||||
- if ( !mfn_eq(mfn, INVALID_MFN) )
|
||||
- {
|
||||
+ if ( mfn_eq(mfn, INVALID_MFN) )
|
||||
dirty = 1;
|
||||
- }
|
||||
else
|
||||
{
|
||||
page = mfn_to_page(mfn);
|
||||
133
xsa320-4.12-1.patch
Normal file
133
xsa320-4.12-1.patch
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/spec-ctrl: CPUID/MSR definitions for Special Register Buffer Data Sampling
|
||||
|
||||
This is part of XSA-320 / CVE-2020-0543
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Wei Liu <wl@xen.org>
|
||||
|
||||
diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
|
||||
index 3561d88b59..dbdaee92dc 100644
|
||||
--- a/docs/misc/xen-command-line.pandoc
|
||||
+++ b/docs/misc/xen-command-line.pandoc
|
||||
@@ -483,10 +483,10 @@ accounting for hardware capabilities as enumerated via CPUID.
|
||||
|
||||
Currently accepted:
|
||||
|
||||
-The Speculation Control hardware features `md-clear`, `ibrsb`, `stibp`, `ibpb`,
|
||||
-`l1d-flush` and `ssbd` are used by default if available and applicable. They can
|
||||
-be ignored, e.g. `no-ibrsb`, at which point Xen won't use them itself, and
|
||||
-won't offer them to guests.
|
||||
+The Speculation Control hardware features `srbds-ctrl`, `md-clear`, `ibrsb`,
|
||||
+`stibp`, `ibpb`, `l1d-flush` and `ssbd` are used by default if available and
|
||||
+applicable. They can be ignored, e.g. `no-ibrsb`, at which point Xen won't
|
||||
+use them itself, and won't offer them to guests.
|
||||
|
||||
### cpuid_mask_cpu
|
||||
> `= fam_0f_rev_[cdefg] | fam_10_rev_[bc] | fam_11_rev_b`
|
||||
diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c
|
||||
index 4cf0f0738d..88b5760c85 100644
|
||||
--- a/tools/libxl/libxl_cpuid.c
|
||||
+++ b/tools/libxl/libxl_cpuid.c
|
||||
@@ -203,6 +203,7 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
|
||||
|
||||
{"avx512-4vnniw",0x00000007, 0, CPUID_REG_EDX, 2, 1},
|
||||
{"avx512-4fmaps",0x00000007, 0, CPUID_REG_EDX, 3, 1},
|
||||
+ {"srbds-ctrl", 0x00000007, 0, CPUID_REG_EDX, 9, 1},
|
||||
{"md-clear", 0x00000007, 0, CPUID_REG_EDX, 10, 1},
|
||||
{"cet-ibt", 0x00000007, 0, CPUID_REG_EDX, 20, 1},
|
||||
{"ibrsb", 0x00000007, 0, CPUID_REG_EDX, 26, 1},
|
||||
diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c
|
||||
index 2a00697643..b4c4dfcf19 100644
|
||||
--- a/tools/misc/xen-cpuid.c
|
||||
+++ b/tools/misc/xen-cpuid.c
|
||||
@@ -154,6 +154,7 @@ static const char *str_7d0[32] =
|
||||
[ 2] = "avx512_4vnniw", [ 3] = "avx512_4fmaps",
|
||||
[ 4] = "fsrm",
|
||||
|
||||
+ /* 8 */ [ 9] = "srbds-ctrl",
|
||||
[10] = "md-clear",
|
||||
/* 12 */ [13] = "tsx-force-abort",
|
||||
|
||||
diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
|
||||
index 1727497459..22d8c71a95 100644
|
||||
--- a/xen/arch/x86/cpuid.c
|
||||
+++ b/xen/arch/x86/cpuid.c
|
||||
@@ -59,6 +59,11 @@ static int __init parse_xen_cpuid(const char *s)
|
||||
if ( !val )
|
||||
setup_clear_cpu_cap(X86_FEATURE_SSBD);
|
||||
}
|
||||
+ else if ( (val = parse_boolean("srbds-ctrl", s, ss)) >= 0 )
|
||||
+ {
|
||||
+ if ( !val )
|
||||
+ setup_clear_cpu_cap(X86_FEATURE_SRBDS_CTRL);
|
||||
+ }
|
||||
else
|
||||
rc = -EINVAL;
|
||||
|
||||
diff --git a/xen/arch/x86/msr.c b/xen/arch/x86/msr.c
|
||||
index 4888fff16c..9ff27b7007 100644
|
||||
--- a/xen/arch/x86/msr.c
|
||||
+++ b/xen/arch/x86/msr.c
|
||||
@@ -133,6 +133,7 @@ int guest_rdmsr(const struct vcpu *v, uint32_t msr, uint64_t *val)
|
||||
/* Write-only */
|
||||
case MSR_TSX_FORCE_ABORT:
|
||||
case MSR_TSX_CTRL:
|
||||
+ case MSR_MCU_OPT_CTRL:
|
||||
case MSR_U_CET:
|
||||
case MSR_S_CET:
|
||||
case MSR_PL0_SSP ... MSR_INTERRUPT_SSP_TABLE:
|
||||
@@ -273,6 +274,7 @@ int guest_wrmsr(struct vcpu *v, uint32_t msr, uint64_t val)
|
||||
/* Read-only */
|
||||
case MSR_TSX_FORCE_ABORT:
|
||||
case MSR_TSX_CTRL:
|
||||
+ case MSR_MCU_OPT_CTRL:
|
||||
case MSR_U_CET:
|
||||
case MSR_S_CET:
|
||||
case MSR_PL0_SSP ... MSR_INTERRUPT_SSP_TABLE:
|
||||
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
|
||||
index 800139d79c..5158e012ca 100644
|
||||
--- a/xen/arch/x86/spec_ctrl.c
|
||||
+++ b/xen/arch/x86/spec_ctrl.c
|
||||
@@ -309,12 +309,13 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
|
||||
printk("Speculative mitigation facilities:\n");
|
||||
|
||||
/* Hardware features which pertain to speculative mitigations. */
|
||||
- printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
|
||||
+ printk(" Hardware features:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
|
||||
(_7d0 & cpufeat_mask(X86_FEATURE_IBRSB)) ? " IBRS/IBPB" : "",
|
||||
(_7d0 & cpufeat_mask(X86_FEATURE_STIBP)) ? " STIBP" : "",
|
||||
(_7d0 & cpufeat_mask(X86_FEATURE_L1D_FLUSH)) ? " L1D_FLUSH" : "",
|
||||
(_7d0 & cpufeat_mask(X86_FEATURE_SSBD)) ? " SSBD" : "",
|
||||
(_7d0 & cpufeat_mask(X86_FEATURE_MD_CLEAR)) ? " MD_CLEAR" : "",
|
||||
+ (_7d0 & cpufeat_mask(X86_FEATURE_SRBDS_CTRL)) ? " SRBDS_CTRL" : "",
|
||||
(e8b & cpufeat_mask(X86_FEATURE_IBPB)) ? " IBPB" : "",
|
||||
(caps & ARCH_CAPS_IBRS_ALL) ? " IBRS_ALL" : "",
|
||||
(caps & ARCH_CAPS_RDCL_NO) ? " RDCL_NO" : "",
|
||||
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
|
||||
index 7693c4a71a..91994669e1 100644
|
||||
--- a/xen/include/asm-x86/msr-index.h
|
||||
+++ b/xen/include/asm-x86/msr-index.h
|
||||
@@ -179,6 +179,9 @@
|
||||
#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x490
|
||||
#define MSR_IA32_VMX_VMFUNC 0x491
|
||||
|
||||
+#define MSR_MCU_OPT_CTRL 0x00000123
|
||||
+#define MCU_OPT_CTRL_RNGDS_MITG_DIS (_AC(1, ULL) << 0)
|
||||
+
|
||||
#define MSR_U_CET 0x000006a0
|
||||
#define MSR_S_CET 0x000006a2
|
||||
#define MSR_PL0_SSP 0x000006a4
|
||||
diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h
|
||||
index 865a435d2c..31490a7c10 100644
|
||||
--- a/xen/include/public/arch-x86/cpufeatureset.h
|
||||
+++ b/xen/include/public/arch-x86/cpufeatureset.h
|
||||
@@ -243,6 +243,7 @@ XEN_CPUFEATURE(IBPB, 8*32+12) /*A IBPB support only (no IBRS, used by
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0.edx, word 9 */
|
||||
XEN_CPUFEATURE(AVX512_4VNNIW, 9*32+ 2) /*A AVX512 Neural Network Instructions */
|
||||
XEN_CPUFEATURE(AVX512_4FMAPS, 9*32+ 3) /*A AVX512 Multiply Accumulation Single Precision */
|
||||
+XEN_CPUFEATURE(SRBDS_CTRL, 9*32+ 9) /* MSR_MCU_OPT_CTRL and RNGDS_MITG_DIS. */
|
||||
XEN_CPUFEATURE(MD_CLEAR, 9*32+10) /*A VERW clears microarchitectural buffers */
|
||||
XEN_CPUFEATURE(TSX_FORCE_ABORT, 9*32+13) /* MSR_TSX_FORCE_ABORT.RTM_ABORT */
|
||||
XEN_CPUFEATURE(CET_IBT, 9*32+20) /* CET - Indirect Branch Tracking */
|
||||
179
xsa320-4.12-2.patch
Normal file
179
xsa320-4.12-2.patch
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/spec-ctrl: Mitigate the Special Register Buffer Data Sampling sidechannel
|
||||
|
||||
See patch documentation and comments.
|
||||
|
||||
This is part of XSA-320 / CVE-2020-0543
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
|
||||
index dbdaee92dc..337fbf0492 100644
|
||||
--- a/docs/misc/xen-command-line.pandoc
|
||||
+++ b/docs/misc/xen-command-line.pandoc
|
||||
@@ -1909,7 +1909,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`).
|
||||
### spec-ctrl (x86)
|
||||
> `= List of [ <bool>, xen=<bool>, {pv,hvm,msr-sc,rsb,md-clear}=<bool>,
|
||||
> bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,eager-fpu,
|
||||
-> l1d-flush}=<bool> ]`
|
||||
+> l1d-flush,srb-lock}=<bool> ]`
|
||||
|
||||
Controls for speculative execution sidechannel mitigations. By default, Xen
|
||||
will pick the most appropriate mitigations based on compiled in support,
|
||||
@@ -1981,6 +1981,12 @@ Irrespective of Xen's setting, the feature is virtualised for HVM guests to
|
||||
use. By default, Xen will enable this mitigation on hardware believed to be
|
||||
vulnerable to L1TF.
|
||||
|
||||
+On hardware supporting SRBDS_CTRL, the `srb-lock=` option can be used to force
|
||||
+or prevent Xen from protect the Special Register Buffer from leaking stale
|
||||
+data. By default, Xen will enable this mitigation, except on parts where MDS
|
||||
+is fixed and TAA is fixed/mitigated (in which case, there is believed to be no
|
||||
+way for an attacker to obtain the stale data).
|
||||
+
|
||||
### sync_console
|
||||
> `= <boolean>`
|
||||
|
||||
diff --git a/xen/arch/x86/acpi/power.c b/xen/arch/x86/acpi/power.c
|
||||
index c1d772f63f..a07aa3b9ed 100644
|
||||
--- a/xen/arch/x86/acpi/power.c
|
||||
+++ b/xen/arch/x86/acpi/power.c
|
||||
@@ -266,6 +266,9 @@ static int enter_state(u32 state)
|
||||
ci->spec_ctrl_flags |= (default_spec_ctrl_flags & SCF_ist_wrmsr);
|
||||
spec_ctrl_exit_idle(ci);
|
||||
|
||||
+ if ( boot_cpu_has(X86_FEATURE_SRBDS_CTRL) )
|
||||
+ wrmsrl(MSR_MCU_OPT_CTRL, default_xen_mcu_opt_ctrl);
|
||||
+
|
||||
done:
|
||||
spin_debug_enable();
|
||||
local_irq_restore(flags);
|
||||
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
|
||||
index 699e21bfb7..b741d1354a 100644
|
||||
--- a/xen/arch/x86/smpboot.c
|
||||
+++ b/xen/arch/x86/smpboot.c
|
||||
@@ -369,12 +369,14 @@ void start_secondary(void *unused)
|
||||
microcode_resume_cpu(cpu);
|
||||
|
||||
/*
|
||||
- * If MSR_SPEC_CTRL is available, apply Xen's default setting and discard
|
||||
- * any firmware settings. Note: MSR_SPEC_CTRL may only become available
|
||||
- * after loading microcode.
|
||||
+ * If any speculative control MSRs are available, apply Xen's default
|
||||
+ * settings. Note: These MSRs may only become available after loading
|
||||
+ * microcode.
|
||||
*/
|
||||
if ( boot_cpu_has(X86_FEATURE_IBRSB) )
|
||||
wrmsrl(MSR_SPEC_CTRL, default_xen_spec_ctrl);
|
||||
+ if ( boot_cpu_has(X86_FEATURE_SRBDS_CTRL) )
|
||||
+ wrmsrl(MSR_MCU_OPT_CTRL, default_xen_mcu_opt_ctrl);
|
||||
|
||||
tsx_init(); /* Needs microcode. May change HLE/RTM feature bits. */
|
||||
|
||||
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
|
||||
index 5158e012ca..e2fcefc86a 100644
|
||||
--- a/xen/arch/x86/spec_ctrl.c
|
||||
+++ b/xen/arch/x86/spec_ctrl.c
|
||||
@@ -64,6 +64,9 @@ static unsigned int __initdata l1d_maxphysaddr;
|
||||
static bool __initdata cpu_has_bug_msbds_only; /* => minimal HT impact. */
|
||||
static bool __initdata cpu_has_bug_mds; /* Any other M{LP,SB,FB}DS combination. */
|
||||
|
||||
+static int8_t __initdata opt_srb_lock = -1;
|
||||
+uint64_t __read_mostly default_xen_mcu_opt_ctrl;
|
||||
+
|
||||
static int __init parse_spec_ctrl(const char *s)
|
||||
{
|
||||
const char *ss;
|
||||
@@ -110,6 +113,7 @@ static int __init parse_spec_ctrl(const char *s)
|
||||
opt_ibpb = false;
|
||||
opt_ssbd = false;
|
||||
opt_l1d_flush = 0;
|
||||
+ opt_srb_lock = 0;
|
||||
}
|
||||
else if ( val > 0 )
|
||||
rc = -EINVAL;
|
||||
@@ -175,6 +179,8 @@ static int __init parse_spec_ctrl(const char *s)
|
||||
opt_eager_fpu = val;
|
||||
else if ( (val = parse_boolean("l1d-flush", s, ss)) >= 0 )
|
||||
opt_l1d_flush = val;
|
||||
+ else if ( (val = parse_boolean("srb-lock", s, ss)) >= 0 )
|
||||
+ opt_srb_lock = val;
|
||||
else
|
||||
rc = -EINVAL;
|
||||
|
||||
@@ -338,7 +344,7 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
|
||||
"\n");
|
||||
|
||||
/* Settings for Xen's protection, irrespective of guests. */
|
||||
- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s, Other:%s%s%s\n",
|
||||
+ printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s, Other:%s%s%s%s\n",
|
||||
thunk == THUNK_NONE ? "N/A" :
|
||||
thunk == THUNK_RETPOLINE ? "RETPOLINE" :
|
||||
thunk == THUNK_LFENCE ? "LFENCE" :
|
||||
@@ -349,6 +355,8 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
|
||||
(default_xen_spec_ctrl & SPEC_CTRL_SSBD) ? " SSBD+" : " SSBD-",
|
||||
!(caps & ARCH_CAPS_TSX_CTRL) ? "" :
|
||||
(opt_tsx & 1) ? " TSX+" : " TSX-",
|
||||
+ !boot_cpu_has(X86_FEATURE_SRBDS_CTRL) ? "" :
|
||||
+ opt_srb_lock ? " SRB_LOCK+" : " SRB_LOCK-",
|
||||
opt_ibpb ? " IBPB" : "",
|
||||
opt_l1d_flush ? " L1D_FLUSH" : "",
|
||||
opt_md_clear_pv || opt_md_clear_hvm ? " VERW" : "");
|
||||
@@ -1142,6 +1150,34 @@ void __init init_speculation_mitigations(void)
|
||||
tsx_init();
|
||||
}
|
||||
|
||||
+ /* Calculate suitable defaults for MSR_MCU_OPT_CTRL */
|
||||
+ if ( boot_cpu_has(X86_FEATURE_SRBDS_CTRL) )
|
||||
+ {
|
||||
+ uint64_t val;
|
||||
+
|
||||
+ rdmsrl(MSR_MCU_OPT_CTRL, val);
|
||||
+
|
||||
+ /*
|
||||
+ * On some SRBDS-affected hardware, it may be safe to relax srb-lock
|
||||
+ * by default.
|
||||
+ *
|
||||
+ * On parts which enumerate MDS_NO and not TAA_NO, TSX is the only way
|
||||
+ * to access the Fill Buffer. If TSX isn't available (inc. SKU
|
||||
+ * reasons on some models), or TSX is explicitly disabled, then there
|
||||
+ * is no need for the extra overhead to protect RDRAND/RDSEED.
|
||||
+ */
|
||||
+ if ( opt_srb_lock == -1 &&
|
||||
+ (caps & (ARCH_CAPS_MDS_NO|ARCH_CAPS_TAA_NO)) == ARCH_CAPS_MDS_NO &&
|
||||
+ (!cpu_has_hle || ((caps & ARCH_CAPS_TSX_CTRL) && opt_tsx == 0)) )
|
||||
+ opt_srb_lock = 0;
|
||||
+
|
||||
+ val &= ~MCU_OPT_CTRL_RNGDS_MITG_DIS;
|
||||
+ if ( !opt_srb_lock )
|
||||
+ val |= MCU_OPT_CTRL_RNGDS_MITG_DIS;
|
||||
+
|
||||
+ default_xen_mcu_opt_ctrl = val;
|
||||
+ }
|
||||
+
|
||||
print_details(thunk, caps);
|
||||
|
||||
/*
|
||||
@@ -1173,6 +1209,9 @@ void __init init_speculation_mitigations(void)
|
||||
|
||||
wrmsrl(MSR_SPEC_CTRL, bsp_delay_spec_ctrl ? 0 : default_xen_spec_ctrl);
|
||||
}
|
||||
+
|
||||
+ if ( boot_cpu_has(X86_FEATURE_SRBDS_CTRL) )
|
||||
+ wrmsrl(MSR_MCU_OPT_CTRL, default_xen_mcu_opt_ctrl);
|
||||
}
|
||||
|
||||
static void __init __maybe_unused build_assertions(void)
|
||||
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
|
||||
index ba03bb42e5..59bab1a41b 100644
|
||||
--- a/xen/include/asm-x86/spec_ctrl.h
|
||||
+++ b/xen/include/asm-x86/spec_ctrl.h
|
||||
@@ -53,6 +53,8 @@ extern int8_t opt_pv_l1tf_hwdom, opt_pv_l1tf_domu;
|
||||
*/
|
||||
extern paddr_t l1tf_addr_mask, l1tf_safe_maddr;
|
||||
|
||||
+extern uint64_t default_xen_mcu_opt_ctrl;
|
||||
+
|
||||
static inline void init_shadow_spec_ctrl_state(void)
|
||||
{
|
||||
struct cpu_info *info = get_cpu_info();
|
||||
31
xsa321-4.12-1.patch
Normal file
31
xsa321-4.12-1.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: vtd: improve IOMMU TLB flush
|
||||
|
||||
Do not limit PSI flushes to order 0 pages, in order to avoid doing a
|
||||
full TLB flush if the passed in page has an order greater than 0 and
|
||||
is aligned. Should increase the performance of IOMMU TLB flushes when
|
||||
dealing with page orders greater than 0.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||||
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||||
@@ -611,13 +611,14 @@ static int __must_check iommu_flush_iotl
|
||||
if ( iommu_domid == -1 )
|
||||
continue;
|
||||
|
||||
- if ( page_count != 1 || dfn_eq(dfn, INVALID_DFN) )
|
||||
+ if ( !page_count || (page_count & (page_count - 1)) ||
|
||||
+ dfn_eq(dfn, INVALID_DFN) || !IS_ALIGNED(dfn_x(dfn), page_count) )
|
||||
rc = iommu_flush_iotlb_dsi(iommu, iommu_domid,
|
||||
0, flush_dev_iotlb);
|
||||
else
|
||||
rc = iommu_flush_iotlb_psi(iommu, iommu_domid,
|
||||
dfn_to_daddr(dfn),
|
||||
- PAGE_ORDER_4K,
|
||||
+ get_order_from_pages(page_count),
|
||||
!dma_old_pte_present,
|
||||
flush_dev_iotlb);
|
||||
|
||||
175
xsa321-4.12-2.patch
Normal file
175
xsa321-4.12-2.patch
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: vtd: prune (and rename) cache flush functions
|
||||
|
||||
Rename __iommu_flush_cache to iommu_sync_cache and remove
|
||||
iommu_flush_cache_page. Also remove the iommu_flush_cache_entry
|
||||
wrapper and just use iommu_sync_cache instead. Note the _entry suffix
|
||||
was meaningless as the wrapper was already taking a size parameter in
|
||||
bytes. While there also constify the addr parameter.
|
||||
|
||||
No functional change intended.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/extern.h
|
||||
+++ b/xen/drivers/passthrough/vtd/extern.h
|
||||
@@ -38,8 +38,7 @@ void disable_qinval(struct iommu *iommu)
|
||||
int enable_intremap(struct iommu *iommu, int eim);
|
||||
void disable_intremap(struct iommu *iommu);
|
||||
|
||||
-void iommu_flush_cache_entry(void *addr, unsigned int size);
|
||||
-void iommu_flush_cache_page(void *addr, unsigned long npages);
|
||||
+void iommu_sync_cache(const void *addr, unsigned int size);
|
||||
int iommu_alloc(struct acpi_drhd_unit *drhd);
|
||||
void iommu_free(struct acpi_drhd_unit *drhd);
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/intremap.c
|
||||
+++ b/xen/drivers/passthrough/vtd/intremap.c
|
||||
@@ -231,7 +231,7 @@ static void free_remap_entry(struct iomm
|
||||
iremap_entries, iremap_entry);
|
||||
|
||||
update_irte(iommu, iremap_entry, &new_ire, false);
|
||||
- iommu_flush_cache_entry(iremap_entry, sizeof(*iremap_entry));
|
||||
+ iommu_sync_cache(iremap_entry, sizeof(*iremap_entry));
|
||||
iommu_flush_iec_index(iommu, 0, index);
|
||||
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
@@ -403,7 +403,7 @@ static int ioapic_rte_to_remap_entry(str
|
||||
}
|
||||
|
||||
update_irte(iommu, iremap_entry, &new_ire, !init);
|
||||
- iommu_flush_cache_entry(iremap_entry, sizeof(*iremap_entry));
|
||||
+ iommu_sync_cache(iremap_entry, sizeof(*iremap_entry));
|
||||
iommu_flush_iec_index(iommu, 0, index);
|
||||
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
@@ -694,7 +694,7 @@ static int msi_msg_to_remap_entry(
|
||||
update_irte(iommu, iremap_entry, &new_ire, msi_desc->irte_initialized);
|
||||
msi_desc->irte_initialized = true;
|
||||
|
||||
- iommu_flush_cache_entry(iremap_entry, sizeof(*iremap_entry));
|
||||
+ iommu_sync_cache(iremap_entry, sizeof(*iremap_entry));
|
||||
iommu_flush_iec_index(iommu, 0, index);
|
||||
|
||||
unmap_vtd_domain_page(iremap_entries);
|
||||
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||||
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||||
@@ -158,7 +158,8 @@ static void __init free_intel_iommu(stru
|
||||
}
|
||||
|
||||
static int iommus_incoherent;
|
||||
-static void __iommu_flush_cache(void *addr, unsigned int size)
|
||||
+
|
||||
+void iommu_sync_cache(const void *addr, unsigned int size)
|
||||
{
|
||||
int i;
|
||||
static unsigned int clflush_size = 0;
|
||||
@@ -173,16 +174,6 @@ static void __iommu_flush_cache(void *ad
|
||||
cacheline_flush((char *)addr + i);
|
||||
}
|
||||
|
||||
-void iommu_flush_cache_entry(void *addr, unsigned int size)
|
||||
-{
|
||||
- __iommu_flush_cache(addr, size);
|
||||
-}
|
||||
-
|
||||
-void iommu_flush_cache_page(void *addr, unsigned long npages)
|
||||
-{
|
||||
- __iommu_flush_cache(addr, PAGE_SIZE * npages);
|
||||
-}
|
||||
-
|
||||
/* Allocate page table, return its machine address */
|
||||
u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages)
|
||||
{
|
||||
@@ -207,7 +198,7 @@ u64 alloc_pgtable_maddr(struct acpi_drhd
|
||||
vaddr = __map_domain_page(cur_pg);
|
||||
memset(vaddr, 0, PAGE_SIZE);
|
||||
|
||||
- iommu_flush_cache_page(vaddr, 1);
|
||||
+ iommu_sync_cache(vaddr, PAGE_SIZE);
|
||||
unmap_domain_page(vaddr);
|
||||
cur_pg++;
|
||||
}
|
||||
@@ -242,7 +233,7 @@ static u64 bus_to_context_maddr(struct i
|
||||
}
|
||||
set_root_value(*root, maddr);
|
||||
set_root_present(*root);
|
||||
- iommu_flush_cache_entry(root, sizeof(struct root_entry));
|
||||
+ iommu_sync_cache(root, sizeof(struct root_entry));
|
||||
}
|
||||
maddr = (u64) get_context_addr(*root);
|
||||
unmap_vtd_domain_page(root_entries);
|
||||
@@ -300,7 +291,7 @@ static u64 addr_to_dma_page_maddr(struct
|
||||
*/
|
||||
dma_set_pte_readable(*pte);
|
||||
dma_set_pte_writable(*pte);
|
||||
- iommu_flush_cache_entry(pte, sizeof(struct dma_pte));
|
||||
+ iommu_sync_cache(pte, sizeof(struct dma_pte));
|
||||
}
|
||||
|
||||
if ( level == 2 )
|
||||
@@ -681,7 +672,7 @@ static int __must_check dma_pte_clear_on
|
||||
*flush_flags |= IOMMU_FLUSHF_modified;
|
||||
|
||||
spin_unlock(&hd->arch.mapping_lock);
|
||||
- iommu_flush_cache_entry(pte, sizeof(struct dma_pte));
|
||||
+ iommu_sync_cache(pte, sizeof(struct dma_pte));
|
||||
|
||||
unmap_vtd_domain_page(page);
|
||||
|
||||
@@ -720,7 +711,7 @@ static void iommu_free_page_table(struct
|
||||
iommu_free_pagetable(dma_pte_addr(*pte), next_level);
|
||||
|
||||
dma_clear_pte(*pte);
|
||||
- iommu_flush_cache_entry(pte, sizeof(struct dma_pte));
|
||||
+ iommu_sync_cache(pte, sizeof(struct dma_pte));
|
||||
}
|
||||
|
||||
unmap_vtd_domain_page(pt_vaddr);
|
||||
@@ -1449,7 +1440,7 @@ int domain_context_mapping_one(
|
||||
context_set_address_width(*context, agaw);
|
||||
context_set_fault_enable(*context);
|
||||
context_set_present(*context);
|
||||
- iommu_flush_cache_entry(context, sizeof(struct context_entry));
|
||||
+ iommu_sync_cache(context, sizeof(struct context_entry));
|
||||
spin_unlock(&iommu->lock);
|
||||
|
||||
/* Context entry was previously non-present (with domid 0). */
|
||||
@@ -1602,7 +1593,7 @@ int domain_context_unmap_one(
|
||||
|
||||
context_clear_present(*context);
|
||||
context_clear_entry(*context);
|
||||
- iommu_flush_cache_entry(context, sizeof(struct context_entry));
|
||||
+ iommu_sync_cache(context, sizeof(struct context_entry));
|
||||
|
||||
iommu_domid= domain_iommu_domid(domain, iommu);
|
||||
if ( iommu_domid == -1 )
|
||||
@@ -1837,7 +1828,7 @@ static int __must_check intel_iommu_map_
|
||||
|
||||
*pte = new;
|
||||
|
||||
- iommu_flush_cache_entry(pte, sizeof(struct dma_pte));
|
||||
+ iommu_sync_cache(pte, sizeof(struct dma_pte));
|
||||
spin_unlock(&hd->arch.mapping_lock);
|
||||
unmap_vtd_domain_page(page);
|
||||
|
||||
@@ -1912,7 +1903,7 @@ int iommu_pte_flush(struct domain *d, ui
|
||||
int iommu_domid;
|
||||
int rc = 0;
|
||||
|
||||
- iommu_flush_cache_entry(pte, sizeof(struct dma_pte));
|
||||
+ iommu_sync_cache(pte, sizeof(struct dma_pte));
|
||||
|
||||
for_each_drhd_unit ( drhd )
|
||||
{
|
||||
@@ -2777,7 +2768,7 @@ static int __init intel_iommu_quarantine
|
||||
dma_set_pte_addr(*pte, maddr);
|
||||
dma_set_pte_readable(*pte);
|
||||
}
|
||||
- iommu_flush_cache_page(parent, 1);
|
||||
+ iommu_sync_cache(parent, PAGE_SIZE);
|
||||
|
||||
unmap_vtd_domain_page(parent);
|
||||
parent = map_vtd_domain_page(maddr);
|
||||
82
xsa321-4.12-3.patch
Normal file
82
xsa321-4.12-3.patch
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: x86/iommu: introduce a cache sync hook
|
||||
|
||||
The hook is only implemented for VT-d and it uses the already existing
|
||||
iommu_sync_cache function present in VT-d code. The new hook is
|
||||
added so that the cache can be flushed by code outside of VT-d when
|
||||
using shared page tables.
|
||||
|
||||
Note that alloc_pgtable_maddr must use the now locally defined
|
||||
sync_cache function, because IOMMU ops are not yet setup the first
|
||||
time the function gets called during IOMMU initialization.
|
||||
|
||||
No functional change intended.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/extern.h
|
||||
+++ b/xen/drivers/passthrough/vtd/extern.h
|
||||
@@ -38,7 +38,6 @@ void disable_qinval(struct iommu *iommu)
|
||||
int enable_intremap(struct iommu *iommu, int eim);
|
||||
void disable_intremap(struct iommu *iommu);
|
||||
|
||||
-void iommu_sync_cache(const void *addr, unsigned int size);
|
||||
int iommu_alloc(struct acpi_drhd_unit *drhd);
|
||||
void iommu_free(struct acpi_drhd_unit *drhd);
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||||
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||||
@@ -159,7 +159,7 @@ static void __init free_intel_iommu(stru
|
||||
|
||||
static int iommus_incoherent;
|
||||
|
||||
-void iommu_sync_cache(const void *addr, unsigned int size)
|
||||
+static void sync_cache(const void *addr, unsigned int size)
|
||||
{
|
||||
int i;
|
||||
static unsigned int clflush_size = 0;
|
||||
@@ -198,7 +198,7 @@ u64 alloc_pgtable_maddr(struct acpi_drhd
|
||||
vaddr = __map_domain_page(cur_pg);
|
||||
memset(vaddr, 0, PAGE_SIZE);
|
||||
|
||||
- iommu_sync_cache(vaddr, PAGE_SIZE);
|
||||
+ sync_cache(vaddr, PAGE_SIZE);
|
||||
unmap_domain_page(vaddr);
|
||||
cur_pg++;
|
||||
}
|
||||
@@ -2813,6 +2813,7 @@ const struct iommu_ops __initconstrel in
|
||||
.iotlb_flush_all = iommu_flush_iotlb_all,
|
||||
.get_reserved_device_memory = intel_iommu_get_reserved_device_memory,
|
||||
.dump_p2m_table = vtd_dump_p2m_table,
|
||||
+ .sync_cache = sync_cache,
|
||||
};
|
||||
|
||||
/*
|
||||
--- a/xen/include/asm-x86/iommu.h
|
||||
+++ b/xen/include/asm-x86/iommu.h
|
||||
@@ -101,6 +101,13 @@ extern bool untrusted_msi;
|
||||
int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq,
|
||||
const uint8_t gvec);
|
||||
|
||||
+#define iommu_sync_cache(addr, size) ({ \
|
||||
+ const struct iommu_ops *ops = iommu_get_ops(); \
|
||||
+ \
|
||||
+ if ( ops->sync_cache ) \
|
||||
+ ops->sync_cache(addr, size); \
|
||||
+})
|
||||
+
|
||||
#endif /* !__ARCH_X86_IOMMU_H__ */
|
||||
/*
|
||||
* Local variables:
|
||||
--- a/xen/include/xen/iommu.h
|
||||
+++ b/xen/include/xen/iommu.h
|
||||
@@ -221,6 +221,7 @@ struct iommu_ops {
|
||||
void (*update_ire_from_apic)(unsigned int apic, unsigned int reg, unsigned int value);
|
||||
unsigned int (*read_apic_from_ire)(unsigned int apic, unsigned int reg);
|
||||
int (*setup_hpet_msi)(struct msi_desc *);
|
||||
+ void (*sync_cache)(const void *addr, unsigned int size);
|
||||
#endif /* CONFIG_X86 */
|
||||
int __must_check (*suspend)(void);
|
||||
void (*resume)(void);
|
||||
36
xsa321-4.12-4.patch
Normal file
36
xsa321-4.12-4.patch
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: vtd: don't assume addresses are aligned in sync_cache
|
||||
|
||||
Current code in sync_cache assume that the address passed in is
|
||||
aligned to a cache line size. Fix the code to support passing in
|
||||
arbitrary addresses not necessarily aligned to a cache line size.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||||
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||||
@@ -161,8 +161,8 @@ static int iommus_incoherent;
|
||||
|
||||
static void sync_cache(const void *addr, unsigned int size)
|
||||
{
|
||||
- int i;
|
||||
- static unsigned int clflush_size = 0;
|
||||
+ static unsigned long clflush_size = 0;
|
||||
+ const void *end = addr + size;
|
||||
|
||||
if ( !iommus_incoherent )
|
||||
return;
|
||||
@@ -170,8 +170,9 @@ static void sync_cache(const void *addr,
|
||||
if ( clflush_size == 0 )
|
||||
clflush_size = get_cache_line_size();
|
||||
|
||||
- for ( i = 0; i < size; i += clflush_size )
|
||||
- cacheline_flush((char *)addr + i);
|
||||
+ addr -= (unsigned long)addr & (clflush_size - 1);
|
||||
+ for ( ; addr < end; addr += clflush_size )
|
||||
+ cacheline_flush((char *)addr);
|
||||
}
|
||||
|
||||
/* Allocate page table, return its machine address */
|
||||
24
xsa321-4.12-5.patch
Normal file
24
xsa321-4.12-5.patch
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: x86/alternative: introduce alternative_2
|
||||
|
||||
It's based on alternative_io_2 without inputs or outputs but with an
|
||||
added memory clobber.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Acked-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/include/asm-x86/alternative.h
|
||||
+++ b/xen/include/asm-x86/alternative.h
|
||||
@@ -113,6 +113,11 @@ extern void alternative_instructions(voi
|
||||
#define alternative(oldinstr, newinstr, feature) \
|
||||
asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
|
||||
|
||||
+#define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
|
||||
+ asm volatile (ALTERNATIVE_2(oldinstr, newinstr1, feature1, \
|
||||
+ newinstr2, feature2) \
|
||||
+ : : : "memory")
|
||||
+
|
||||
/*
|
||||
* Alternative inline assembly with input.
|
||||
*
|
||||
91
xsa321-4.12-6.patch
Normal file
91
xsa321-4.12-6.patch
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: vtd: optimize CPU cache sync
|
||||
|
||||
Some VT-d IOMMUs are non-coherent, which requires a cache write back
|
||||
in order for the changes made by the CPU to be visible to the IOMMU.
|
||||
This cache write back was unconditionally done using clflush, but there are
|
||||
other more efficient instructions to do so, hence implement support
|
||||
for them using the alternative framework.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/drivers/passthrough/vtd/extern.h
|
||||
+++ b/xen/drivers/passthrough/vtd/extern.h
|
||||
@@ -64,7 +64,6 @@ int __must_check qinval_device_iotlb_syn
|
||||
u16 did, u16 size, u64 addr);
|
||||
|
||||
unsigned int get_cache_line_size(void);
|
||||
-void cacheline_flush(char *);
|
||||
void flush_all_cache(void);
|
||||
|
||||
u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages);
|
||||
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||||
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <xen/pci_regs.h>
|
||||
#include <xen/keyhandler.h>
|
||||
#include <asm/msi.h>
|
||||
+#include <asm/nops.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/hvm/vmx/vmx.h>
|
||||
#include <asm/p2m.h>
|
||||
@@ -172,7 +173,42 @@ static void sync_cache(const void *addr,
|
||||
|
||||
addr -= (unsigned long)addr & (clflush_size - 1);
|
||||
for ( ; addr < end; addr += clflush_size )
|
||||
- cacheline_flush((char *)addr);
|
||||
+/*
|
||||
+ * The arguments to a macro must not include preprocessor directives. Doing so
|
||||
+ * results in undefined behavior, so we have to create some defines here in
|
||||
+ * order to avoid it.
|
||||
+ */
|
||||
+#if defined(HAVE_AS_CLWB)
|
||||
+# define CLWB_ENCODING "clwb %[p]"
|
||||
+#elif defined(HAVE_AS_XSAVEOPT)
|
||||
+# define CLWB_ENCODING "data16 xsaveopt %[p]" /* clwb */
|
||||
+#else
|
||||
+# define CLWB_ENCODING ".byte 0x66, 0x0f, 0xae, 0x30" /* clwb (%%rax) */
|
||||
+#endif
|
||||
+
|
||||
+#define BASE_INPUT(addr) [p] "m" (*(const char *)(addr))
|
||||
+#if defined(HAVE_AS_CLWB) || defined(HAVE_AS_XSAVEOPT)
|
||||
+# define INPUT BASE_INPUT
|
||||
+#else
|
||||
+# define INPUT(addr) "a" (addr), BASE_INPUT(addr)
|
||||
+#endif
|
||||
+ /*
|
||||
+ * Note regarding the use of NOP_DS_PREFIX: it's faster to do a clflush
|
||||
+ * + prefix than a clflush + nop, and hence the prefix is added instead
|
||||
+ * of letting the alternative framework fill the gap by appending nops.
|
||||
+ */
|
||||
+ alternative_io_2(".byte " __stringify(NOP_DS_PREFIX) "; clflush %[p]",
|
||||
+ "data16 clflush %[p]", /* clflushopt */
|
||||
+ X86_FEATURE_CLFLUSHOPT,
|
||||
+ CLWB_ENCODING,
|
||||
+ X86_FEATURE_CLWB, /* no outputs */,
|
||||
+ INPUT(addr));
|
||||
+#undef INPUT
|
||||
+#undef BASE_INPUT
|
||||
+#undef CLWB_ENCODING
|
||||
+
|
||||
+ alternative_2("", "sfence", X86_FEATURE_CLFLUSHOPT,
|
||||
+ "sfence", X86_FEATURE_CLWB);
|
||||
}
|
||||
|
||||
/* Allocate page table, return its machine address */
|
||||
--- a/xen/drivers/passthrough/vtd/x86/vtd.c
|
||||
+++ b/xen/drivers/passthrough/vtd/x86/vtd.c
|
||||
@@ -51,11 +51,6 @@ unsigned int get_cache_line_size(void)
|
||||
return ((cpuid_ebx(1) >> 8) & 0xff) * 8;
|
||||
}
|
||||
|
||||
-void cacheline_flush(char * addr)
|
||||
-{
|
||||
- clflush(addr);
|
||||
-}
|
||||
-
|
||||
void flush_all_cache()
|
||||
{
|
||||
wbinvd();
|
||||
151
xsa321-4.12-7.patch
Normal file
151
xsa321-4.12-7.patch
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: x86/ept: flush cache when modifying PTEs and sharing page tables
|
||||
|
||||
Modifications made to the page tables by EPT code need to be written
|
||||
to memory when the page tables are shared with the IOMMU, as Intel
|
||||
IOMMUs can be non-coherent and thus require changes to be written to
|
||||
memory in order to be visible to the IOMMU.
|
||||
|
||||
In order to achieve this make sure data is written back to memory
|
||||
after writing an EPT entry when the recalc bit is not set in
|
||||
atomic_write_ept_entry. If such bit is set, the entry will be
|
||||
adjusted and atomic_write_ept_entry will be called a second time
|
||||
without the recalc bit set. Note that when splitting a super page the
|
||||
new tables resulting of the split should also be written back.
|
||||
|
||||
Failure to do so can allow devices behind the IOMMU access to the
|
||||
stale super page, or cause coherency issues as changes made by the
|
||||
processor to the page tables are not visible to the IOMMU.
|
||||
|
||||
This allows to remove the VT-d specific iommu_pte_flush helper, since
|
||||
the cache write back is now performed by atomic_write_ept_entry, and
|
||||
hence iommu_iotlb_flush can be used to flush the IOMMU TLB. The newly
|
||||
used method (iommu_iotlb_flush) can result in less flushes, since it
|
||||
might sometimes be called rightly with 0 flags, in which case it
|
||||
becomes a no-op.
|
||||
|
||||
This is part of XSA-321.
|
||||
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/arch/x86/mm/p2m-ept.c
|
||||
+++ b/xen/arch/x86/mm/p2m-ept.c
|
||||
@@ -58,6 +58,19 @@ static int atomic_write_ept_entry(struct
|
||||
|
||||
write_atomic(&entryptr->epte, new.epte);
|
||||
|
||||
+ /*
|
||||
+ * The recalc field on the EPT is used to signal either that a
|
||||
+ * recalculation of the EMT field is required (which doesn't effect the
|
||||
+ * IOMMU), or a type change. Type changes can only be between ram_rw,
|
||||
+ * logdirty and ioreq_server: changes to/from logdirty won't work well with
|
||||
+ * an IOMMU anyway, as IOMMU #PFs are not synchronous and will lead to
|
||||
+ * aborts, and changes to/from ioreq_server are already fully flushed
|
||||
+ * before returning to guest context (see
|
||||
+ * XEN_DMOP_map_mem_type_to_ioreq_server).
|
||||
+ */
|
||||
+ if ( !new.recalc && iommu_use_hap_pt(p2m->domain) )
|
||||
+ iommu_sync_cache(entryptr, sizeof(*entryptr));
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -278,6 +291,9 @@ static bool_t ept_split_super_page(struc
|
||||
break;
|
||||
}
|
||||
|
||||
+ if ( iommu_use_hap_pt(p2m->domain) )
|
||||
+ iommu_sync_cache(table, EPT_PAGETABLE_ENTRIES * sizeof(ept_entry_t));
|
||||
+
|
||||
unmap_domain_page(table);
|
||||
|
||||
/* Even failed we should install the newly allocated ept page. */
|
||||
@@ -337,6 +353,9 @@ static int ept_next_level(struct p2m_dom
|
||||
if ( !next )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
|
||||
+ if ( iommu_use_hap_pt(p2m->domain) )
|
||||
+ iommu_sync_cache(next, EPT_PAGETABLE_ENTRIES * sizeof(ept_entry_t));
|
||||
+
|
||||
rc = atomic_write_ept_entry(p2m, ept_entry, e, next_level);
|
||||
ASSERT(rc == 0);
|
||||
}
|
||||
@@ -815,7 +834,10 @@ out:
|
||||
need_modify_vtd_table )
|
||||
{
|
||||
if ( iommu_use_hap_pt(d) )
|
||||
- rc = iommu_pte_flush(d, gfn, &ept_entry->epte, order, vtd_pte_present);
|
||||
+ rc = iommu_iotlb_flush(d, _dfn(gfn), (1u << order),
|
||||
+ (iommu_flags ? IOMMU_FLUSHF_added : 0) |
|
||||
+ (vtd_pte_present ? IOMMU_FLUSHF_modified
|
||||
+ : 0));
|
||||
else if ( need_iommu_pt_sync(d) )
|
||||
rc = iommu_flags ?
|
||||
iommu_legacy_map(d, _dfn(gfn), mfn, order, iommu_flags) :
|
||||
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||||
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||||
@@ -1930,53 +1930,6 @@ static int intel_iommu_lookup_page(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int iommu_pte_flush(struct domain *d, uint64_t dfn, uint64_t *pte,
|
||||
- int order, int present)
|
||||
-{
|
||||
- struct acpi_drhd_unit *drhd;
|
||||
- struct iommu *iommu = NULL;
|
||||
- struct domain_iommu *hd = dom_iommu(d);
|
||||
- bool_t flush_dev_iotlb;
|
||||
- int iommu_domid;
|
||||
- int rc = 0;
|
||||
-
|
||||
- iommu_sync_cache(pte, sizeof(struct dma_pte));
|
||||
-
|
||||
- for_each_drhd_unit ( drhd )
|
||||
- {
|
||||
- iommu = drhd->iommu;
|
||||
- if ( !test_bit(iommu->index, &hd->arch.iommu_bitmap) )
|
||||
- continue;
|
||||
-
|
||||
- flush_dev_iotlb = !!find_ats_dev_drhd(iommu);
|
||||
- iommu_domid= domain_iommu_domid(d, iommu);
|
||||
- if ( iommu_domid == -1 )
|
||||
- continue;
|
||||
-
|
||||
- rc = iommu_flush_iotlb_psi(iommu, iommu_domid,
|
||||
- __dfn_to_daddr(dfn),
|
||||
- order, !present, flush_dev_iotlb);
|
||||
- if ( rc > 0 )
|
||||
- {
|
||||
- iommu_flush_write_buffer(iommu);
|
||||
- rc = 0;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if ( unlikely(rc) )
|
||||
- {
|
||||
- if ( !d->is_shutting_down && printk_ratelimit() )
|
||||
- printk(XENLOG_ERR VTDPREFIX
|
||||
- " d%d: IOMMU pages flush failed: %d\n",
|
||||
- d->domain_id, rc);
|
||||
-
|
||||
- if ( !is_hardware_domain(d) )
|
||||
- domain_crash(d);
|
||||
- }
|
||||
-
|
||||
- return rc;
|
||||
-}
|
||||
-
|
||||
static int __init vtd_ept_page_compatible(struct iommu *iommu)
|
||||
{
|
||||
u64 ept_cap, vtd_cap = iommu->cap;
|
||||
--- a/xen/include/asm-x86/iommu.h
|
||||
+++ b/xen/include/asm-x86/iommu.h
|
||||
@@ -90,8 +90,6 @@ int iommu_setup_hpet_msi(struct msi_desc
|
||||
|
||||
/* While VT-d specific, this must get declared in a generic header. */
|
||||
int adjust_vtd_irq_affinities(void);
|
||||
-int __must_check iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte,
|
||||
- int order, int present);
|
||||
bool_t iommu_supports_eim(void);
|
||||
int iommu_enable_x2apic_IR(void);
|
||||
void iommu_disable_x2apic_IR(void);
|
||||
63
xsa327.patch
Normal file
63
xsa327.patch
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
From 030300ebbb86c40c12db038714479d746167c767 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Grall <jgrall@amazon.com>
|
||||
Date: Tue, 26 May 2020 18:31:33 +0100
|
||||
Subject: [PATCH] xen: Check the alignment of the offset pased via
|
||||
VCPUOP_register_vcpu_info
|
||||
|
||||
Currently a guest is able to register any guest physical address to use
|
||||
for the vcpu_info structure as long as the structure can fits in the
|
||||
rest of the frame.
|
||||
|
||||
This means a guest can provide an address that is not aligned to the
|
||||
natural alignment of the structure.
|
||||
|
||||
On Arm 32-bit, unaligned access are completely forbidden by the
|
||||
hypervisor. This will result to a data abort which is fatal.
|
||||
|
||||
On Arm 64-bit, unaligned access are only forbidden when used for atomic
|
||||
access. As the structure contains fields (such as evtchn_pending_self)
|
||||
that are updated using atomic operations, any unaligned access will be
|
||||
fatal as well.
|
||||
|
||||
While the misalignment is only fatal on Arm, a generic check is added
|
||||
as an x86 guest shouldn't sensibly pass an unaligned address (this
|
||||
would result to a split lock).
|
||||
|
||||
This is XSA-327.
|
||||
|
||||
Reported-by: Julien Grall <jgrall@amazon.com>
|
||||
Signed-off-by: Julien Grall <jgrall@amazon.com>
|
||||
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
---
|
||||
xen/common/domain.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/xen/common/domain.c b/xen/common/domain.c
|
||||
index 7cc9526139a6..e9be05f1d05f 100644
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -1227,10 +1227,20 @@ int map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
|
||||
void *mapping;
|
||||
vcpu_info_t *new_info;
|
||||
struct page_info *page;
|
||||
+ unsigned int align;
|
||||
|
||||
if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
|
||||
return -EINVAL;
|
||||
|
||||
+#ifdef CONFIG_COMPAT
|
||||
+ if ( has_32bit_shinfo(d) )
|
||||
+ align = alignof(new_info->compat);
|
||||
+ else
|
||||
+#endif
|
||||
+ align = alignof(*new_info);
|
||||
+ if ( offset & (align - 1) )
|
||||
+ return -EINVAL;
|
||||
+
|
||||
if ( !mfn_eq(v->vcpu_info_mfn, INVALID_MFN) )
|
||||
return -EINVAL;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
||||
118
xsa328-4.12-1.patch
Normal file
118
xsa328-4.12-1.patch
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/EPT: ept_set_middle_entry() related adjustments
|
||||
|
||||
ept_split_super_page() wants to further modify the newly allocated
|
||||
table, so have ept_set_middle_entry() return the mapped pointer rather
|
||||
than tearing it down and then getting re-established right again.
|
||||
|
||||
Similarly ept_next_level() wants to hand back a mapped pointer of
|
||||
the next level page, so re-use the one established by
|
||||
ept_set_middle_entry() in case that path was taken.
|
||||
|
||||
Pull the setting of suppress_ve ahead of insertion into the higher level
|
||||
table, and don't have ept_split_super_page() set the field a 2nd time.
|
||||
|
||||
This is part of XSA-328.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/arch/x86/mm/p2m-ept.c
|
||||
+++ b/xen/arch/x86/mm/p2m-ept.c
|
||||
@@ -187,8 +187,9 @@ static void ept_p2m_type_to_flags(struct
|
||||
#define GUEST_TABLE_SUPER_PAGE 2
|
||||
#define GUEST_TABLE_POD_PAGE 3
|
||||
|
||||
-/* Fill in middle levels of ept table */
|
||||
-static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry)
|
||||
+/* Fill in middle level of ept table; return pointer to mapped new table. */
|
||||
+static ept_entry_t *ept_set_middle_entry(struct p2m_domain *p2m,
|
||||
+ ept_entry_t *ept_entry)
|
||||
{
|
||||
mfn_t mfn;
|
||||
ept_entry_t *table;
|
||||
@@ -196,7 +197,12 @@ static int ept_set_middle_entry(struct p
|
||||
|
||||
mfn = p2m_alloc_ptp(p2m, 0);
|
||||
if ( mfn_eq(mfn, INVALID_MFN) )
|
||||
- return 0;
|
||||
+ return NULL;
|
||||
+
|
||||
+ table = map_domain_page(mfn);
|
||||
+
|
||||
+ for ( i = 0; i < EPT_PAGETABLE_ENTRIES; i++ )
|
||||
+ table[i].suppress_ve = 1;
|
||||
|
||||
ept_entry->epte = 0;
|
||||
ept_entry->mfn = mfn_x(mfn);
|
||||
@@ -208,14 +214,7 @@ static int ept_set_middle_entry(struct p
|
||||
|
||||
ept_entry->suppress_ve = 1;
|
||||
|
||||
- table = map_domain_page(mfn);
|
||||
-
|
||||
- for ( i = 0; i < EPT_PAGETABLE_ENTRIES; i++ )
|
||||
- table[i].suppress_ve = 1;
|
||||
-
|
||||
- unmap_domain_page(table);
|
||||
-
|
||||
- return 1;
|
||||
+ return table;
|
||||
}
|
||||
|
||||
/* free ept sub tree behind an entry */
|
||||
@@ -253,10 +252,10 @@ static bool_t ept_split_super_page(struc
|
||||
|
||||
ASSERT(is_epte_superpage(ept_entry));
|
||||
|
||||
- if ( !ept_set_middle_entry(p2m, &new_ept) )
|
||||
+ table = ept_set_middle_entry(p2m, &new_ept);
|
||||
+ if ( !table )
|
||||
return 0;
|
||||
|
||||
- table = map_domain_page(_mfn(new_ept.mfn));
|
||||
trunk = 1UL << ((level - 1) * EPT_TABLE_ORDER);
|
||||
|
||||
for ( i = 0; i < EPT_PAGETABLE_ENTRIES; i++ )
|
||||
@@ -267,7 +266,6 @@ static bool_t ept_split_super_page(struc
|
||||
epte->sp = (level > 1);
|
||||
epte->mfn += i * trunk;
|
||||
epte->snp = (iommu_enabled && iommu_snoop);
|
||||
- epte->suppress_ve = 1;
|
||||
|
||||
ept_p2m_type_to_flags(p2m, epte, epte->sa_p2mt, epte->access);
|
||||
|
||||
@@ -306,8 +304,7 @@ static int ept_next_level(struct p2m_dom
|
||||
ept_entry_t **table, unsigned long *gfn_remainder,
|
||||
int next_level)
|
||||
{
|
||||
- unsigned long mfn;
|
||||
- ept_entry_t *ept_entry, e;
|
||||
+ ept_entry_t *ept_entry, *next = NULL, e;
|
||||
u32 shift, index;
|
||||
|
||||
shift = next_level * EPT_TABLE_ORDER;
|
||||
@@ -332,19 +329,17 @@ static int ept_next_level(struct p2m_dom
|
||||
if ( read_only )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
|
||||
- if ( !ept_set_middle_entry(p2m, ept_entry) )
|
||||
+ next = ept_set_middle_entry(p2m, ept_entry);
|
||||
+ if ( !next )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
- else
|
||||
- e = atomic_read_ept_entry(ept_entry); /* Refresh */
|
||||
+ /* e is now stale and hence may not be used anymore below. */
|
||||
}
|
||||
-
|
||||
/* The only time sp would be set here is if we had hit a superpage */
|
||||
- if ( is_epte_superpage(&e) )
|
||||
+ else if ( is_epte_superpage(&e) )
|
||||
return GUEST_TABLE_SUPER_PAGE;
|
||||
|
||||
- mfn = e.mfn;
|
||||
unmap_domain_page(*table);
|
||||
- *table = map_domain_page(_mfn(mfn));
|
||||
+ *table = next ?: map_domain_page(_mfn(e.mfn));
|
||||
*gfn_remainder &= (1UL << shift) - 1;
|
||||
return GUEST_TABLE_NORMAL_PAGE;
|
||||
}
|
||||
48
xsa328-4.12-2.patch
Normal file
48
xsa328-4.12-2.patch
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
From: <security@xenproject.org>
|
||||
Subject: x86/ept: atomically modify entries in ept_next_level
|
||||
|
||||
ept_next_level was passing a live PTE pointer to ept_set_middle_entry,
|
||||
which was then modified without taking into account that the PTE could
|
||||
be part of a live EPT table. This wasn't a security issue because the
|
||||
pages returned by p2m_alloc_ptp are zeroed, so adding such an entry
|
||||
before actually initializing it didn't allow a guest to access
|
||||
physical memory addresses it wasn't supposed to access.
|
||||
|
||||
This is part of XSA-328.
|
||||
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/arch/x86/mm/p2m-ept.c
|
||||
+++ b/xen/arch/x86/mm/p2m-ept.c
|
||||
@@ -307,6 +307,8 @@ static int ept_next_level(struct p2m_dom
|
||||
ept_entry_t *ept_entry, *next = NULL, e;
|
||||
u32 shift, index;
|
||||
|
||||
+ ASSERT(next_level);
|
||||
+
|
||||
shift = next_level * EPT_TABLE_ORDER;
|
||||
|
||||
index = *gfn_remainder >> shift;
|
||||
@@ -323,16 +325,20 @@ static int ept_next_level(struct p2m_dom
|
||||
|
||||
if ( !is_epte_present(&e) )
|
||||
{
|
||||
+ int rc;
|
||||
+
|
||||
if ( e.sa_p2mt == p2m_populate_on_demand )
|
||||
return GUEST_TABLE_POD_PAGE;
|
||||
|
||||
if ( read_only )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
|
||||
- next = ept_set_middle_entry(p2m, ept_entry);
|
||||
+ next = ept_set_middle_entry(p2m, &e);
|
||||
if ( !next )
|
||||
return GUEST_TABLE_MAP_FAILED;
|
||||
- /* e is now stale and hence may not be used anymore below. */
|
||||
+
|
||||
+ rc = atomic_write_ept_entry(p2m, ept_entry, e, next_level);
|
||||
+ ASSERT(rc == 0);
|
||||
}
|
||||
/* The only time sp would be set here is if we had hit a superpage */
|
||||
else if ( is_epte_superpage(&e) )
|
||||
39
xsa333.patch
Normal file
39
xsa333.patch
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/pv: Handle the Intel-specific MSR_MISC_ENABLE correctly
|
||||
|
||||
This MSR doesn't exist on AMD hardware, and switching away from the safe
|
||||
functions in the common MSR path was an erroneous change.
|
||||
|
||||
Partially revert the change.
|
||||
|
||||
This is XSA-333.
|
||||
|
||||
Fixes: 4fdc932b3cc ("x86/Intel: drop another 32-bit leftover")
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Wei Liu <wl@xen.org>
|
||||
|
||||
diff --git a/xen/arch/x86/pv/emul-priv-op.c b/xen/arch/x86/pv/emul-priv-op.c
|
||||
index efeb2a727e..6332c74b80 100644
|
||||
--- a/xen/arch/x86/pv/emul-priv-op.c
|
||||
+++ b/xen/arch/x86/pv/emul-priv-op.c
|
||||
@@ -924,7 +924,8 @@ static int read_msr(unsigned int reg, uint64_t *val,
|
||||
return X86EMUL_OKAY;
|
||||
|
||||
case MSR_IA32_MISC_ENABLE:
|
||||
- rdmsrl(reg, *val);
|
||||
+ if ( rdmsr_safe(reg, *val) )
|
||||
+ break;
|
||||
*val = guest_misc_enable(*val);
|
||||
return X86EMUL_OKAY;
|
||||
|
||||
@@ -1059,7 +1060,8 @@ static int write_msr(unsigned int reg, uint64_t val,
|
||||
break;
|
||||
|
||||
case MSR_IA32_MISC_ENABLE:
|
||||
- rdmsrl(reg, temp);
|
||||
+ if ( rdmsr_safe(reg, temp) )
|
||||
+ break;
|
||||
if ( val != guest_misc_enable(temp) )
|
||||
goto invalid;
|
||||
return X86EMUL_OKAY;
|
||||
57
xsa334-4.12.patch
Normal file
57
xsa334-4.12.patch
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: xen/memory: Don't skip the RCU unlock path in acquire_resource()
|
||||
|
||||
In the case that an HVM Stubdomain makes an XENMEM_acquire_resource hypercall,
|
||||
the FIXME path will bypass rcu_unlock_domain() on the way out of the function.
|
||||
|
||||
Move the check to the start of the function. This does change the behaviour
|
||||
of the get-size path for HVM Stubdomains, but that functionality is currently
|
||||
broken and unused anyway, as well as being quite useless to entities which
|
||||
can't actually map the resource anyway.
|
||||
|
||||
This is XSA-334.
|
||||
|
||||
Fixes: 83fa6552ce ("common: add a new mappable resource type: XENMEM_resource_grant_table")
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
Backport note: The deletion of the XENMEM_rsrc_acq_caller_owned clause is
|
||||
correct and intentional. This was an output-only flag who's use never
|
||||
survived into the Xen 4.12 release, and was subsequently deleted in Xen 4.13.
|
||||
|
||||
diff --git a/xen/common/memory.c b/xen/common/memory.c
|
||||
index dbc06fb0bf..ff88ebb314 100644
|
||||
--- a/xen/common/memory.c
|
||||
+++ b/xen/common/memory.c
|
||||
@@ -1059,6 +1059,14 @@ static int acquire_resource(
|
||||
xen_pfn_t mfn_list[32];
|
||||
int rc;
|
||||
|
||||
+ /*
|
||||
+ * FIXME: Until foreign pages inserted into the P2M are properly
|
||||
+ * reference counted, it is unsafe to allow mapping of
|
||||
+ * resource pages unless the caller is the hardware domain.
|
||||
+ */
|
||||
+ if ( paging_mode_translate(currd) && !is_hardware_domain(currd) )
|
||||
+ return -EACCES;
|
||||
+
|
||||
if ( copy_from_guest(&xmar, arg, 1) )
|
||||
return -EFAULT;
|
||||
|
||||
@@ -1115,16 +1123,6 @@ static int acquire_resource(
|
||||
xen_pfn_t gfn_list[ARRAY_SIZE(mfn_list)];
|
||||
unsigned int i;
|
||||
|
||||
- /*
|
||||
- * FIXME: Until foreign pages inserted into the P2M are properly
|
||||
- * reference counted, it is unsafe to allow mapping of
|
||||
- * non-caller-owned resource pages unless the caller is
|
||||
- * the hardware domain.
|
||||
- */
|
||||
- if ( !(xmar.flags & XENMEM_rsrc_acq_caller_owned) &&
|
||||
- !is_hardware_domain(currd) )
|
||||
- return -EACCES;
|
||||
-
|
||||
if ( copy_from_guest(gfn_list, xmar.frame_list, xmar.nr_frames) )
|
||||
rc = -EFAULT;
|
||||
|
||||
84
xsa335-qemu.patch
Normal file
84
xsa335-qemu.patch
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
From c5bd2924c6d6a5bcbffb8b5e7798a88970131c07 Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Mon, 17 Aug 2020 08:34:22 +0200
|
||||
Subject: [PATCH] usb: fix setup_len init (CVE-2020-14364)
|
||||
|
||||
Store calculated setup_len in a local variable, verify it, and only
|
||||
write it to the struct (USBDevice->setup_len) in case it passed the
|
||||
sanity checks.
|
||||
|
||||
This prevents other code (do_token_{in,out} functions specifically)
|
||||
from working with invalid USBDevice->setup_len values and overrunning
|
||||
the USBDevice->setup_buf[] buffer.
|
||||
|
||||
Fixes: CVE-2020-14364
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb/core.c | 16 ++++++++++------
|
||||
1 file changed, 10 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/hw/usb/core.c b/hw/usb/core.c
|
||||
index 5abd128b6bc5..5234dcc73fea 100644
|
||||
--- a/hw/usb/core.c
|
||||
+++ b/hw/usb/core.c
|
||||
@@ -129,6 +129,7 @@ void usb_wakeup(USBEndpoint *ep, unsigned int stream)
|
||||
static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
int request, value, index;
|
||||
+ unsigned int setup_len;
|
||||
|
||||
if (p->iov.size != 8) {
|
||||
p->status = USB_RET_STALL;
|
||||
@@ -138,14 +139,15 @@ static void do_token_setup(USBDevice *s, USBPacket *p)
|
||||
usb_packet_copy(p, s->setup_buf, p->iov.size);
|
||||
s->setup_index = 0;
|
||||
p->actual_length = 0;
|
||||
- s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
- if (s->setup_len > sizeof(s->data_buf)) {
|
||||
+ setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
+ if (setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
- s->setup_len, sizeof(s->data_buf));
|
||||
+ setup_len, sizeof(s->data_buf));
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
+ s->setup_len = setup_len;
|
||||
|
||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
@@ -259,26 +261,28 @@ static void do_token_out(USBDevice *s, USBPacket *p)
|
||||
static void do_parameter(USBDevice *s, USBPacket *p)
|
||||
{
|
||||
int i, request, value, index;
|
||||
+ unsigned int setup_len;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
s->setup_buf[i] = p->parameter >> (i*8);
|
||||
}
|
||||
|
||||
s->setup_state = SETUP_STATE_PARAM;
|
||||
- s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
s->setup_index = 0;
|
||||
|
||||
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
|
||||
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
|
||||
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
|
||||
|
||||
- if (s->setup_len > sizeof(s->data_buf)) {
|
||||
+ setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
|
||||
+ if (setup_len > sizeof(s->data_buf)) {
|
||||
fprintf(stderr,
|
||||
"usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n",
|
||||
- s->setup_len, sizeof(s->data_buf));
|
||||
+ setup_len, sizeof(s->data_buf));
|
||||
p->status = USB_RET_STALL;
|
||||
return;
|
||||
}
|
||||
+ s->setup_len = setup_len;
|
||||
|
||||
if (p->pid == USB_TOKEN_OUT) {
|
||||
usb_packet_copy(p, s->data_buf, s->setup_len);
|
||||
--
|
||||
2.18.4
|
||||
45
xsa335-trad.patch
Normal file
45
xsa335-trad.patch
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
From a62cdd675bc6a8053f6797b6add29b2853b081e3 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Jackson <ian.jackson@eu.citrix.com>
|
||||
Date: Wed, 19 Aug 2020 18:31:45 +0100
|
||||
Subject: [PATCH] SUPPORT.md: Desupport qemu trad except stub dm
|
||||
|
||||
While investigating XSA-335 we discovered that many upstream security
|
||||
fixes were missing. It is not practical to backport them. There is
|
||||
no good reason to be running this very ancient version of qemu, except
|
||||
that it is the only way to run a stub dm which is currently supported
|
||||
by upstream.
|
||||
|
||||
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
|
||||
---
|
||||
SUPPORT.md | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
diff --git a/SUPPORT.md b/SUPPORT.md
|
||||
index 1479055c45..b0939052e2 100644
|
||||
--- a/SUPPORT.md
|
||||
+++ b/SUPPORT.md
|
||||
@@ -758,6 +758,21 @@ See the section **Blkback** for image formats supported by QEMU.
|
||||
|
||||
Status: Supported, not security supported
|
||||
|
||||
+### qemu-xen-traditional ###
|
||||
+
|
||||
+The Xen Project provides an old version of qemu with modifications
|
||||
+which enable use as a device model stub domain. The old version is
|
||||
+normally selected by default only in a stub dm configuration, but it
|
||||
+can be requested explicitly in other configurations, for example in
|
||||
+`xl` with `device_model_version="QEMU_XEN_TRADITIONAL"`.
|
||||
+
|
||||
+ Status, Device Model Stub Domains: Supported, with caveats
|
||||
+ Status, as host process device model: No security support, not recommended
|
||||
+
|
||||
+qemu-xen-traditional is security supported only for those available
|
||||
+devices which are supported for mainstream QEMU (see above), with
|
||||
+trusted driver domains (see Device Model Stub Domains).
|
||||
+
|
||||
## Virtual Firmware
|
||||
|
||||
### x86/HVM iPXE
|
||||
--
|
||||
2.20.1
|
||||
|
||||
283
xsa336.patch
Normal file
283
xsa336.patch
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
From: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Subject: x86/vpt: fix race when migrating timers between vCPUs
|
||||
|
||||
The current vPT code will migrate the emulated timers between vCPUs
|
||||
(change the pt->vcpu field) while just holding the destination lock,
|
||||
either from create_periodic_time or pt_adjust_global_vcpu_target if
|
||||
the global target is adjusted. Changing the periodic_timer vCPU field
|
||||
in this way creates a race where a third party could grab the lock in
|
||||
the unlocked region of pt_adjust_global_vcpu_target (or before
|
||||
create_periodic_time performs the vcpu change) and then release the
|
||||
lock from a different vCPU, creating a locking imbalance.
|
||||
|
||||
Introduce a per-domain rwlock in order to protect periodic_time
|
||||
migration between vCPU lists. Taking the lock in read mode prevents
|
||||
any timer from being migrated to a different vCPU, while taking it in
|
||||
write mode allows performing migration of timers across vCPUs. The
|
||||
per-vcpu locks are still used to protect all the other fields from the
|
||||
periodic_timer struct.
|
||||
|
||||
Note that such migration shouldn't happen frequently, and hence
|
||||
there's no performance drop as a result of such locking.
|
||||
|
||||
This is XSA-336.
|
||||
|
||||
Reported-by: Igor Druzhinin <igor.druzhinin@citrix.com>
|
||||
Tested-by: Igor Druzhinin <igor.druzhinin@citrix.com>
|
||||
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
---
|
||||
Changes since v2:
|
||||
- Re-order pt_adjust_vcpu to remove one if.
|
||||
- Fix pt_lock to not call pt_vcpu_lock, as we might end up using a
|
||||
stale value of pt->vcpu when taking the per-vcpu lock.
|
||||
|
||||
Changes since v1:
|
||||
- Use a per-domain rwlock to protect timer vCPU migration.
|
||||
|
||||
--- a/xen/arch/x86/hvm/hvm.c
|
||||
+++ b/xen/arch/x86/hvm/hvm.c
|
||||
@@ -658,6 +658,8 @@ int hvm_domain_initialise(struct domain
|
||||
/* need link to containing domain */
|
||||
d->arch.hvm.pl_time->domain = d;
|
||||
|
||||
+ rwlock_init(&d->arch.hvm.pl_time->pt_migrate);
|
||||
+
|
||||
/* Set the default IO Bitmap. */
|
||||
if ( is_hardware_domain(d) )
|
||||
{
|
||||
--- a/xen/arch/x86/hvm/vpt.c
|
||||
+++ b/xen/arch/x86/hvm/vpt.c
|
||||
@@ -153,23 +153,32 @@ static int pt_irq_masked(struct periodic
|
||||
return 1;
|
||||
}
|
||||
|
||||
-static void pt_lock(struct periodic_time *pt)
|
||||
+static void pt_vcpu_lock(struct vcpu *v)
|
||||
{
|
||||
- struct vcpu *v;
|
||||
+ read_lock(&v->domain->arch.hvm.pl_time->pt_migrate);
|
||||
+ spin_lock(&v->arch.hvm.tm_lock);
|
||||
+}
|
||||
|
||||
- for ( ; ; )
|
||||
- {
|
||||
- v = pt->vcpu;
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
- if ( likely(pt->vcpu == v) )
|
||||
- break;
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
- }
|
||||
+static void pt_vcpu_unlock(struct vcpu *v)
|
||||
+{
|
||||
+ spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ read_unlock(&v->domain->arch.hvm.pl_time->pt_migrate);
|
||||
+}
|
||||
+
|
||||
+static void pt_lock(struct periodic_time *pt)
|
||||
+{
|
||||
+ /*
|
||||
+ * We cannot use pt_vcpu_lock here, because we need to acquire the
|
||||
+ * per-domain lock first and then (re-)fetch the value of pt->vcpu, or
|
||||
+ * else we might be using a stale value of pt->vcpu.
|
||||
+ */
|
||||
+ read_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate);
|
||||
+ spin_lock(&pt->vcpu->arch.hvm.tm_lock);
|
||||
}
|
||||
|
||||
static void pt_unlock(struct periodic_time *pt)
|
||||
{
|
||||
- spin_unlock(&pt->vcpu->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(pt->vcpu);
|
||||
}
|
||||
|
||||
static void pt_process_missed_ticks(struct periodic_time *pt)
|
||||
@@ -219,7 +228,7 @@ void pt_save_timer(struct vcpu *v)
|
||||
if ( v->pause_flags & VPF_blocked )
|
||||
return;
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_lock(v);
|
||||
|
||||
list_for_each_entry ( pt, head, list )
|
||||
if ( !pt->do_not_freeze )
|
||||
@@ -227,7 +236,7 @@ void pt_save_timer(struct vcpu *v)
|
||||
|
||||
pt_freeze_time(v);
|
||||
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
}
|
||||
|
||||
void pt_restore_timer(struct vcpu *v)
|
||||
@@ -235,7 +244,7 @@ void pt_restore_timer(struct vcpu *v)
|
||||
struct list_head *head = &v->arch.hvm.tm_list;
|
||||
struct periodic_time *pt;
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_lock(v);
|
||||
|
||||
list_for_each_entry ( pt, head, list )
|
||||
{
|
||||
@@ -248,7 +257,7 @@ void pt_restore_timer(struct vcpu *v)
|
||||
|
||||
pt_thaw_time(v);
|
||||
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
}
|
||||
|
||||
static void pt_timer_fn(void *data)
|
||||
@@ -309,7 +318,7 @@ int pt_update_irq(struct vcpu *v)
|
||||
int irq, pt_vector = -1;
|
||||
bool level;
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_lock(v);
|
||||
|
||||
earliest_pt = NULL;
|
||||
max_lag = -1ULL;
|
||||
@@ -339,7 +348,7 @@ int pt_update_irq(struct vcpu *v)
|
||||
|
||||
if ( earliest_pt == NULL )
|
||||
{
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -347,7 +356,7 @@ int pt_update_irq(struct vcpu *v)
|
||||
irq = earliest_pt->irq;
|
||||
level = earliest_pt->level;
|
||||
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
|
||||
switch ( earliest_pt->source )
|
||||
{
|
||||
@@ -394,7 +403,7 @@ int pt_update_irq(struct vcpu *v)
|
||||
time_cb *cb = NULL;
|
||||
void *cb_priv;
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_lock(v);
|
||||
/* Make sure the timer is still on the list. */
|
||||
list_for_each_entry ( pt, &v->arch.hvm.tm_list, list )
|
||||
if ( pt == earliest_pt )
|
||||
@@ -404,7 +413,7 @@ int pt_update_irq(struct vcpu *v)
|
||||
cb_priv = pt->priv;
|
||||
break;
|
||||
}
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
|
||||
if ( cb != NULL )
|
||||
cb(v, cb_priv);
|
||||
@@ -441,12 +450,12 @@ void pt_intr_post(struct vcpu *v, struct
|
||||
if ( intack.source == hvm_intsrc_vector )
|
||||
return;
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_lock(v);
|
||||
|
||||
pt = is_pt_irq(v, intack);
|
||||
if ( pt == NULL )
|
||||
{
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -455,7 +464,7 @@ void pt_intr_post(struct vcpu *v, struct
|
||||
cb = pt->cb;
|
||||
cb_priv = pt->priv;
|
||||
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
|
||||
if ( cb != NULL )
|
||||
cb(v, cb_priv);
|
||||
@@ -466,12 +475,12 @@ void pt_migrate(struct vcpu *v)
|
||||
struct list_head *head = &v->arch.hvm.tm_list;
|
||||
struct periodic_time *pt;
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_lock(v);
|
||||
|
||||
list_for_each_entry ( pt, head, list )
|
||||
migrate_timer(&pt->timer, v->processor);
|
||||
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ pt_vcpu_unlock(v);
|
||||
}
|
||||
|
||||
void create_periodic_time(
|
||||
@@ -490,7 +499,7 @@ void create_periodic_time(
|
||||
|
||||
destroy_periodic_time(pt);
|
||||
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ write_lock(&v->domain->arch.hvm.pl_time->pt_migrate);
|
||||
|
||||
pt->pending_intr_nr = 0;
|
||||
pt->do_not_freeze = 0;
|
||||
@@ -540,7 +549,7 @@ void create_periodic_time(
|
||||
init_timer(&pt->timer, pt_timer_fn, pt, v->processor);
|
||||
set_timer(&pt->timer, pt->scheduled);
|
||||
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ write_unlock(&v->domain->arch.hvm.pl_time->pt_migrate);
|
||||
}
|
||||
|
||||
void destroy_periodic_time(struct periodic_time *pt)
|
||||
@@ -565,30 +574,20 @@ void destroy_periodic_time(struct period
|
||||
|
||||
static void pt_adjust_vcpu(struct periodic_time *pt, struct vcpu *v)
|
||||
{
|
||||
- int on_list;
|
||||
-
|
||||
ASSERT(pt->source == PTSRC_isa || pt->source == PTSRC_ioapic);
|
||||
|
||||
if ( pt->vcpu == NULL )
|
||||
return;
|
||||
|
||||
- pt_lock(pt);
|
||||
- on_list = pt->on_list;
|
||||
- if ( pt->on_list )
|
||||
- list_del(&pt->list);
|
||||
- pt->on_list = 0;
|
||||
- pt_unlock(pt);
|
||||
-
|
||||
- spin_lock(&v->arch.hvm.tm_lock);
|
||||
+ write_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate);
|
||||
pt->vcpu = v;
|
||||
- if ( on_list )
|
||||
+ if ( pt->on_list )
|
||||
{
|
||||
- pt->on_list = 1;
|
||||
+ list_del(&pt->list);
|
||||
list_add(&pt->list, &v->arch.hvm.tm_list);
|
||||
-
|
||||
migrate_timer(&pt->timer, v->processor);
|
||||
}
|
||||
- spin_unlock(&v->arch.hvm.tm_lock);
|
||||
+ write_unlock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate);
|
||||
}
|
||||
|
||||
void pt_adjust_global_vcpu_target(struct vcpu *v)
|
||||
--- a/xen/include/asm-x86/hvm/vpt.h
|
||||
+++ b/xen/include/asm-x86/hvm/vpt.h
|
||||
@@ -128,6 +128,13 @@ struct pl_time { /* platform time */
|
||||
struct RTCState vrtc;
|
||||
struct HPETState vhpet;
|
||||
struct PMTState vpmt;
|
||||
+ /*
|
||||
+ * rwlock to prevent periodic_time vCPU migration. Take the lock in read
|
||||
+ * mode in order to prevent the vcpu field of periodic_time from changing.
|
||||
+ * Lock must be taken in write mode when changes to the vcpu field are
|
||||
+ * performed, as it allows exclusive access to all the timers of a domain.
|
||||
+ */
|
||||
+ rwlock_t pt_migrate;
|
||||
/* guest_time = Xen sys time + stime_offset */
|
||||
int64_t stime_offset;
|
||||
/* Ensures monotonicity in appropriate timer modes. */
|
||||
92
xsa337-4.12-1.patch
Normal file
92
xsa337-4.12-1.patch
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
From: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Subject: x86/msi: get rid of read_msi_msg
|
||||
|
||||
It's safer and faster to just use the cached last written
|
||||
(untranslated) MSI message stored in msi_desc for the single user that
|
||||
calls read_msi_msg.
|
||||
|
||||
This also prevents relying on the data read from the device MSI
|
||||
registers in order to figure out the index into the IOMMU interrupt
|
||||
remapping table, which is not safe.
|
||||
|
||||
This is part of XSA-337.
|
||||
|
||||
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Requested-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
--- a/xen/arch/x86/msi.c
|
||||
+++ b/xen/arch/x86/msi.c
|
||||
@@ -192,59 +192,6 @@ void msi_compose_msg(unsigned vector, co
|
||||
MSI_DATA_VECTOR(vector);
|
||||
}
|
||||
|
||||
-static bool read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
|
||||
-{
|
||||
- switch ( entry->msi_attrib.type )
|
||||
- {
|
||||
- case PCI_CAP_ID_MSI:
|
||||
- {
|
||||
- struct pci_dev *dev = entry->dev;
|
||||
- int pos = entry->msi_attrib.pos;
|
||||
- u16 data, seg = dev->seg;
|
||||
- u8 bus = dev->bus;
|
||||
- u8 slot = PCI_SLOT(dev->devfn);
|
||||
- u8 func = PCI_FUNC(dev->devfn);
|
||||
-
|
||||
- msg->address_lo = pci_conf_read32(seg, bus, slot, func,
|
||||
- msi_lower_address_reg(pos));
|
||||
- if ( entry->msi_attrib.is_64 )
|
||||
- {
|
||||
- msg->address_hi = pci_conf_read32(seg, bus, slot, func,
|
||||
- msi_upper_address_reg(pos));
|
||||
- data = pci_conf_read16(seg, bus, slot, func,
|
||||
- msi_data_reg(pos, 1));
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- msg->address_hi = 0;
|
||||
- data = pci_conf_read16(seg, bus, slot, func,
|
||||
- msi_data_reg(pos, 0));
|
||||
- }
|
||||
- msg->data = data;
|
||||
- break;
|
||||
- }
|
||||
- case PCI_CAP_ID_MSIX:
|
||||
- {
|
||||
- void __iomem *base = entry->mask_base;
|
||||
-
|
||||
- if ( unlikely(!msix_memory_decoded(entry->dev,
|
||||
- entry->msi_attrib.pos)) )
|
||||
- return false;
|
||||
- msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
|
||||
- msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
|
||||
- msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
|
||||
- break;
|
||||
- }
|
||||
- default:
|
||||
- BUG();
|
||||
- }
|
||||
-
|
||||
- if ( iommu_intremap )
|
||||
- iommu_read_msi_from_ire(entry, msg);
|
||||
-
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
static int write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
|
||||
{
|
||||
entry->msg = *msg;
|
||||
@@ -322,10 +269,7 @@ void set_msi_affinity(struct irq_desc *d
|
||||
|
||||
ASSERT(spin_is_locked(&desc->lock));
|
||||
|
||||
- memset(&msg, 0, sizeof(msg));
|
||||
- if ( !read_msi_msg(msi_desc, &msg) )
|
||||
- return;
|
||||
-
|
||||
+ msg = msi_desc->msg;
|
||||
msg.data &= ~MSI_DATA_VECTOR_MASK;
|
||||
msg.data |= MSI_DATA_VECTOR(desc->arch.vector);
|
||||
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
|
||||
182
xsa337-4.12-2.patch
Normal file
182
xsa337-4.12-2.patch
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/MSI-X: restrict reading of table/PBA bases from BARs
|
||||
|
||||
When assigned to less trusted or un-trusted guests, devices may change
|
||||
state behind our backs (they may e.g. get reset by means we may not know
|
||||
about). Therefore we should avoid reading BARs from hardware once a
|
||||
device is no longer owned by Dom0. Furthermore when we can't read a BAR,
|
||||
or when we read zero, we shouldn't instead use the caller provided
|
||||
address unless that caller can be trusted.
|
||||
|
||||
Re-arrange the logic in msix_capability_init() such that only Dom0 (and
|
||||
only if the device isn't DomU-owned yet) or calls through
|
||||
PHYSDEVOP_prepare_msix will actually result in the reading of the
|
||||
respective BAR register(s). Additionally do so only as long as in-use
|
||||
table entries are known (note that invocation of PHYSDEVOP_prepare_msix
|
||||
counts as a "pseudo" entry). In all other uses the value already
|
||||
recorded will get used instead.
|
||||
|
||||
Clear the recorded values in _pci_cleanup_msix() as well as on the one
|
||||
affected error path. (Adjust this error path to also avoid blindly
|
||||
disabling MSI-X when it was enabled on entry to the function.)
|
||||
|
||||
While moving around variable declarations (in many cases to reduce their
|
||||
scopes), also adjust some of their types.
|
||||
|
||||
This is part of XSA-337.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/x86/msi.c
|
||||
+++ b/xen/arch/x86/msi.c
|
||||
@@ -790,16 +790,14 @@ static int msix_capability_init(struct p
|
||||
{
|
||||
struct arch_msix *msix = dev->msix;
|
||||
struct msi_desc *entry = NULL;
|
||||
- int vf;
|
||||
u16 control;
|
||||
u64 table_paddr;
|
||||
u32 table_offset;
|
||||
- u8 bir, pbus, pslot, pfunc;
|
||||
u16 seg = dev->seg;
|
||||
u8 bus = dev->bus;
|
||||
u8 slot = PCI_SLOT(dev->devfn);
|
||||
u8 func = PCI_FUNC(dev->devfn);
|
||||
- bool maskall = msix->host_maskall;
|
||||
+ bool maskall = msix->host_maskall, zap_on_error = false;
|
||||
|
||||
ASSERT(pcidevs_locked());
|
||||
|
||||
@@ -837,43 +835,45 @@ static int msix_capability_init(struct p
|
||||
/* Locate MSI-X table region */
|
||||
table_offset = pci_conf_read32(seg, bus, slot, func,
|
||||
msix_table_offset_reg(pos));
|
||||
- bir = (u8)(table_offset & PCI_MSIX_BIRMASK);
|
||||
- table_offset &= ~PCI_MSIX_BIRMASK;
|
||||
+ if ( !msix->used_entries &&
|
||||
+ (!msi ||
|
||||
+ (is_hardware_domain(current->domain) &&
|
||||
+ (dev->domain == current->domain || dev->domain == dom_io))) )
|
||||
+ {
|
||||
+ unsigned int bir = table_offset & PCI_MSIX_BIRMASK, pbus, pslot, pfunc;
|
||||
+ int vf;
|
||||
+ paddr_t pba_paddr;
|
||||
+ unsigned int pba_offset;
|
||||
|
||||
- if ( !dev->info.is_virtfn )
|
||||
- {
|
||||
- pbus = bus;
|
||||
- pslot = slot;
|
||||
- pfunc = func;
|
||||
- vf = -1;
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- pbus = dev->info.physfn.bus;
|
||||
- pslot = PCI_SLOT(dev->info.physfn.devfn);
|
||||
- pfunc = PCI_FUNC(dev->info.physfn.devfn);
|
||||
- vf = PCI_BDF2(dev->bus, dev->devfn);
|
||||
- }
|
||||
-
|
||||
- table_paddr = read_pci_mem_bar(seg, pbus, pslot, pfunc, bir, vf);
|
||||
- WARN_ON(msi && msi->table_base != table_paddr);
|
||||
- if ( !table_paddr )
|
||||
- {
|
||||
- if ( !msi || !msi->table_base )
|
||||
+ if ( !dev->info.is_virtfn )
|
||||
{
|
||||
- pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos),
|
||||
- control & ~PCI_MSIX_FLAGS_ENABLE);
|
||||
- xfree(entry);
|
||||
- return -ENXIO;
|
||||
+ pbus = bus;
|
||||
+ pslot = slot;
|
||||
+ pfunc = func;
|
||||
+ vf = -1;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ pbus = dev->info.physfn.bus;
|
||||
+ pslot = PCI_SLOT(dev->info.physfn.devfn);
|
||||
+ pfunc = PCI_FUNC(dev->info.physfn.devfn);
|
||||
+ vf = PCI_BDF2(dev->bus, dev->devfn);
|
||||
}
|
||||
- table_paddr = msi->table_base;
|
||||
- }
|
||||
- table_paddr += table_offset;
|
||||
|
||||
- if ( !msix->used_entries )
|
||||
- {
|
||||
- u64 pba_paddr;
|
||||
- u32 pba_offset;
|
||||
+ table_paddr = read_pci_mem_bar(seg, pbus, pslot, pfunc, bir, vf);
|
||||
+ WARN_ON(msi && msi->table_base != table_paddr);
|
||||
+ if ( !table_paddr )
|
||||
+ {
|
||||
+ if ( !msi || !msi->table_base )
|
||||
+ {
|
||||
+ pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos),
|
||||
+ control & ~PCI_MSIX_FLAGS_ENABLE);
|
||||
+ xfree(entry);
|
||||
+ return -ENXIO;
|
||||
+ }
|
||||
+ table_paddr = msi->table_base;
|
||||
+ }
|
||||
+ table_paddr += table_offset & ~PCI_MSIX_BIRMASK;
|
||||
|
||||
msix->nr_entries = nr_entries;
|
||||
msix->table.first = PFN_DOWN(table_paddr);
|
||||
@@ -894,7 +894,19 @@ static int msix_capability_init(struct p
|
||||
BITS_TO_LONGS(nr_entries) - 1);
|
||||
WARN_ON(rangeset_overlaps_range(mmio_ro_ranges, msix->pba.first,
|
||||
msix->pba.last));
|
||||
+
|
||||
+ zap_on_error = true;
|
||||
}
|
||||
+ else if ( !msix->table.first )
|
||||
+ {
|
||||
+ pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos),
|
||||
+ control);
|
||||
+ xfree(entry);
|
||||
+ return -ENODATA;
|
||||
+ }
|
||||
+ else
|
||||
+ table_paddr = (msix->table.first << PAGE_SHIFT) +
|
||||
+ (table_offset & ~PCI_MSIX_BIRMASK & ~PAGE_MASK);
|
||||
|
||||
if ( entry )
|
||||
{
|
||||
@@ -905,8 +917,16 @@ static int msix_capability_init(struct p
|
||||
|
||||
if ( idx < 0 )
|
||||
{
|
||||
+ if ( zap_on_error )
|
||||
+ {
|
||||
+ msix->table.first = 0;
|
||||
+ msix->pba.first = 0;
|
||||
+
|
||||
+ control &= ~PCI_MSIX_FLAGS_ENABLE;
|
||||
+ }
|
||||
+
|
||||
pci_conf_write16(seg, bus, slot, func, msix_control_reg(pos),
|
||||
- control & ~PCI_MSIX_FLAGS_ENABLE);
|
||||
+ control);
|
||||
xfree(entry);
|
||||
return idx;
|
||||
}
|
||||
@@ -1102,9 +1122,14 @@ static void _pci_cleanup_msix(struct arc
|
||||
if ( rangeset_remove_range(mmio_ro_ranges, msix->table.first,
|
||||
msix->table.last) )
|
||||
WARN();
|
||||
+ msix->table.first = 0;
|
||||
+ msix->table.last = 0;
|
||||
+
|
||||
if ( rangeset_remove_range(mmio_ro_ranges, msix->pba.first,
|
||||
msix->pba.last) )
|
||||
WARN();
|
||||
+ msix->pba.first = 0;
|
||||
+ msix->pba.last = 0;
|
||||
}
|
||||
}
|
||||
|
||||
42
xsa338.patch
Normal file
42
xsa338.patch
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn: relax port_is_valid()
|
||||
|
||||
To avoid ports potentially becoming invalid behind the back of certain
|
||||
other functions (due to ->max_evtchn shrinking) because of
|
||||
- a guest invoking evtchn_reset() and from a 2nd vCPU opening new
|
||||
channels in parallel (see also XSA-343),
|
||||
- alloc_unbound_xen_event_channel() produced channels living above the
|
||||
2-level range (see also XSA-342),
|
||||
drop the max_evtchns check from port_is_valid(). For a port for which
|
||||
the function once returned "true", the returned value may not turn into
|
||||
"false" later on. The function's result may only depend on bounds which
|
||||
can only ever grow (which is the case for d->valid_evtchns).
|
||||
|
||||
This also eliminates a false sense of safety, utilized by some of the
|
||||
users (see again XSA-343): Without a suitable lock held, d->max_evtchns
|
||||
may change at any time, and hence deducing that certain other operations
|
||||
are safe when port_is_valid() returned true is not legitimate. The
|
||||
opportunities to abuse this may get widened by the change here
|
||||
(depending on guest and host configuration), but will be taken care of
|
||||
by the other XSA.
|
||||
|
||||
This is XSA-338.
|
||||
|
||||
Fixes: 48974e6ce52e ("evtchn: use a per-domain variable for the max number of event channels")
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
Reviewed-by: Julien Grall <jgrall@amazon.com>
|
||||
---
|
||||
v5: New, split from larger patch.
|
||||
|
||||
--- a/xen/include/xen/event.h
|
||||
+++ b/xen/include/xen/event.h
|
||||
@@ -107,8 +107,6 @@ void notify_via_xen_event_channel(struct
|
||||
|
||||
static inline bool_t port_is_valid(struct domain *d, unsigned int p)
|
||||
{
|
||||
- if ( p >= d->max_evtchns )
|
||||
- return 0;
|
||||
return p < read_atomic(&d->valid_evtchns);
|
||||
}
|
||||
|
||||
76
xsa339.patch
Normal file
76
xsa339.patch
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/pv: Avoid double exception injection
|
||||
|
||||
There is at least one path (SYSENTER with NT set, Xen converts to #GP) which
|
||||
ends up injecting the #GP fault twice, first in compat_sysenter(), and then a
|
||||
second time in compat_test_all_events(), due to the stale TBF_EXCEPTION left
|
||||
in TRAPBOUNCE_flags.
|
||||
|
||||
The guest kernel sees the second fault first, which is a kernel level #GP
|
||||
pointing at the head of the #GP handler, and is therefore a userspace
|
||||
trigger-able DoS.
|
||||
|
||||
This particular bug has bitten us several times before, so rearrange
|
||||
{compat_,}create_bounce_frame() to clobber TRAPBOUNCE on success, rather than
|
||||
leaving this task to one area of code which isn't used uniformly.
|
||||
|
||||
Other scenarios which might result in a double injection (e.g. two calls
|
||||
directly to compat_create_bounce_frame) will now crash the guest, which is far
|
||||
more obvious than letting the kernel run with corrupt state.
|
||||
|
||||
This is XSA-339
|
||||
|
||||
Fixes: fdac9515607b ("x86: clear EFLAGS.NT in SYSENTER entry path")
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
|
||||
diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S
|
||||
index c3e62f8734..73619f57ca 100644
|
||||
--- a/xen/arch/x86/x86_64/compat/entry.S
|
||||
+++ b/xen/arch/x86/x86_64/compat/entry.S
|
||||
@@ -78,7 +78,6 @@ compat_process_softirqs:
|
||||
sti
|
||||
.Lcompat_bounce_exception:
|
||||
call compat_create_bounce_frame
|
||||
- movb $0, TRAPBOUNCE_flags(%rdx)
|
||||
jmp compat_test_all_events
|
||||
|
||||
ALIGN
|
||||
@@ -352,7 +351,13 @@ __UNLIKELY_END(compat_bounce_null_selector)
|
||||
movl %eax,UREGS_cs+8(%rsp)
|
||||
movl TRAPBOUNCE_eip(%rdx),%eax
|
||||
movl %eax,UREGS_rip+8(%rsp)
|
||||
+
|
||||
+ /* Trapbounce complete. Clobber state to avoid an erroneous second injection. */
|
||||
+ xor %eax, %eax
|
||||
+ mov %ax, TRAPBOUNCE_cs(%rdx)
|
||||
+ mov %al, TRAPBOUNCE_flags(%rdx)
|
||||
ret
|
||||
+
|
||||
.section .fixup,"ax"
|
||||
.Lfx13:
|
||||
xorl %edi,%edi
|
||||
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
|
||||
index 1e880eb9f6..71a00e846b 100644
|
||||
--- a/xen/arch/x86/x86_64/entry.S
|
||||
+++ b/xen/arch/x86/x86_64/entry.S
|
||||
@@ -90,7 +90,6 @@ process_softirqs:
|
||||
sti
|
||||
.Lbounce_exception:
|
||||
call create_bounce_frame
|
||||
- movb $0, TRAPBOUNCE_flags(%rdx)
|
||||
jmp test_all_events
|
||||
|
||||
ALIGN
|
||||
@@ -512,6 +511,11 @@ UNLIKELY_START(z, create_bounce_frame_bad_bounce_ip)
|
||||
jmp asm_domain_crash_synchronous /* Does not return */
|
||||
__UNLIKELY_END(create_bounce_frame_bad_bounce_ip)
|
||||
movq %rax,UREGS_rip+8(%rsp)
|
||||
+
|
||||
+ /* Trapbounce complete. Clobber state to avoid an erroneous second injection. */
|
||||
+ xor %eax, %eax
|
||||
+ mov %rax, TRAPBOUNCE_eip(%rdx)
|
||||
+ mov %al, TRAPBOUNCE_flags(%rdx)
|
||||
ret
|
||||
|
||||
.pushsection .fixup, "ax", @progbits
|
||||
65
xsa340.patch
Normal file
65
xsa340.patch
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
From: Julien Grall <jgrall@amazon.com>
|
||||
Subject: xen/evtchn: Add missing barriers when accessing/allocating an event channel
|
||||
|
||||
While the allocation of a bucket is always performed with the per-domain
|
||||
lock, the bucket may be accessed without the lock taken (for instance, see
|
||||
evtchn_send()).
|
||||
|
||||
Instead such sites relies on port_is_valid() to return a non-zero value
|
||||
when the port has a struct evtchn associated to it. The function will
|
||||
mostly check whether the port is less than d->valid_evtchns as all the
|
||||
buckets/event channels should be allocated up to that point.
|
||||
|
||||
Unfortunately a compiler is free to re-order the assignment in
|
||||
evtchn_allocate_port() so it would be possible to have d->valid_evtchns
|
||||
updated before the new bucket has finish to allocate.
|
||||
|
||||
Additionally on Arm, even if this was compiled "correctly", the
|
||||
processor can still re-order the memory access.
|
||||
|
||||
Add a write memory barrier in the allocation side and a read memory
|
||||
barrier when the port is valid to prevent any re-ordering issue.
|
||||
|
||||
This is XSA-340.
|
||||
|
||||
Reported-by: Julien Grall <jgrall@amazon.com>
|
||||
Signed-off-by: Julien Grall <jgrall@amazon.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -178,6 +178,13 @@ int evtchn_allocate_port(struct domain *
|
||||
return -ENOMEM;
|
||||
bucket_from_port(d, port) = chn;
|
||||
|
||||
+ /*
|
||||
+ * d->valid_evtchns is used to check whether the bucket can be
|
||||
+ * accessed without the per-domain lock. Therefore,
|
||||
+ * d->valid_evtchns should be seen *after* the new bucket has
|
||||
+ * been setup.
|
||||
+ */
|
||||
+ smp_wmb();
|
||||
write_atomic(&d->valid_evtchns, d->valid_evtchns + EVTCHNS_PER_BUCKET);
|
||||
}
|
||||
|
||||
--- a/xen/include/xen/event.h
|
||||
+++ b/xen/include/xen/event.h
|
||||
@@ -107,7 +107,17 @@ void notify_via_xen_event_channel(struct
|
||||
|
||||
static inline bool_t port_is_valid(struct domain *d, unsigned int p)
|
||||
{
|
||||
- return p < read_atomic(&d->valid_evtchns);
|
||||
+ if ( p >= read_atomic(&d->valid_evtchns) )
|
||||
+ return false;
|
||||
+
|
||||
+ /*
|
||||
+ * The caller will usually access the event channel afterwards and
|
||||
+ * may be done without taking the per-domain lock. The barrier is
|
||||
+ * going in pair the smp_wmb() barrier in evtchn_allocate_port().
|
||||
+ */
|
||||
+ smp_rmb();
|
||||
+
|
||||
+ return true;
|
||||
}
|
||||
|
||||
static inline struct evtchn *evtchn_from_port(struct domain *d, unsigned int p)
|
||||
145
xsa342-4.13.patch
Normal file
145
xsa342-4.13.patch
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn/x86: enforce correct upper limit for 32-bit guests
|
||||
|
||||
The recording of d->max_evtchns in evtchn_2l_init(), in particular with
|
||||
the limited set of callers of the function, is insufficient. Neither for
|
||||
PV nor for HVM guests the bitness is known at domain_create() time, yet
|
||||
the upper bound in 2-level mode depends upon guest bitness. Recording
|
||||
too high a limit "allows" x86 32-bit domains to open not properly usable
|
||||
event channels, management of which (inside Xen) would then result in
|
||||
corruption of the shared info and vCPU info structures.
|
||||
|
||||
Keep the upper limit dynamic for the 2-level case, introducing a helper
|
||||
function to retrieve the effective limit. This helper is now supposed to
|
||||
be private to the event channel code. The used in do_poll() and
|
||||
domain_dump_evtchn_info() weren't consistent with port uses elsewhere
|
||||
and hence get switched to port_is_valid().
|
||||
|
||||
Furthermore FIFO mode's setup_ports() gets adjusted to loop only up to
|
||||
the prior ABI limit, rather than all the way up to the new one.
|
||||
|
||||
Finally a word on the change to do_poll(): Accessing ->max_evtchns
|
||||
without holding a suitable lock was never safe, as it as well as
|
||||
->evtchn_port_ops may change behind do_poll()'s back. Using
|
||||
port_is_valid() instead widens some the window for potential abuse,
|
||||
until we've dealt with the race altogether (see XSA-343).
|
||||
|
||||
This is XSA-342.
|
||||
|
||||
Reported-by: Julien Grall <jgrall@amazon.com>
|
||||
Fixes: 48974e6ce52e ("evtchn: use a per-domain variable for the max number of event channels")
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
Reviewed-by: Julien Grall <jgrall@amazon.com>
|
||||
|
||||
--- a/xen/common/event_2l.c
|
||||
+++ b/xen/common/event_2l.c
|
||||
@@ -103,7 +103,6 @@ static const struct evtchn_port_ops evtc
|
||||
void evtchn_2l_init(struct domain *d)
|
||||
{
|
||||
d->evtchn_port_ops = &evtchn_port_ops_2l;
|
||||
- d->max_evtchns = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
|
||||
}
|
||||
|
||||
/*
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -151,7 +151,7 @@ static void free_evtchn_bucket(struct do
|
||||
|
||||
int evtchn_allocate_port(struct domain *d, evtchn_port_t port)
|
||||
{
|
||||
- if ( port > d->max_evtchn_port || port >= d->max_evtchns )
|
||||
+ if ( port > d->max_evtchn_port || port >= max_evtchns(d) )
|
||||
return -ENOSPC;
|
||||
|
||||
if ( port_is_valid(d, port) )
|
||||
@@ -1396,13 +1396,11 @@ static void domain_dump_evtchn_info(stru
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
- for ( port = 1; port < d->max_evtchns; ++port )
|
||||
+ for ( port = 1; port_is_valid(d, port); ++port )
|
||||
{
|
||||
const struct evtchn *chn;
|
||||
char *ssid;
|
||||
|
||||
- if ( !port_is_valid(d, port) )
|
||||
- continue;
|
||||
chn = evtchn_from_port(d, port);
|
||||
if ( chn->state == ECS_FREE )
|
||||
continue;
|
||||
--- a/xen/common/event_fifo.c
|
||||
+++ b/xen/common/event_fifo.c
|
||||
@@ -478,7 +478,7 @@ static void cleanup_event_array(struct d
|
||||
d->evtchn_fifo = NULL;
|
||||
}
|
||||
|
||||
-static void setup_ports(struct domain *d)
|
||||
+static void setup_ports(struct domain *d, unsigned int prev_evtchns)
|
||||
{
|
||||
unsigned int port;
|
||||
|
||||
@@ -488,7 +488,7 @@ static void setup_ports(struct domain *d
|
||||
* - save its pending state.
|
||||
* - set default priority.
|
||||
*/
|
||||
- for ( port = 1; port < d->max_evtchns; port++ )
|
||||
+ for ( port = 1; port < prev_evtchns; port++ )
|
||||
{
|
||||
struct evtchn *evtchn;
|
||||
|
||||
@@ -546,6 +546,8 @@ int evtchn_fifo_init_control(struct evtc
|
||||
if ( !d->evtchn_fifo )
|
||||
{
|
||||
struct vcpu *vcb;
|
||||
+ /* Latch the value before it changes during setup_event_array(). */
|
||||
+ unsigned int prev_evtchns = max_evtchns(d);
|
||||
|
||||
for_each_vcpu ( d, vcb ) {
|
||||
rc = setup_control_block(vcb);
|
||||
@@ -562,8 +564,7 @@ int evtchn_fifo_init_control(struct evtc
|
||||
goto error;
|
||||
|
||||
d->evtchn_port_ops = &evtchn_port_ops_fifo;
|
||||
- d->max_evtchns = EVTCHN_FIFO_NR_CHANNELS;
|
||||
- setup_ports(d);
|
||||
+ setup_ports(d, prev_evtchns);
|
||||
}
|
||||
else
|
||||
rc = map_control_block(v, gfn, offset);
|
||||
--- a/xen/common/schedule.c
|
||||
+++ b/xen/common/schedule.c
|
||||
@@ -1434,7 +1434,7 @@ static long do_poll(struct sched_poll *s
|
||||
goto out;
|
||||
|
||||
rc = -EINVAL;
|
||||
- if ( port >= d->max_evtchns )
|
||||
+ if ( !port_is_valid(d, port) )
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
--- a/xen/include/xen/event.h
|
||||
+++ b/xen/include/xen/event.h
|
||||
@@ -105,6 +105,12 @@ void notify_via_xen_event_channel(struct
|
||||
#define bucket_from_port(d, p) \
|
||||
((group_from_port(d, p))[((p) % EVTCHNS_PER_GROUP) / EVTCHNS_PER_BUCKET])
|
||||
|
||||
+static inline unsigned int max_evtchns(const struct domain *d)
|
||||
+{
|
||||
+ return d->evtchn_fifo ? EVTCHN_FIFO_NR_CHANNELS
|
||||
+ : BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
|
||||
+}
|
||||
+
|
||||
static inline bool_t port_is_valid(struct domain *d, unsigned int p)
|
||||
{
|
||||
if ( p >= read_atomic(&d->valid_evtchns) )
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -382,7 +382,6 @@ struct domain
|
||||
/* Event channel information. */
|
||||
struct evtchn *evtchn; /* first bucket only */
|
||||
struct evtchn **evtchn_group[NR_EVTCHN_GROUPS]; /* all other buckets */
|
||||
- unsigned int max_evtchns; /* number supported by ABI */
|
||||
unsigned int max_evtchn_port; /* max permitted port number */
|
||||
unsigned int valid_evtchns; /* number of allocated event channels */
|
||||
spinlock_t event_lock;
|
||||
190
xsa343-4.12-1.patch
Normal file
190
xsa343-4.12-1.patch
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn: evtchn_reset() shouldn't succeed with still-open ports
|
||||
|
||||
While the function closes all ports, it does so without holding any
|
||||
lock, and hence racing requests may be issued causing new ports to get
|
||||
opened. This would have been problematic in particular if such a newly
|
||||
opened port had a port number above the new implementation limit (i.e.
|
||||
when switching from FIFO to 2-level) after the reset, as prior to
|
||||
"evtchn: relax port_is_valid()" this could have led to e.g.
|
||||
evtchn_close()'s "BUG_ON(!port_is_valid(d2, port2))" to trigger.
|
||||
|
||||
Introduce a counter of active ports and check that it's (still) no
|
||||
larger then the number of Xen internally used ones after obtaining the
|
||||
necessary lock in evtchn_reset().
|
||||
|
||||
As to the access model of the new {active,xen}_evtchns fields - while
|
||||
all writes get done using write_atomic(), reads ought to use
|
||||
read_atomic() only when outside of a suitably locked region.
|
||||
|
||||
Note that as of now evtchn_bind_virq() and evtchn_bind_ipi() don't have
|
||||
a need to call check_free_port().
|
||||
|
||||
This is part of XSA-343.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
Reviewed-by: Julien Grall <jgrall@amazon.com>
|
||||
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -188,6 +188,8 @@ int evtchn_allocate_port(struct domain *
|
||||
write_atomic(&d->valid_evtchns, d->valid_evtchns + EVTCHNS_PER_BUCKET);
|
||||
}
|
||||
|
||||
+ write_atomic(&d->active_evtchns, d->active_evtchns + 1);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -211,11 +213,26 @@ static int get_free_port(struct domain *
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Check whether a port is still marked free, and if so update the domain
|
||||
+ * counter accordingly. To be used on function exit paths.
|
||||
+ */
|
||||
+static void check_free_port(struct domain *d, evtchn_port_t port)
|
||||
+{
|
||||
+ if ( port_is_valid(d, port) &&
|
||||
+ evtchn_from_port(d, port)->state == ECS_FREE )
|
||||
+ write_atomic(&d->active_evtchns, d->active_evtchns - 1);
|
||||
+}
|
||||
+
|
||||
void evtchn_free(struct domain *d, struct evtchn *chn)
|
||||
{
|
||||
/* Clear pending event to avoid unexpected behavior on re-bind. */
|
||||
evtchn_port_clear_pending(d, chn);
|
||||
|
||||
+ if ( consumer_is_xen(chn) )
|
||||
+ write_atomic(&d->xen_evtchns, d->xen_evtchns - 1);
|
||||
+ write_atomic(&d->active_evtchns, d->active_evtchns - 1);
|
||||
+
|
||||
/* Reset binding to vcpu0 when the channel is freed. */
|
||||
chn->state = ECS_FREE;
|
||||
chn->notify_vcpu_id = 0;
|
||||
@@ -258,6 +275,7 @@ static long evtchn_alloc_unbound(evtchn_
|
||||
alloc->port = port;
|
||||
|
||||
out:
|
||||
+ check_free_port(d, port);
|
||||
spin_unlock(&d->event_lock);
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
@@ -351,6 +369,7 @@ static long evtchn_bind_interdomain(evtc
|
||||
bind->local_port = lport;
|
||||
|
||||
out:
|
||||
+ check_free_port(ld, lport);
|
||||
spin_unlock(&ld->event_lock);
|
||||
if ( ld != rd )
|
||||
spin_unlock(&rd->event_lock);
|
||||
@@ -488,7 +507,7 @@ static long evtchn_bind_pirq(evtchn_bind
|
||||
struct domain *d = current->domain;
|
||||
struct vcpu *v = d->vcpu[0];
|
||||
struct pirq *info;
|
||||
- int port, pirq = bind->pirq;
|
||||
+ int port = 0, pirq = bind->pirq;
|
||||
long rc;
|
||||
|
||||
if ( (pirq < 0) || (pirq >= d->nr_pirqs) )
|
||||
@@ -536,6 +555,7 @@ static long evtchn_bind_pirq(evtchn_bind
|
||||
arch_evtchn_bind_pirq(d, pirq);
|
||||
|
||||
out:
|
||||
+ check_free_port(d, port);
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
@@ -1011,10 +1031,10 @@ int evtchn_unmask(unsigned int port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-
|
||||
int evtchn_reset(struct domain *d)
|
||||
{
|
||||
unsigned int i;
|
||||
+ int rc = 0;
|
||||
|
||||
if ( d != current->domain && !d->controller_pause_count )
|
||||
return -EINVAL;
|
||||
@@ -1024,7 +1044,9 @@ int evtchn_reset(struct domain *d)
|
||||
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
- if ( d->evtchn_fifo )
|
||||
+ if ( d->active_evtchns > d->xen_evtchns )
|
||||
+ rc = -EAGAIN;
|
||||
+ else if ( d->evtchn_fifo )
|
||||
{
|
||||
/* Switching back to 2-level ABI. */
|
||||
evtchn_fifo_destroy(d);
|
||||
@@ -1033,7 +1055,7 @@ int evtchn_reset(struct domain *d)
|
||||
|
||||
spin_unlock(&d->event_lock);
|
||||
|
||||
- return 0;
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
static long evtchn_set_priority(const struct evtchn_set_priority *set_priority)
|
||||
@@ -1219,10 +1241,9 @@ int alloc_unbound_xen_event_channel(
|
||||
|
||||
spin_lock(&ld->event_lock);
|
||||
|
||||
- rc = get_free_port(ld);
|
||||
+ port = rc = get_free_port(ld);
|
||||
if ( rc < 0 )
|
||||
goto out;
|
||||
- port = rc;
|
||||
chn = evtchn_from_port(ld, port);
|
||||
|
||||
rc = xsm_evtchn_unbound(XSM_TARGET, ld, chn, remote_domid);
|
||||
@@ -1238,7 +1259,10 @@ int alloc_unbound_xen_event_channel(
|
||||
|
||||
spin_unlock(&chn->lock);
|
||||
|
||||
+ write_atomic(&ld->xen_evtchns, ld->xen_evtchns + 1);
|
||||
+
|
||||
out:
|
||||
+ check_free_port(ld, port);
|
||||
spin_unlock(&ld->event_lock);
|
||||
|
||||
return rc < 0 ? rc : port;
|
||||
@@ -1314,6 +1338,7 @@ int evtchn_init(struct domain *d, unsign
|
||||
return -EINVAL;
|
||||
}
|
||||
evtchn_from_port(d, 0)->state = ECS_RESERVED;
|
||||
+ write_atomic(&d->active_evtchns, 0);
|
||||
|
||||
#if MAX_VIRT_CPUS > BITS_PER_LONG
|
||||
d->poll_mask = xzalloc_array(unsigned long, BITS_TO_LONGS(d->max_vcpus));
|
||||
@@ -1340,6 +1365,8 @@ void evtchn_destroy(struct domain *d)
|
||||
for ( i = 0; port_is_valid(d, i); i++ )
|
||||
evtchn_close(d, i, 0);
|
||||
|
||||
+ ASSERT(!d->active_evtchns);
|
||||
+
|
||||
clear_global_virq_handlers(d);
|
||||
|
||||
evtchn_fifo_destroy(d);
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -346,6 +346,16 @@ struct domain
|
||||
struct evtchn **evtchn_group[NR_EVTCHN_GROUPS]; /* all other buckets */
|
||||
unsigned int max_evtchn_port; /* max permitted port number */
|
||||
unsigned int valid_evtchns; /* number of allocated event channels */
|
||||
+ /*
|
||||
+ * Number of in-use event channels. Writers should use write_atomic().
|
||||
+ * Readers need to use read_atomic() only when not holding event_lock.
|
||||
+ */
|
||||
+ unsigned int active_evtchns;
|
||||
+ /*
|
||||
+ * Number of event channels used internally by Xen (not subject to
|
||||
+ * EVTCHNOP_reset). Read/write access like for active_evtchns.
|
||||
+ */
|
||||
+ unsigned int xen_evtchns;
|
||||
spinlock_t event_lock;
|
||||
const struct evtchn_port_ops *evtchn_port_ops;
|
||||
struct evtchn_fifo_domain *evtchn_fifo;
|
||||
290
xsa343-4.12-2.patch
Normal file
290
xsa343-4.12-2.patch
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn: convert per-channel lock to be IRQ-safe
|
||||
|
||||
... in order for send_guest_{global,vcpu}_virq() to be able to make use
|
||||
of it.
|
||||
|
||||
This is part of XSA-343.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Julien Grall <jgrall@amazon.com>
|
||||
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -248,6 +248,7 @@ static long evtchn_alloc_unbound(evtchn_
|
||||
int port;
|
||||
domid_t dom = alloc->dom;
|
||||
long rc;
|
||||
+ unsigned long flags;
|
||||
|
||||
d = rcu_lock_domain_by_any_id(dom);
|
||||
if ( d == NULL )
|
||||
@@ -263,14 +264,14 @@ static long evtchn_alloc_unbound(evtchn_
|
||||
if ( rc )
|
||||
goto out;
|
||||
|
||||
- spin_lock(&chn->lock);
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
|
||||
chn->state = ECS_UNBOUND;
|
||||
if ( (chn->u.unbound.remote_domid = alloc->remote_dom) == DOMID_SELF )
|
||||
chn->u.unbound.remote_domid = current->domain->domain_id;
|
||||
evtchn_port_init(d, chn);
|
||||
|
||||
- spin_unlock(&chn->lock);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
|
||||
alloc->port = port;
|
||||
|
||||
@@ -283,26 +284,32 @@ static long evtchn_alloc_unbound(evtchn_
|
||||
}
|
||||
|
||||
|
||||
-static void double_evtchn_lock(struct evtchn *lchn, struct evtchn *rchn)
|
||||
+static unsigned long double_evtchn_lock(struct evtchn *lchn,
|
||||
+ struct evtchn *rchn)
|
||||
{
|
||||
- if ( lchn < rchn )
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ if ( lchn <= rchn )
|
||||
{
|
||||
- spin_lock(&lchn->lock);
|
||||
- spin_lock(&rchn->lock);
|
||||
+ spin_lock_irqsave(&lchn->lock, flags);
|
||||
+ if ( lchn != rchn )
|
||||
+ spin_lock(&rchn->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
- if ( lchn != rchn )
|
||||
- spin_lock(&rchn->lock);
|
||||
+ spin_lock_irqsave(&rchn->lock, flags);
|
||||
spin_lock(&lchn->lock);
|
||||
}
|
||||
+
|
||||
+ return flags;
|
||||
}
|
||||
|
||||
-static void double_evtchn_unlock(struct evtchn *lchn, struct evtchn *rchn)
|
||||
+static void double_evtchn_unlock(struct evtchn *lchn, struct evtchn *rchn,
|
||||
+ unsigned long flags)
|
||||
{
|
||||
- spin_unlock(&lchn->lock);
|
||||
if ( lchn != rchn )
|
||||
- spin_unlock(&rchn->lock);
|
||||
+ spin_unlock(&lchn->lock);
|
||||
+ spin_unlock_irqrestore(&rchn->lock, flags);
|
||||
}
|
||||
|
||||
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
|
||||
@@ -312,6 +319,7 @@ static long evtchn_bind_interdomain(evtc
|
||||
int lport, rport = bind->remote_port;
|
||||
domid_t rdom = bind->remote_dom;
|
||||
long rc;
|
||||
+ unsigned long flags;
|
||||
|
||||
if ( rdom == DOMID_SELF )
|
||||
rdom = current->domain->domain_id;
|
||||
@@ -347,7 +355,7 @@ static long evtchn_bind_interdomain(evtc
|
||||
if ( rc )
|
||||
goto out;
|
||||
|
||||
- double_evtchn_lock(lchn, rchn);
|
||||
+ flags = double_evtchn_lock(lchn, rchn);
|
||||
|
||||
lchn->u.interdomain.remote_dom = rd;
|
||||
lchn->u.interdomain.remote_port = rport;
|
||||
@@ -364,7 +372,7 @@ static long evtchn_bind_interdomain(evtc
|
||||
*/
|
||||
evtchn_port_set_pending(ld, lchn->notify_vcpu_id, lchn);
|
||||
|
||||
- double_evtchn_unlock(lchn, rchn);
|
||||
+ double_evtchn_unlock(lchn, rchn, flags);
|
||||
|
||||
bind->local_port = lport;
|
||||
|
||||
@@ -387,6 +395,7 @@ int evtchn_bind_virq(evtchn_bind_virq_t
|
||||
struct domain *d = current->domain;
|
||||
int virq = bind->virq, vcpu = bind->vcpu;
|
||||
int rc = 0;
|
||||
+ unsigned long flags;
|
||||
|
||||
if ( (virq < 0) || (virq >= ARRAY_SIZE(v->virq_to_evtchn)) )
|
||||
return -EINVAL;
|
||||
@@ -424,14 +433,14 @@ int evtchn_bind_virq(evtchn_bind_virq_t
|
||||
|
||||
chn = evtchn_from_port(d, port);
|
||||
|
||||
- spin_lock(&chn->lock);
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
|
||||
chn->state = ECS_VIRQ;
|
||||
chn->notify_vcpu_id = vcpu;
|
||||
chn->u.virq = virq;
|
||||
evtchn_port_init(d, chn);
|
||||
|
||||
- spin_unlock(&chn->lock);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
|
||||
v->virq_to_evtchn[virq] = bind->port = port;
|
||||
|
||||
@@ -448,6 +457,7 @@ static long evtchn_bind_ipi(evtchn_bind_
|
||||
struct domain *d = current->domain;
|
||||
int port, vcpu = bind->vcpu;
|
||||
long rc = 0;
|
||||
+ unsigned long flags;
|
||||
|
||||
if ( domain_vcpu(d, vcpu) == NULL )
|
||||
return -ENOENT;
|
||||
@@ -459,13 +469,13 @@ static long evtchn_bind_ipi(evtchn_bind_
|
||||
|
||||
chn = evtchn_from_port(d, port);
|
||||
|
||||
- spin_lock(&chn->lock);
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
|
||||
chn->state = ECS_IPI;
|
||||
chn->notify_vcpu_id = vcpu;
|
||||
evtchn_port_init(d, chn);
|
||||
|
||||
- spin_unlock(&chn->lock);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
|
||||
bind->port = port;
|
||||
|
||||
@@ -509,6 +519,7 @@ static long evtchn_bind_pirq(evtchn_bind
|
||||
struct pirq *info;
|
||||
int port = 0, pirq = bind->pirq;
|
||||
long rc;
|
||||
+ unsigned long flags;
|
||||
|
||||
if ( (pirq < 0) || (pirq >= d->nr_pirqs) )
|
||||
return -EINVAL;
|
||||
@@ -541,14 +552,14 @@ static long evtchn_bind_pirq(evtchn_bind
|
||||
goto out;
|
||||
}
|
||||
|
||||
- spin_lock(&chn->lock);
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
|
||||
chn->state = ECS_PIRQ;
|
||||
chn->u.pirq.irq = pirq;
|
||||
link_pirq_port(port, chn, v);
|
||||
evtchn_port_init(d, chn);
|
||||
|
||||
- spin_unlock(&chn->lock);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
|
||||
bind->port = port;
|
||||
|
||||
@@ -569,6 +580,7 @@ int evtchn_close(struct domain *d1, int
|
||||
struct evtchn *chn1, *chn2;
|
||||
int port2;
|
||||
long rc = 0;
|
||||
+ unsigned long flags;
|
||||
|
||||
again:
|
||||
spin_lock(&d1->event_lock);
|
||||
@@ -668,14 +680,14 @@ int evtchn_close(struct domain *d1, int
|
||||
BUG_ON(chn2->state != ECS_INTERDOMAIN);
|
||||
BUG_ON(chn2->u.interdomain.remote_dom != d1);
|
||||
|
||||
- double_evtchn_lock(chn1, chn2);
|
||||
+ flags = double_evtchn_lock(chn1, chn2);
|
||||
|
||||
evtchn_free(d1, chn1);
|
||||
|
||||
chn2->state = ECS_UNBOUND;
|
||||
chn2->u.unbound.remote_domid = d1->domain_id;
|
||||
|
||||
- double_evtchn_unlock(chn1, chn2);
|
||||
+ double_evtchn_unlock(chn1, chn2, flags);
|
||||
|
||||
goto out;
|
||||
|
||||
@@ -683,9 +695,9 @@ int evtchn_close(struct domain *d1, int
|
||||
BUG();
|
||||
}
|
||||
|
||||
- spin_lock(&chn1->lock);
|
||||
+ spin_lock_irqsave(&chn1->lock, flags);
|
||||
evtchn_free(d1, chn1);
|
||||
- spin_unlock(&chn1->lock);
|
||||
+ spin_unlock_irqrestore(&chn1->lock, flags);
|
||||
|
||||
out:
|
||||
if ( d2 != NULL )
|
||||
@@ -705,13 +717,14 @@ int evtchn_send(struct domain *ld, unsig
|
||||
struct evtchn *lchn, *rchn;
|
||||
struct domain *rd;
|
||||
int rport, ret = 0;
|
||||
+ unsigned long flags;
|
||||
|
||||
if ( !port_is_valid(ld, lport) )
|
||||
return -EINVAL;
|
||||
|
||||
lchn = evtchn_from_port(ld, lport);
|
||||
|
||||
- spin_lock(&lchn->lock);
|
||||
+ spin_lock_irqsave(&lchn->lock, flags);
|
||||
|
||||
/* Guest cannot send via a Xen-attached event channel. */
|
||||
if ( unlikely(consumer_is_xen(lchn)) )
|
||||
@@ -746,7 +759,7 @@ int evtchn_send(struct domain *ld, unsig
|
||||
}
|
||||
|
||||
out:
|
||||
- spin_unlock(&lchn->lock);
|
||||
+ spin_unlock_irqrestore(&lchn->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1238,6 +1251,7 @@ int alloc_unbound_xen_event_channel(
|
||||
{
|
||||
struct evtchn *chn;
|
||||
int port, rc;
|
||||
+ unsigned long flags;
|
||||
|
||||
spin_lock(&ld->event_lock);
|
||||
|
||||
@@ -1250,14 +1264,14 @@ int alloc_unbound_xen_event_channel(
|
||||
if ( rc )
|
||||
goto out;
|
||||
|
||||
- spin_lock(&chn->lock);
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
|
||||
chn->state = ECS_UNBOUND;
|
||||
chn->xen_consumer = get_xen_consumer(notification_fn);
|
||||
chn->notify_vcpu_id = lvcpu;
|
||||
chn->u.unbound.remote_domid = remote_domid;
|
||||
|
||||
- spin_unlock(&chn->lock);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
|
||||
write_atomic(&ld->xen_evtchns, ld->xen_evtchns + 1);
|
||||
|
||||
@@ -1280,11 +1294,12 @@ void notify_via_xen_event_channel(struct
|
||||
{
|
||||
struct evtchn *lchn, *rchn;
|
||||
struct domain *rd;
|
||||
+ unsigned long flags;
|
||||
|
||||
ASSERT(port_is_valid(ld, lport));
|
||||
lchn = evtchn_from_port(ld, lport);
|
||||
|
||||
- spin_lock(&lchn->lock);
|
||||
+ spin_lock_irqsave(&lchn->lock, flags);
|
||||
|
||||
if ( likely(lchn->state == ECS_INTERDOMAIN) )
|
||||
{
|
||||
@@ -1294,7 +1309,7 @@ void notify_via_xen_event_channel(struct
|
||||
evtchn_port_set_pending(rd, rchn->notify_vcpu_id, rchn);
|
||||
}
|
||||
|
||||
- spin_unlock(&lchn->lock);
|
||||
+ spin_unlock_irqrestore(&lchn->lock, flags);
|
||||
}
|
||||
|
||||
void evtchn_check_pollers(struct domain *d, unsigned int port)
|
||||
381
xsa343-4.12-3.patch
Normal file
381
xsa343-4.12-3.patch
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn: address races with evtchn_reset()
|
||||
|
||||
Neither d->evtchn_port_ops nor max_evtchns(d) may be used in an entirely
|
||||
lock-less manner, as both may change by a racing evtchn_reset(). In the
|
||||
common case, at least one of the domain's event lock or the per-channel
|
||||
lock needs to be held. In the specific case of the inter-domain sending
|
||||
by evtchn_send() and notify_via_xen_event_channel() holding the other
|
||||
side's per-channel lock is sufficient, as the channel can't change state
|
||||
without both per-channel locks held. Without such a channel changing
|
||||
state, evtchn_reset() can't complete successfully.
|
||||
|
||||
Lock-free accesses continue to be permitted for the shim (calling some
|
||||
otherwise internal event channel functions), as this happens while the
|
||||
domain is in effectively single-threaded mode. Special care also needs
|
||||
taking for the shim's marking of in-use ports as ECS_RESERVED (allowing
|
||||
use of such ports in the shim case is okay because switching into and
|
||||
hence also out of FIFO mode is impossible there).
|
||||
|
||||
As a side effect, certain operations on Xen bound event channels which
|
||||
were mistakenly permitted so far (e.g. unmask or poll) will be refused
|
||||
now.
|
||||
|
||||
This is part of XSA-343.
|
||||
|
||||
Reported-by: Julien Grall <jgrall@amazon.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Julien Grall <jgrall@amazon.com>
|
||||
|
||||
--- a/xen/arch/x86/irq.c
|
||||
+++ b/xen/arch/x86/irq.c
|
||||
@@ -2364,14 +2364,24 @@ static void dump_irqs(unsigned char key)
|
||||
|
||||
for ( i = 0; i < action->nr_guests; i++ )
|
||||
{
|
||||
+ struct evtchn *evtchn;
|
||||
+ unsigned int pending = 2, masked = 2;
|
||||
+
|
||||
d = action->guest[i];
|
||||
pirq = domain_irq_to_pirq(d, irq);
|
||||
info = pirq_info(d, pirq);
|
||||
+ evtchn = evtchn_from_port(d, info->evtchn);
|
||||
+ local_irq_disable();
|
||||
+ if ( spin_trylock(&evtchn->lock) )
|
||||
+ {
|
||||
+ pending = evtchn_is_pending(d, evtchn);
|
||||
+ masked = evtchn_is_masked(d, evtchn);
|
||||
+ spin_unlock(&evtchn->lock);
|
||||
+ }
|
||||
+ local_irq_enable();
|
||||
printk("%u:%3d(%c%c%c)",
|
||||
- d->domain_id, pirq,
|
||||
- evtchn_port_is_pending(d, info->evtchn) ? 'P' : '-',
|
||||
- evtchn_port_is_masked(d, info->evtchn) ? 'M' : '-',
|
||||
- (info->masked ? 'M' : '-'));
|
||||
+ d->domain_id, pirq, "-P?"[pending],
|
||||
+ "-M?"[masked], info->masked ? 'M' : '-');
|
||||
if ( i != action->nr_guests )
|
||||
printk(",");
|
||||
}
|
||||
--- a/xen/arch/x86/pv/shim.c
|
||||
+++ b/xen/arch/x86/pv/shim.c
|
||||
@@ -662,8 +662,11 @@ void pv_shim_inject_evtchn(unsigned int
|
||||
if ( port_is_valid(guest, port) )
|
||||
{
|
||||
struct evtchn *chn = evtchn_from_port(guest, port);
|
||||
+ unsigned long flags;
|
||||
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
evtchn_port_set_pending(guest, chn->notify_vcpu_id, chn);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
--- a/xen/common/event_2l.c
|
||||
+++ b/xen/common/event_2l.c
|
||||
@@ -63,8 +63,10 @@ static void evtchn_2l_unmask(struct doma
|
||||
}
|
||||
}
|
||||
|
||||
-static bool evtchn_2l_is_pending(const struct domain *d, evtchn_port_t port)
|
||||
+static bool evtchn_2l_is_pending(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
+ evtchn_port_t port = evtchn->port;
|
||||
unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
|
||||
|
||||
ASSERT(port < max_ports);
|
||||
@@ -72,8 +74,10 @@ static bool evtchn_2l_is_pending(const s
|
||||
guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
|
||||
}
|
||||
|
||||
-static bool evtchn_2l_is_masked(const struct domain *d, evtchn_port_t port)
|
||||
+static bool evtchn_2l_is_masked(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
+ evtchn_port_t port = evtchn->port;
|
||||
unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
|
||||
|
||||
ASSERT(port < max_ports);
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -156,8 +156,9 @@ int evtchn_allocate_port(struct domain *
|
||||
|
||||
if ( port_is_valid(d, port) )
|
||||
{
|
||||
- if ( evtchn_from_port(d, port)->state != ECS_FREE ||
|
||||
- evtchn_port_is_busy(d, port) )
|
||||
+ const struct evtchn *chn = evtchn_from_port(d, port);
|
||||
+
|
||||
+ if ( chn->state != ECS_FREE || evtchn_is_busy(d, chn) )
|
||||
return -EBUSY;
|
||||
}
|
||||
else
|
||||
@@ -774,6 +775,7 @@ void send_guest_vcpu_virq(struct vcpu *v
|
||||
unsigned long flags;
|
||||
int port;
|
||||
struct domain *d;
|
||||
+ struct evtchn *chn;
|
||||
|
||||
ASSERT(!virq_is_global(virq));
|
||||
|
||||
@@ -784,7 +786,10 @@ void send_guest_vcpu_virq(struct vcpu *v
|
||||
goto out;
|
||||
|
||||
d = v->domain;
|
||||
- evtchn_port_set_pending(d, v->vcpu_id, evtchn_from_port(d, port));
|
||||
+ chn = evtchn_from_port(d, port);
|
||||
+ spin_lock(&chn->lock);
|
||||
+ evtchn_port_set_pending(d, v->vcpu_id, chn);
|
||||
+ spin_unlock(&chn->lock);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&v->virq_lock, flags);
|
||||
@@ -813,7 +818,9 @@ void send_guest_global_virq(struct domai
|
||||
goto out;
|
||||
|
||||
chn = evtchn_from_port(d, port);
|
||||
+ spin_lock(&chn->lock);
|
||||
evtchn_port_set_pending(d, chn->notify_vcpu_id, chn);
|
||||
+ spin_unlock(&chn->lock);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&v->virq_lock, flags);
|
||||
@@ -823,6 +830,7 @@ void send_guest_pirq(struct domain *d, c
|
||||
{
|
||||
int port;
|
||||
struct evtchn *chn;
|
||||
+ unsigned long flags;
|
||||
|
||||
/*
|
||||
* PV guests: It should not be possible to race with __evtchn_close(). The
|
||||
@@ -837,7 +845,9 @@ void send_guest_pirq(struct domain *d, c
|
||||
}
|
||||
|
||||
chn = evtchn_from_port(d, port);
|
||||
+ spin_lock_irqsave(&chn->lock, flags);
|
||||
evtchn_port_set_pending(d, chn->notify_vcpu_id, chn);
|
||||
+ spin_unlock_irqrestore(&chn->lock, flags);
|
||||
}
|
||||
|
||||
static struct domain *global_virq_handlers[NR_VIRQS] __read_mostly;
|
||||
@@ -1034,12 +1044,15 @@ int evtchn_unmask(unsigned int port)
|
||||
{
|
||||
struct domain *d = current->domain;
|
||||
struct evtchn *evtchn;
|
||||
+ unsigned long flags;
|
||||
|
||||
if ( unlikely(!port_is_valid(d, port)) )
|
||||
return -EINVAL;
|
||||
|
||||
evtchn = evtchn_from_port(d, port);
|
||||
+ spin_lock_irqsave(&evtchn->lock, flags);
|
||||
evtchn_port_unmask(d, evtchn);
|
||||
+ spin_unlock_irqrestore(&evtchn->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1449,8 +1462,8 @@ static void domain_dump_evtchn_info(stru
|
||||
|
||||
printk(" %4u [%d/%d/",
|
||||
port,
|
||||
- evtchn_port_is_pending(d, port),
|
||||
- evtchn_port_is_masked(d, port));
|
||||
+ evtchn_is_pending(d, chn),
|
||||
+ evtchn_is_masked(d, chn));
|
||||
evtchn_port_print_state(d, chn);
|
||||
printk("]: s=%d n=%d x=%d",
|
||||
chn->state, chn->notify_vcpu_id, chn->xen_consumer);
|
||||
--- a/xen/common/event_fifo.c
|
||||
+++ b/xen/common/event_fifo.c
|
||||
@@ -296,23 +296,26 @@ static void evtchn_fifo_unmask(struct do
|
||||
evtchn_fifo_set_pending(v, evtchn);
|
||||
}
|
||||
|
||||
-static bool evtchn_fifo_is_pending(const struct domain *d, evtchn_port_t port)
|
||||
+static bool evtchn_fifo_is_pending(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
- const event_word_t *word = evtchn_fifo_word_from_port(d, port);
|
||||
+ const event_word_t *word = evtchn_fifo_word_from_port(d, evtchn->port);
|
||||
|
||||
return word && guest_test_bit(d, EVTCHN_FIFO_PENDING, word);
|
||||
}
|
||||
|
||||
-static bool_t evtchn_fifo_is_masked(const struct domain *d, evtchn_port_t port)
|
||||
+static bool_t evtchn_fifo_is_masked(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
- const event_word_t *word = evtchn_fifo_word_from_port(d, port);
|
||||
+ const event_word_t *word = evtchn_fifo_word_from_port(d, evtchn->port);
|
||||
|
||||
return !word || guest_test_bit(d, EVTCHN_FIFO_MASKED, word);
|
||||
}
|
||||
|
||||
-static bool_t evtchn_fifo_is_busy(const struct domain *d, evtchn_port_t port)
|
||||
+static bool_t evtchn_fifo_is_busy(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
- const event_word_t *word = evtchn_fifo_word_from_port(d, port);
|
||||
+ const event_word_t *word = evtchn_fifo_word_from_port(d, evtchn->port);
|
||||
|
||||
return word && guest_test_bit(d, EVTCHN_FIFO_LINKED, word);
|
||||
}
|
||||
--- a/xen/include/asm-x86/event.h
|
||||
+++ b/xen/include/asm-x86/event.h
|
||||
@@ -47,4 +47,10 @@ static inline bool arch_virq_is_global(u
|
||||
return true;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_PV_SHIM
|
||||
+# include <asm/pv/shim.h>
|
||||
+# define arch_evtchn_is_special(chn) \
|
||||
+ (pv_shim && (chn)->port && (chn)->state == ECS_RESERVED)
|
||||
+#endif
|
||||
+
|
||||
#endif
|
||||
--- a/xen/include/xen/event.h
|
||||
+++ b/xen/include/xen/event.h
|
||||
@@ -133,6 +133,24 @@ static inline struct evtchn *evtchn_from
|
||||
return bucket_from_port(d, p) + (p % EVTCHNS_PER_BUCKET);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * "usable" as in "by a guest", i.e. Xen consumed channels are assumed to be
|
||||
+ * taken care of separately where used for Xen's internal purposes.
|
||||
+ */
|
||||
+static bool evtchn_usable(const struct evtchn *evtchn)
|
||||
+{
|
||||
+ if ( evtchn->xen_consumer )
|
||||
+ return false;
|
||||
+
|
||||
+#ifdef arch_evtchn_is_special
|
||||
+ if ( arch_evtchn_is_special(evtchn) )
|
||||
+ return true;
|
||||
+#endif
|
||||
+
|
||||
+ BUILD_BUG_ON(ECS_FREE > ECS_RESERVED);
|
||||
+ return evtchn->state > ECS_RESERVED;
|
||||
+}
|
||||
+
|
||||
/* Wait on a Xen-attached event channel. */
|
||||
#define wait_on_xen_event_channel(port, condition) \
|
||||
do { \
|
||||
@@ -165,19 +183,24 @@ int evtchn_reset(struct domain *d);
|
||||
|
||||
/*
|
||||
* Low-level event channel port ops.
|
||||
+ *
|
||||
+ * All hooks have to be called with a lock held which prevents the channel
|
||||
+ * from changing state. This may be the domain event lock, the per-channel
|
||||
+ * lock, or in the case of sending interdomain events also the other side's
|
||||
+ * per-channel lock. Exceptions apply in certain cases for the PV shim.
|
||||
*/
|
||||
struct evtchn_port_ops {
|
||||
void (*init)(struct domain *d, struct evtchn *evtchn);
|
||||
void (*set_pending)(struct vcpu *v, struct evtchn *evtchn);
|
||||
void (*clear_pending)(struct domain *d, struct evtchn *evtchn);
|
||||
void (*unmask)(struct domain *d, struct evtchn *evtchn);
|
||||
- bool (*is_pending)(const struct domain *d, evtchn_port_t port);
|
||||
- bool (*is_masked)(const struct domain *d, evtchn_port_t port);
|
||||
+ bool (*is_pending)(const struct domain *d, const struct evtchn *evtchn);
|
||||
+ bool (*is_masked)(const struct domain *d, const struct evtchn *evtchn);
|
||||
/*
|
||||
* Is the port unavailable because it's still being cleaned up
|
||||
* after being closed?
|
||||
*/
|
||||
- bool (*is_busy)(const struct domain *d, evtchn_port_t port);
|
||||
+ bool (*is_busy)(const struct domain *d, const struct evtchn *evtchn);
|
||||
int (*set_priority)(struct domain *d, struct evtchn *evtchn,
|
||||
unsigned int priority);
|
||||
void (*print_state)(struct domain *d, const struct evtchn *evtchn);
|
||||
@@ -193,38 +216,67 @@ static inline void evtchn_port_set_pendi
|
||||
unsigned int vcpu_id,
|
||||
struct evtchn *evtchn)
|
||||
{
|
||||
- d->evtchn_port_ops->set_pending(d->vcpu[vcpu_id], evtchn);
|
||||
+ if ( evtchn_usable(evtchn) )
|
||||
+ d->evtchn_port_ops->set_pending(d->vcpu[vcpu_id], evtchn);
|
||||
}
|
||||
|
||||
static inline void evtchn_port_clear_pending(struct domain *d,
|
||||
struct evtchn *evtchn)
|
||||
{
|
||||
- d->evtchn_port_ops->clear_pending(d, evtchn);
|
||||
+ if ( evtchn_usable(evtchn) )
|
||||
+ d->evtchn_port_ops->clear_pending(d, evtchn);
|
||||
}
|
||||
|
||||
static inline void evtchn_port_unmask(struct domain *d,
|
||||
struct evtchn *evtchn)
|
||||
{
|
||||
- d->evtchn_port_ops->unmask(d, evtchn);
|
||||
+ if ( evtchn_usable(evtchn) )
|
||||
+ d->evtchn_port_ops->unmask(d, evtchn);
|
||||
}
|
||||
|
||||
-static inline bool evtchn_port_is_pending(const struct domain *d,
|
||||
- evtchn_port_t port)
|
||||
+static inline bool evtchn_is_pending(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
- return d->evtchn_port_ops->is_pending(d, port);
|
||||
+ return evtchn_usable(evtchn) && d->evtchn_port_ops->is_pending(d, evtchn);
|
||||
}
|
||||
|
||||
-static inline bool evtchn_port_is_masked(const struct domain *d,
|
||||
- evtchn_port_t port)
|
||||
+static inline bool evtchn_port_is_pending(struct domain *d, evtchn_port_t port)
|
||||
{
|
||||
- return d->evtchn_port_ops->is_masked(d, port);
|
||||
+ struct evtchn *evtchn = evtchn_from_port(d, port);
|
||||
+ bool rc;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&evtchn->lock, flags);
|
||||
+ rc = evtchn_is_pending(d, evtchn);
|
||||
+ spin_unlock_irqrestore(&evtchn->lock, flags);
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+static inline bool evtchn_is_masked(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
+{
|
||||
+ return !evtchn_usable(evtchn) || d->evtchn_port_ops->is_masked(d, evtchn);
|
||||
+}
|
||||
+
|
||||
+static inline bool evtchn_port_is_masked(struct domain *d, evtchn_port_t port)
|
||||
+{
|
||||
+ struct evtchn *evtchn = evtchn_from_port(d, port);
|
||||
+ bool rc;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&evtchn->lock, flags);
|
||||
+ rc = evtchn_is_masked(d, evtchn);
|
||||
+ spin_unlock_irqrestore(&evtchn->lock, flags);
|
||||
+
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
-static inline bool evtchn_port_is_busy(const struct domain *d,
|
||||
- evtchn_port_t port)
|
||||
+static inline bool evtchn_is_busy(const struct domain *d,
|
||||
+ const struct evtchn *evtchn)
|
||||
{
|
||||
return d->evtchn_port_ops->is_busy &&
|
||||
- d->evtchn_port_ops->is_busy(d, port);
|
||||
+ d->evtchn_port_ops->is_busy(d, evtchn);
|
||||
}
|
||||
|
||||
static inline int evtchn_port_set_priority(struct domain *d,
|
||||
@@ -233,6 +285,8 @@ static inline int evtchn_port_set_priori
|
||||
{
|
||||
if ( !d->evtchn_port_ops->set_priority )
|
||||
return -ENOSYS;
|
||||
+ if ( !evtchn_usable(evtchn) )
|
||||
+ return -EACCES;
|
||||
return d->evtchn_port_ops->set_priority(d, evtchn, priority);
|
||||
}
|
||||
|
||||
132
xsa344-4.12-1.patch
Normal file
132
xsa344-4.12-1.patch
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn: arrange for preemption in evtchn_destroy()
|
||||
|
||||
Especially closing of fully established interdomain channels can take
|
||||
quite some time, due to the locking involved. Therefore we shouldn't
|
||||
assume we can clean up still active ports all in one go. Besides adding
|
||||
the necessary preemption check, also avoid pointlessly starting from
|
||||
(or now really ending at) 0; 1 is the lowest numbered port which may
|
||||
need closing.
|
||||
|
||||
Since we're now reducing ->valid_evtchns, free_xen_event_channel(),
|
||||
and (at least to be on the safe side) notify_via_xen_event_channel()
|
||||
need to cope with attempts to close / unbind from / send through already
|
||||
closed (and no longer valid, as per port_is_valid()) ports.
|
||||
|
||||
This is part of XSA-344.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Julien Grall <jgrall@amazon.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -724,7 +724,6 @@ int domain_kill(struct domain *d)
|
||||
return domain_kill(d);
|
||||
d->is_dying = DOMDYING_dying;
|
||||
argo_destroy(d);
|
||||
- evtchn_destroy(d);
|
||||
gnttab_release_mappings(d);
|
||||
tmem_destroy(d->tmem_client);
|
||||
vnuma_destroy(d->vnuma);
|
||||
@@ -732,6 +731,9 @@ int domain_kill(struct domain *d)
|
||||
d->tmem_client = NULL;
|
||||
/* fallthrough */
|
||||
case DOMDYING_dying:
|
||||
+ rc = evtchn_destroy(d);
|
||||
+ if ( rc )
|
||||
+ break;
|
||||
rc = domain_relinquish_resources(d);
|
||||
if ( rc != 0 )
|
||||
break;
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -1297,7 +1297,16 @@ int alloc_unbound_xen_event_channel(
|
||||
|
||||
void free_xen_event_channel(struct domain *d, int port)
|
||||
{
|
||||
- BUG_ON(!port_is_valid(d, port));
|
||||
+ if ( !port_is_valid(d, port) )
|
||||
+ {
|
||||
+ /*
|
||||
+ * Make sure ->is_dying is read /after/ ->valid_evtchns, pairing
|
||||
+ * with the spin_barrier() and BUG_ON() in evtchn_destroy().
|
||||
+ */
|
||||
+ smp_rmb();
|
||||
+ BUG_ON(!d->is_dying);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
evtchn_close(d, port, 0);
|
||||
}
|
||||
@@ -1309,7 +1318,17 @@ void notify_via_xen_event_channel(struct
|
||||
struct domain *rd;
|
||||
unsigned long flags;
|
||||
|
||||
- ASSERT(port_is_valid(ld, lport));
|
||||
+ if ( !port_is_valid(ld, lport) )
|
||||
+ {
|
||||
+ /*
|
||||
+ * Make sure ->is_dying is read /after/ ->valid_evtchns, pairing
|
||||
+ * with the spin_barrier() and BUG_ON() in evtchn_destroy().
|
||||
+ */
|
||||
+ smp_rmb();
|
||||
+ ASSERT(ld->is_dying);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
lchn = evtchn_from_port(ld, lport);
|
||||
|
||||
spin_lock_irqsave(&lchn->lock, flags);
|
||||
@@ -1380,8 +1399,7 @@ int evtchn_init(struct domain *d, unsign
|
||||
return 0;
|
||||
}
|
||||
|
||||
-
|
||||
-void evtchn_destroy(struct domain *d)
|
||||
+int evtchn_destroy(struct domain *d)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -1390,14 +1408,29 @@ void evtchn_destroy(struct domain *d)
|
||||
spin_barrier(&d->event_lock);
|
||||
|
||||
/* Close all existing event channels. */
|
||||
- for ( i = 0; port_is_valid(d, i); i++ )
|
||||
+ for ( i = d->valid_evtchns; --i; )
|
||||
+ {
|
||||
evtchn_close(d, i, 0);
|
||||
|
||||
+ /*
|
||||
+ * Avoid preempting when called from domain_create()'s error path,
|
||||
+ * and don't check too often (choice of frequency is arbitrary).
|
||||
+ */
|
||||
+ if ( i && !(i & 0x3f) && d->is_dying != DOMDYING_dead &&
|
||||
+ hypercall_preempt_check() )
|
||||
+ {
|
||||
+ write_atomic(&d->valid_evtchns, i);
|
||||
+ return -ERESTART;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
ASSERT(!d->active_evtchns);
|
||||
|
||||
clear_global_virq_handlers(d);
|
||||
|
||||
evtchn_fifo_destroy(d);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -136,7 +136,7 @@ struct evtchn
|
||||
} __attribute__((aligned(64)));
|
||||
|
||||
int evtchn_init(struct domain *d, unsigned int max_port);
|
||||
-void evtchn_destroy(struct domain *d); /* from domain_kill */
|
||||
+int evtchn_destroy(struct domain *d); /* from domain_kill */
|
||||
void evtchn_destroy_final(struct domain *d); /* from complete_domain_destroy */
|
||||
|
||||
struct waitqueue_vcpu;
|
||||
203
xsa344-4.12-2.patch
Normal file
203
xsa344-4.12-2.patch
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: evtchn: arrange for preemption in evtchn_reset()
|
||||
|
||||
Like for evtchn_destroy() looping over all possible event channels to
|
||||
close them can take a significant amount of time. Unlike done there, we
|
||||
can't alter domain properties (i.e. d->valid_evtchns) here. Borrow, in a
|
||||
lightweight form, the paging domctl continuation concept, redirecting
|
||||
the continuations to different sub-ops. Just like there this is to be
|
||||
able to allow for predictable overall results of the involved sub-ops:
|
||||
Racing requests should either complete or be refused.
|
||||
|
||||
Note that a domain can't interfere with an already started (by a remote
|
||||
domain) reset, due to being paused. It can prevent a remote reset from
|
||||
happening by leaving a reset unfinished, but that's only going to affect
|
||||
itself.
|
||||
|
||||
This is part of XSA-344.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Julien Grall <jgrall@amazon.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -1170,7 +1170,7 @@ void domain_unpause_except_self(struct d
|
||||
domain_unpause(d);
|
||||
}
|
||||
|
||||
-int domain_soft_reset(struct domain *d)
|
||||
+int domain_soft_reset(struct domain *d, bool resuming)
|
||||
{
|
||||
struct vcpu *v;
|
||||
int rc;
|
||||
@@ -1184,7 +1184,7 @@ int domain_soft_reset(struct domain *d)
|
||||
}
|
||||
spin_unlock(&d->shutdown_lock);
|
||||
|
||||
- rc = evtchn_reset(d);
|
||||
+ rc = evtchn_reset(d, resuming);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -585,12 +585,22 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
}
|
||||
|
||||
case XEN_DOMCTL_soft_reset:
|
||||
+ case XEN_DOMCTL_soft_reset_cont:
|
||||
if ( d == current->domain ) /* no domain_pause() */
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
- ret = domain_soft_reset(d);
|
||||
+ ret = domain_soft_reset(d, op->cmd == XEN_DOMCTL_soft_reset_cont);
|
||||
+ if ( ret == -ERESTART )
|
||||
+ {
|
||||
+ op->cmd = XEN_DOMCTL_soft_reset_cont;
|
||||
+ if ( !__copy_field_to_guest(u_domctl, op, cmd) )
|
||||
+ ret = hypercall_create_continuation(__HYPERVISOR_domctl,
|
||||
+ "h", u_domctl);
|
||||
+ else
|
||||
+ ret = -EFAULT;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_destroydomain:
|
||||
--- a/xen/common/event_channel.c
|
||||
+++ b/xen/common/event_channel.c
|
||||
@@ -1057,7 +1057,7 @@ int evtchn_unmask(unsigned int port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int evtchn_reset(struct domain *d)
|
||||
+int evtchn_reset(struct domain *d, bool resuming)
|
||||
{
|
||||
unsigned int i;
|
||||
int rc = 0;
|
||||
@@ -1065,11 +1065,40 @@ int evtchn_reset(struct domain *d)
|
||||
if ( d != current->domain && !d->controller_pause_count )
|
||||
return -EINVAL;
|
||||
|
||||
- for ( i = 0; port_is_valid(d, i); i++ )
|
||||
+ spin_lock(&d->event_lock);
|
||||
+
|
||||
+ /*
|
||||
+ * If we are resuming, then start where we stopped. Otherwise, check
|
||||
+ * that a reset operation is not already in progress, and if none is,
|
||||
+ * record that this is now the case.
|
||||
+ */
|
||||
+ i = resuming ? d->next_evtchn : !d->next_evtchn;
|
||||
+ if ( i > d->next_evtchn )
|
||||
+ d->next_evtchn = i;
|
||||
+
|
||||
+ spin_unlock(&d->event_lock);
|
||||
+
|
||||
+ if ( !i )
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ for ( ; port_is_valid(d, i); i++ )
|
||||
+ {
|
||||
evtchn_close(d, i, 1);
|
||||
|
||||
+ /* NB: Choice of frequency is arbitrary. */
|
||||
+ if ( !(i & 0x3f) && hypercall_preempt_check() )
|
||||
+ {
|
||||
+ spin_lock(&d->event_lock);
|
||||
+ d->next_evtchn = i;
|
||||
+ spin_unlock(&d->event_lock);
|
||||
+ return -ERESTART;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
spin_lock(&d->event_lock);
|
||||
|
||||
+ d->next_evtchn = 0;
|
||||
+
|
||||
if ( d->active_evtchns > d->xen_evtchns )
|
||||
rc = -EAGAIN;
|
||||
else if ( d->evtchn_fifo )
|
||||
@@ -1204,7 +1233,8 @@ long do_event_channel_op(int cmd, XEN_GU
|
||||
break;
|
||||
}
|
||||
|
||||
- case EVTCHNOP_reset: {
|
||||
+ case EVTCHNOP_reset:
|
||||
+ case EVTCHNOP_reset_cont: {
|
||||
struct evtchn_reset reset;
|
||||
struct domain *d;
|
||||
|
||||
@@ -1217,9 +1247,13 @@ long do_event_channel_op(int cmd, XEN_GU
|
||||
|
||||
rc = xsm_evtchn_reset(XSM_TARGET, current->domain, d);
|
||||
if ( !rc )
|
||||
- rc = evtchn_reset(d);
|
||||
+ rc = evtchn_reset(d, cmd == EVTCHNOP_reset_cont);
|
||||
|
||||
rcu_unlock_domain(d);
|
||||
+
|
||||
+ if ( rc == -ERESTART )
|
||||
+ rc = hypercall_create_continuation(__HYPERVISOR_event_channel_op,
|
||||
+ "ih", EVTCHNOP_reset_cont, arg);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/include/public/domctl.h
|
||||
+++ b/xen/include/public/domctl.h
|
||||
@@ -1144,7 +1144,10 @@ struct xen_domctl {
|
||||
#define XEN_DOMCTL_iomem_permission 20
|
||||
#define XEN_DOMCTL_ioport_permission 21
|
||||
#define XEN_DOMCTL_hypercall_init 22
|
||||
-#define XEN_DOMCTL_arch_setup 23 /* Obsolete IA64 only */
|
||||
+#ifdef __XEN__
|
||||
+/* #define XEN_DOMCTL_arch_setup 23 Obsolete IA64 only */
|
||||
+#define XEN_DOMCTL_soft_reset_cont 23
|
||||
+#endif
|
||||
#define XEN_DOMCTL_settimeoffset 24
|
||||
#define XEN_DOMCTL_getvcpuaffinity 25
|
||||
#define XEN_DOMCTL_real_mode_area 26 /* Obsolete PPC only */
|
||||
--- a/xen/include/public/event_channel.h
|
||||
+++ b/xen/include/public/event_channel.h
|
||||
@@ -74,6 +74,9 @@
|
||||
#define EVTCHNOP_init_control 11
|
||||
#define EVTCHNOP_expand_array 12
|
||||
#define EVTCHNOP_set_priority 13
|
||||
+#ifdef __XEN__
|
||||
+#define EVTCHNOP_reset_cont 14
|
||||
+#endif
|
||||
/* ` } */
|
||||
|
||||
typedef uint32_t evtchn_port_t;
|
||||
--- a/xen/include/xen/event.h
|
||||
+++ b/xen/include/xen/event.h
|
||||
@@ -171,7 +171,7 @@ void evtchn_check_pollers(struct domain
|
||||
void evtchn_2l_init(struct domain *d);
|
||||
|
||||
/* Close all event channels and reset to 2-level ABI. */
|
||||
-int evtchn_reset(struct domain *d);
|
||||
+int evtchn_reset(struct domain *d, bool resuming);
|
||||
|
||||
/*
|
||||
* Low-level event channel port ops.
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -356,6 +356,8 @@ struct domain
|
||||
* EVTCHNOP_reset). Read/write access like for active_evtchns.
|
||||
*/
|
||||
unsigned int xen_evtchns;
|
||||
+ /* Port to resume from in evtchn_reset(), when in a continuation. */
|
||||
+ unsigned int next_evtchn;
|
||||
spinlock_t event_lock;
|
||||
const struct evtchn_port_ops *evtchn_port_ops;
|
||||
struct evtchn_fifo_domain *evtchn_fifo;
|
||||
@@ -628,7 +630,7 @@ int domain_shutdown(struct domain *d, u8
|
||||
void domain_resume(struct domain *d);
|
||||
void domain_pause_for_debugger(void);
|
||||
|
||||
-int domain_soft_reset(struct domain *d);
|
||||
+int domain_soft_reset(struct domain *d, bool resuming);
|
||||
|
||||
int vcpu_start_shutdown_deferral(struct vcpu *v);
|
||||
void vcpu_end_shutdown_deferral(struct vcpu *v);
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
From e33fad3044aaaeec6ed9914925d9558695bdb09d Mon Sep 17 00:00:00 2001
|
||||
From: Wei Liu <wei.liu2@citrix.com>
|
||||
Date: Sat, 11 Jan 2020 21:57:41 +0000
|
||||
Subject: [PATCH 1/3] x86/mm: Refactor map_pages_to_xen to have only a single
|
||||
exit path
|
||||
|
||||
We will soon need to perform clean-ups before returning.
|
||||
|
||||
No functional change.
|
||||
|
||||
This is part of XSA-345.
|
||||
|
||||
Reported-by: Hongyan Xia <hongyxia@amazon.com>
|
||||
Signed-off-by: Wei Liu <wei.liu2@citrix.com>
|
||||
Signed-off-by: Hongyan Xia <hongyxia@amazon.com>
|
||||
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
|
||||
---
|
||||
xen/arch/x86/mm.c | 17 +++++++++++------
|
||||
1 file changed, 11 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
|
||||
index b4c90bd054..0e540f143b 100644
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -5227,6 +5227,7 @@ int map_pages_to_xen(
|
||||
l2_pgentry_t *pl2e, ol2e;
|
||||
l1_pgentry_t *pl1e, ol1e;
|
||||
unsigned int i;
|
||||
+ int rc = -ENOMEM;
|
||||
|
||||
#define flush_flags(oldf) do { \
|
||||
unsigned int o_ = (oldf); \
|
||||
@@ -5247,7 +5248,8 @@ int map_pages_to_xen(
|
||||
l3_pgentry_t ol3e, *pl3e = virt_to_xen_l3e(virt);
|
||||
|
||||
if ( !pl3e )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
+
|
||||
ol3e = *pl3e;
|
||||
|
||||
if ( cpu_has_page1gb &&
|
||||
@@ -5335,7 +5337,7 @@ int map_pages_to_xen(
|
||||
|
||||
pl2e = alloc_xen_pagetable();
|
||||
if ( pl2e == NULL )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
|
||||
for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
|
||||
l2e_write(pl2e + i,
|
||||
@@ -5364,7 +5366,7 @@ int map_pages_to_xen(
|
||||
|
||||
pl2e = virt_to_xen_l2e(virt);
|
||||
if ( !pl2e )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
|
||||
if ( ((((virt >> PAGE_SHIFT) | mfn_x(mfn)) &
|
||||
((1u << PAGETABLE_ORDER) - 1)) == 0) &&
|
||||
@@ -5407,7 +5409,7 @@ int map_pages_to_xen(
|
||||
{
|
||||
pl1e = virt_to_xen_l1e(virt);
|
||||
if ( pl1e == NULL )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
}
|
||||
else if ( l2e_get_flags(*pl2e) & _PAGE_PSE )
|
||||
{
|
||||
@@ -5434,7 +5436,7 @@ int map_pages_to_xen(
|
||||
|
||||
pl1e = alloc_xen_pagetable();
|
||||
if ( pl1e == NULL )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
|
||||
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
|
||||
l1e_write(&pl1e[i],
|
||||
@@ -5578,7 +5580,10 @@ int map_pages_to_xen(
|
||||
|
||||
#undef flush_flags
|
||||
|
||||
- return 0;
|
||||
+ rc = 0;
|
||||
+
|
||||
+ out:
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
int populate_pt_range(unsigned long virt, unsigned long nr_mfns)
|
||||
--
|
||||
2.25.1
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
From a151b07d504d7f442256e1c82917334216c58a21 Mon Sep 17 00:00:00 2001
|
||||
From: Wei Liu <wei.liu2@citrix.com>
|
||||
Date: Sat, 11 Jan 2020 21:57:42 +0000
|
||||
Subject: [PATCH 2/3] x86/mm: Refactor modify_xen_mappings to have one exit
|
||||
path
|
||||
|
||||
We will soon need to perform clean-ups before returning.
|
||||
|
||||
No functional change.
|
||||
|
||||
This is part of XSA-345.
|
||||
|
||||
Reported-by: Hongyan Xia <hongyxia@amazon.com>
|
||||
Signed-off-by: Wei Liu <wei.liu2@citrix.com>
|
||||
Signed-off-by: Hongyan Xia <hongyxia@amazon.com>
|
||||
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
|
||||
---
|
||||
xen/arch/x86/mm.c | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
|
||||
index 0e540f143b..bff2689e60 100644
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -5610,6 +5610,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
l1_pgentry_t *pl1e;
|
||||
unsigned int i;
|
||||
unsigned long v = s;
|
||||
+ int rc = -ENOMEM;
|
||||
|
||||
/* Set of valid PTE bits which may be altered. */
|
||||
#define FLAGS_MASK (_PAGE_NX|_PAGE_RW|_PAGE_PRESENT)
|
||||
@@ -5651,7 +5652,8 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
/* PAGE1GB: shatter the superpage and fall through. */
|
||||
pl2e = alloc_xen_pagetable();
|
||||
if ( !pl2e )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
+
|
||||
for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
|
||||
l2e_write(pl2e + i,
|
||||
l2e_from_pfn(l3e_get_pfn(*pl3e) +
|
||||
@@ -5706,7 +5708,8 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
/* PSE: shatter the superpage and try again. */
|
||||
pl1e = alloc_xen_pagetable();
|
||||
if ( !pl1e )
|
||||
- return -ENOMEM;
|
||||
+ goto out;
|
||||
+
|
||||
for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
|
||||
l1e_write(&pl1e[i],
|
||||
l1e_from_pfn(l2e_get_pfn(*pl2e) + i,
|
||||
@@ -5835,7 +5838,10 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
flush_area(NULL, FLUSH_TLB_GLOBAL);
|
||||
|
||||
#undef FLAGS_MASK
|
||||
- return 0;
|
||||
+ rc = 0;
|
||||
+
|
||||
+ out:
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
#undef flush_area
|
||||
--
|
||||
2.25.1
|
||||
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
From abaf05e183f3bc3927844ae16d6642a382c0dbef Mon Sep 17 00:00:00 2001
|
||||
From: Hongyan Xia <hongyxia@amazon.com>
|
||||
Date: Sat, 11 Jan 2020 21:57:43 +0000
|
||||
Subject: [PATCH 3/3] x86/mm: Prevent some races in hypervisor mapping updates
|
||||
|
||||
map_pages_to_xen will attempt to coalesce mappings into 2MiB and 1GiB
|
||||
superpages if possible, to maximize TLB efficiency. This means both
|
||||
replacing superpage entries with smaller entries, and replacing
|
||||
smaller entries with superpages.
|
||||
|
||||
Unfortunately, while some potential races are handled correctly,
|
||||
others are not. These include:
|
||||
|
||||
1. When one processor modifies a sub-superpage mapping while another
|
||||
processor replaces the entire range with a superpage.
|
||||
|
||||
Take the following example:
|
||||
|
||||
Suppose L3[N] points to L2. And suppose we have two processors, A and
|
||||
B.
|
||||
|
||||
* A walks the pagetables, get a pointer to L2.
|
||||
* B replaces L3[N] with a 1GiB mapping.
|
||||
* B Frees L2
|
||||
* A writes L2[M] #
|
||||
|
||||
This is race exacerbated by the fact that virt_to_xen_l[21]e doesn't
|
||||
handle higher-level superpages properly: If you call virt_xen_to_l2e
|
||||
on a virtual address within an L3 superpage, you'll either hit a BUG()
|
||||
(most likely), or get a pointer into the middle of a data page; same
|
||||
with virt_xen_to_l1 on a virtual address within either an L3 or L2
|
||||
superpage.
|
||||
|
||||
So take the following example:
|
||||
|
||||
* A reads pl3e and discovers it to point to an L2.
|
||||
* B replaces L3[N] with a 1GiB mapping
|
||||
* A calls virt_to_xen_l2e() and hits the BUG_ON() #
|
||||
|
||||
2. When two processors simultaneously try to replace a sub-superpage
|
||||
mapping with a superpage mapping.
|
||||
|
||||
Take the following example:
|
||||
|
||||
Suppose L3[N] points to L2. And suppose we have two processors, A and B,
|
||||
both trying to replace L3[N] with a superpage.
|
||||
|
||||
* A walks the pagetables, get a pointer to pl3e, and takes a copy ol3e pointing to L2.
|
||||
* B walks the pagetables, gets a pointre to pl3e, and takes a copy ol3e pointing to L2.
|
||||
* A writes the new value into L3[N]
|
||||
* B writes the new value into L3[N]
|
||||
* A recursively frees all the L1's under L2, then frees L2
|
||||
* B recursively double-frees all the L1's under L2, then double-frees L2 #
|
||||
|
||||
Fix this by grabbing a lock for the entirety of the mapping update
|
||||
operation.
|
||||
|
||||
Rather than grabbing map_pgdir_lock for the entire operation, however,
|
||||
repurpose the PGT_locked bit from L3's page->type_info as a lock.
|
||||
This means that rather than locking the entire address space, we
|
||||
"only" lock a single 512GiB chunk of hypervisor address space at a
|
||||
time.
|
||||
|
||||
There was a proposal for a lock-and-reverify approach, where we walk
|
||||
the pagetables to the point where we decide what to do; then grab the
|
||||
map_pgdir_lock, re-verify the information we collected without the
|
||||
lock, and finally make the change (starting over again if anything had
|
||||
changed). Without being able to guarantee that the L2 table wasn't
|
||||
freed, however, that means every read would need to be considered
|
||||
potentially unsafe. Thinking carefully about that is probably
|
||||
something that wants to be done on public, not under time pressure.
|
||||
|
||||
This is part of XSA-345.
|
||||
|
||||
Reported-by: Hongyan Xia <hongyxia@amazon.com>
|
||||
Signed-off-by: Hongyan Xia <hongyxia@amazon.com>
|
||||
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
|
||||
---
|
||||
xen/arch/x86/mm.c | 92 +++++++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 89 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
|
||||
index bff2689e60..d6ba8c4bb4 100644
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -2197,6 +2197,50 @@ void page_unlock(struct page_info *page)
|
||||
current_locked_page_set(NULL);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * L3 table locks:
|
||||
+ *
|
||||
+ * Used for serialization in map_pages_to_xen() and modify_xen_mappings().
|
||||
+ *
|
||||
+ * For Xen PT pages, the page->u.inuse.type_info is unused and it is safe to
|
||||
+ * reuse the PGT_locked flag. This lock is taken only when we move down to L3
|
||||
+ * tables and below, since L4 (and above, for 5-level paging) is still globally
|
||||
+ * protected by map_pgdir_lock.
|
||||
+ *
|
||||
+ * PV MMU update hypercalls call map_pages_to_xen while holding a page's page_lock().
|
||||
+ * This has two implications:
|
||||
+ * - We cannot reuse reuse current_locked_page_* for debugging
|
||||
+ * - To avoid the chance of deadlock, even for different pages, we
|
||||
+ * must never grab page_lock() after grabbing l3t_lock(). This
|
||||
+ * includes any page_lock()-based locks, such as
|
||||
+ * mem_sharing_page_lock().
|
||||
+ *
|
||||
+ * Also note that we grab the map_pgdir_lock while holding the
|
||||
+ * l3t_lock(), so to avoid deadlock we must avoid grabbing them in
|
||||
+ * reverse order.
|
||||
+ */
|
||||
+static void l3t_lock(struct page_info *page)
|
||||
+{
|
||||
+ unsigned long x, nx;
|
||||
+
|
||||
+ do {
|
||||
+ while ( (x = page->u.inuse.type_info) & PGT_locked )
|
||||
+ cpu_relax();
|
||||
+ nx = x | PGT_locked;
|
||||
+ } while ( cmpxchg(&page->u.inuse.type_info, x, nx) != x );
|
||||
+}
|
||||
+
|
||||
+static void l3t_unlock(struct page_info *page)
|
||||
+{
|
||||
+ unsigned long x, nx, y = page->u.inuse.type_info;
|
||||
+
|
||||
+ do {
|
||||
+ x = y;
|
||||
+ BUG_ON(!(x & PGT_locked));
|
||||
+ nx = x & ~PGT_locked;
|
||||
+ } while ( (y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x );
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_PV
|
||||
/*
|
||||
* PTE flags that a guest may change without re-validating the PTE.
|
||||
@@ -5217,6 +5261,23 @@ l1_pgentry_t *virt_to_xen_l1e(unsigned long v)
|
||||
flush_area_local((const void *)v, f) : \
|
||||
flush_area_all((const void *)v, f))
|
||||
|
||||
+#define L3T_INIT(page) (page) = ZERO_BLOCK_PTR
|
||||
+
|
||||
+#define L3T_LOCK(page) \
|
||||
+ do { \
|
||||
+ if ( locking ) \
|
||||
+ l3t_lock(page); \
|
||||
+ } while ( false )
|
||||
+
|
||||
+#define L3T_UNLOCK(page) \
|
||||
+ do { \
|
||||
+ if ( locking && (page) != ZERO_BLOCK_PTR ) \
|
||||
+ { \
|
||||
+ l3t_unlock(page); \
|
||||
+ (page) = ZERO_BLOCK_PTR; \
|
||||
+ } \
|
||||
+ } while ( false )
|
||||
+
|
||||
int map_pages_to_xen(
|
||||
unsigned long virt,
|
||||
mfn_t mfn,
|
||||
@@ -5228,6 +5289,7 @@ int map_pages_to_xen(
|
||||
l1_pgentry_t *pl1e, ol1e;
|
||||
unsigned int i;
|
||||
int rc = -ENOMEM;
|
||||
+ struct page_info *current_l3page;
|
||||
|
||||
#define flush_flags(oldf) do { \
|
||||
unsigned int o_ = (oldf); \
|
||||
@@ -5243,13 +5305,20 @@ int map_pages_to_xen(
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
+ L3T_INIT(current_l3page);
|
||||
+
|
||||
while ( nr_mfns != 0 )
|
||||
{
|
||||
- l3_pgentry_t ol3e, *pl3e = virt_to_xen_l3e(virt);
|
||||
+ l3_pgentry_t *pl3e, ol3e;
|
||||
|
||||
+ L3T_UNLOCK(current_l3page);
|
||||
+
|
||||
+ pl3e = virt_to_xen_l3e(virt);
|
||||
if ( !pl3e )
|
||||
goto out;
|
||||
|
||||
+ current_l3page = virt_to_page(pl3e);
|
||||
+ L3T_LOCK(current_l3page);
|
||||
ol3e = *pl3e;
|
||||
|
||||
if ( cpu_has_page1gb &&
|
||||
@@ -5583,6 +5652,7 @@ int map_pages_to_xen(
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
+ L3T_UNLOCK(current_l3page);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -5611,6 +5681,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
unsigned int i;
|
||||
unsigned long v = s;
|
||||
int rc = -ENOMEM;
|
||||
+ struct page_info *current_l3page;
|
||||
|
||||
/* Set of valid PTE bits which may be altered. */
|
||||
#define FLAGS_MASK (_PAGE_NX|_PAGE_RW|_PAGE_PRESENT)
|
||||
@@ -5619,11 +5690,22 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
ASSERT(IS_ALIGNED(s, PAGE_SIZE));
|
||||
ASSERT(IS_ALIGNED(e, PAGE_SIZE));
|
||||
|
||||
+ L3T_INIT(current_l3page);
|
||||
+
|
||||
while ( v < e )
|
||||
{
|
||||
- l3_pgentry_t *pl3e = virt_to_xen_l3e(v);
|
||||
+ l3_pgentry_t *pl3e;
|
||||
+
|
||||
+ L3T_UNLOCK(current_l3page);
|
||||
|
||||
- if ( !pl3e || !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
|
||||
+ pl3e = virt_to_xen_l3e(v);
|
||||
+ if ( !pl3e )
|
||||
+ goto out;
|
||||
+
|
||||
+ current_l3page = virt_to_page(pl3e);
|
||||
+ L3T_LOCK(current_l3page);
|
||||
+
|
||||
+ if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
|
||||
{
|
||||
/* Confirm the caller isn't trying to create new mappings. */
|
||||
ASSERT(!(nf & _PAGE_PRESENT));
|
||||
@@ -5841,9 +5923,13 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
+ L3T_UNLOCK(current_l3page);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+#undef L3T_LOCK
|
||||
+#undef L3T_UNLOCK
|
||||
+
|
||||
#undef flush_area
|
||||
|
||||
int destroy_xen_mappings(unsigned long s, unsigned long e)
|
||||
--
|
||||
2.25.1
|
||||
|
||||
50
xsa346-4.12-1.patch
Normal file
50
xsa346-4.12-1.patch
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: IOMMU: suppress "iommu_dont_flush_iotlb" when about to free a page
|
||||
|
||||
Deferring flushes to a single, wide range one - as is done when
|
||||
handling XENMAPSPACE_gmfn_range - is okay only as long as
|
||||
pages don't get freed ahead of the eventual flush. While the only
|
||||
function setting the flag (xenmem_add_to_physmap()) suggests by its name
|
||||
that it's only mapping new entries, in reality the way
|
||||
xenmem_add_to_physmap_one() works means an unmap would happen not only
|
||||
for the page being moved (but not freed) but, if the destination GFN is
|
||||
populated, also for the page being displaced from that GFN. Collapsing
|
||||
the two flushes for this GFN into just one (end even more so deferring
|
||||
it to a batched invocation) is not correct.
|
||||
|
||||
This is part of XSA-346.
|
||||
|
||||
Fixes: cf95b2a9fd5a ("iommu: Introduce per cpu flag (iommu_dont_flush_iotlb) to avoid unnecessary iotlb... ")
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Paul Durrant <paul@xen.org>
|
||||
Acked-by: Julien Grall <jgrall@amazon.com>
|
||||
|
||||
--- a/xen/common/memory.c
|
||||
+++ b/xen/common/memory.c
|
||||
@@ -300,6 +300,7 @@ int guest_remove_page(struct domain *d,
|
||||
p2m_type_t p2mt;
|
||||
#endif
|
||||
mfn_t mfn;
|
||||
+ bool *dont_flush_p, dont_flush;
|
||||
int rc;
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
@@ -386,8 +387,18 @@ int guest_remove_page(struct domain *d,
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Since we're likely to free the page below, we need to suspend
|
||||
+ * xenmem_add_to_physmap()'s suppressing of IOMMU TLB flushes.
|
||||
+ */
|
||||
+ dont_flush_p = &this_cpu(iommu_dont_flush_iotlb);
|
||||
+ dont_flush = *dont_flush_p;
|
||||
+ *dont_flush_p = false;
|
||||
+
|
||||
rc = guest_physmap_remove_page(d, _gfn(gmfn), mfn, 0);
|
||||
|
||||
+ *dont_flush_p = dont_flush;
|
||||
+
|
||||
/*
|
||||
* With the lack of an IOMMU on some platforms, domains with DMA-capable
|
||||
* device must retrieve the same pfn when the hypercall populate_physmap
|
||||
202
xsa346-4.12-2.patch
Normal file
202
xsa346-4.12-2.patch
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: IOMMU: hold page ref until after deferred TLB flush
|
||||
|
||||
When moving around a page via XENMAPSPACE_gmfn_range, deferring the TLB
|
||||
flush for the "from" GFN range requires that the page remains allocated
|
||||
to the guest until the TLB flush has actually occurred. Otherwise a
|
||||
parallel hypercall to remove the page would only flush the TLB for the
|
||||
GFN it has been moved to, but not the one is was mapped at originally.
|
||||
|
||||
This is part of XSA-346.
|
||||
|
||||
Fixes: cf95b2a9fd5a ("iommu: Introduce per cpu flag (iommu_dont_flush_iotlb) to avoid unnecessary iotlb... ")
|
||||
Reported-by: Julien Grall <jgrall@amazon.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Julien Grall <jgrall@amazon.com>
|
||||
|
||||
--- a/xen/arch/arm/mm.c
|
||||
+++ b/xen/arch/arm/mm.c
|
||||
@@ -1211,7 +1211,7 @@ void share_xen_page_with_guest(struct pa
|
||||
int xenmem_add_to_physmap_one(
|
||||
struct domain *d,
|
||||
unsigned int space,
|
||||
- union xen_add_to_physmap_batch_extra extra,
|
||||
+ union add_to_physmap_extra extra,
|
||||
unsigned long idx,
|
||||
gfn_t gfn)
|
||||
{
|
||||
@@ -1284,10 +1284,6 @@ int xenmem_add_to_physmap_one(
|
||||
break;
|
||||
}
|
||||
case XENMAPSPACE_dev_mmio:
|
||||
- /* extra should be 0. Reserved for future use. */
|
||||
- if ( extra.res0 )
|
||||
- return -EOPNOTSUPP;
|
||||
-
|
||||
rc = map_dev_mmio_region(d, gfn, 1, _mfn(idx));
|
||||
return rc;
|
||||
|
||||
--- a/xen/arch/x86/mm.c
|
||||
+++ b/xen/arch/x86/mm.c
|
||||
@@ -4653,7 +4653,7 @@ static int handle_iomem_range(unsigned l
|
||||
int xenmem_add_to_physmap_one(
|
||||
struct domain *d,
|
||||
unsigned int space,
|
||||
- union xen_add_to_physmap_batch_extra extra,
|
||||
+ union add_to_physmap_extra extra,
|
||||
unsigned long idx,
|
||||
gfn_t gpfn)
|
||||
{
|
||||
@@ -4740,9 +4740,20 @@ int xenmem_add_to_physmap_one(
|
||||
rc = guest_physmap_add_page(d, gpfn, mfn, PAGE_ORDER_4K);
|
||||
|
||||
put_both:
|
||||
- /* In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top. */
|
||||
+ /*
|
||||
+ * In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top.
|
||||
+ * We also may need to transfer ownership of the page reference to our
|
||||
+ * caller.
|
||||
+ */
|
||||
if ( space == XENMAPSPACE_gmfn )
|
||||
+ {
|
||||
put_gfn(d, gfn);
|
||||
+ if ( !rc && extra.ppage )
|
||||
+ {
|
||||
+ *extra.ppage = page;
|
||||
+ page = NULL;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
if ( page )
|
||||
put_page(page);
|
||||
--- a/xen/common/memory.c
|
||||
+++ b/xen/common/memory.c
|
||||
@@ -824,11 +824,10 @@ int xenmem_add_to_physmap(struct domain
|
||||
{
|
||||
unsigned int done = 0;
|
||||
long rc = 0;
|
||||
- union xen_add_to_physmap_batch_extra extra;
|
||||
+ union add_to_physmap_extra extra = {};
|
||||
+ struct page_info *pages[16];
|
||||
|
||||
- if ( xatp->space != XENMAPSPACE_gmfn_foreign )
|
||||
- extra.res0 = 0;
|
||||
- else
|
||||
+ if ( xatp->space == XENMAPSPACE_gmfn_foreign )
|
||||
extra.foreign_domid = DOMID_INVALID;
|
||||
|
||||
if ( xatp->space != XENMAPSPACE_gmfn_range )
|
||||
@@ -843,7 +842,10 @@ int xenmem_add_to_physmap(struct domain
|
||||
xatp->size -= start;
|
||||
|
||||
if ( has_iommu_pt(d) )
|
||||
+ {
|
||||
this_cpu(iommu_dont_flush_iotlb) = 1;
|
||||
+ extra.ppage = &pages[0];
|
||||
+ }
|
||||
|
||||
while ( xatp->size > done )
|
||||
{
|
||||
@@ -855,8 +857,12 @@ int xenmem_add_to_physmap(struct domain
|
||||
xatp->idx++;
|
||||
xatp->gpfn++;
|
||||
|
||||
+ if ( extra.ppage )
|
||||
+ ++extra.ppage;
|
||||
+
|
||||
/* Check for continuation if it's not the last iteration. */
|
||||
- if ( xatp->size > ++done && hypercall_preempt_check() )
|
||||
+ if ( (++done > ARRAY_SIZE(pages) && extra.ppage) ||
|
||||
+ (xatp->size > done && hypercall_preempt_check()) )
|
||||
{
|
||||
rc = start + done;
|
||||
break;
|
||||
@@ -866,6 +872,7 @@ int xenmem_add_to_physmap(struct domain
|
||||
if ( has_iommu_pt(d) )
|
||||
{
|
||||
int ret;
|
||||
+ unsigned int i;
|
||||
|
||||
this_cpu(iommu_dont_flush_iotlb) = 0;
|
||||
|
||||
@@ -874,6 +881,15 @@ int xenmem_add_to_physmap(struct domain
|
||||
if ( unlikely(ret) && rc >= 0 )
|
||||
rc = ret;
|
||||
|
||||
+ /*
|
||||
+ * Now that the IOMMU TLB flush was done for the original GFN, drop
|
||||
+ * the page references. The 2nd flush below is fine to make later, as
|
||||
+ * whoever removes the page again from its new GFN will have to do
|
||||
+ * another flush anyway.
|
||||
+ */
|
||||
+ for ( i = 0; i < done; ++i )
|
||||
+ put_page(pages[i]);
|
||||
+
|
||||
ret = iommu_iotlb_flush(d, _dfn(xatp->gpfn - done), done,
|
||||
IOMMU_FLUSHF_added | IOMMU_FLUSHF_modified);
|
||||
if ( unlikely(ret) && rc >= 0 )
|
||||
@@ -887,6 +903,8 @@ static int xenmem_add_to_physmap_batch(s
|
||||
struct xen_add_to_physmap_batch *xatpb,
|
||||
unsigned int extent)
|
||||
{
|
||||
+ union add_to_physmap_extra extra = {};
|
||||
+
|
||||
if ( xatpb->size < extent )
|
||||
return -EILSEQ;
|
||||
|
||||
@@ -895,6 +913,19 @@ static int xenmem_add_to_physmap_batch(s
|
||||
!guest_handle_subrange_okay(xatpb->errs, extent, xatpb->size - 1) )
|
||||
return -EFAULT;
|
||||
|
||||
+ switch ( xatpb->space )
|
||||
+ {
|
||||
+ case XENMAPSPACE_dev_mmio:
|
||||
+ /* res0 is reserved for future use. */
|
||||
+ if ( xatpb->u.res0 )
|
||||
+ return -EOPNOTSUPP;
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_gmfn_foreign:
|
||||
+ extra.foreign_domid = xatpb->u.foreign_domid;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
while ( xatpb->size > extent )
|
||||
{
|
||||
xen_ulong_t idx;
|
||||
@@ -907,8 +938,7 @@ static int xenmem_add_to_physmap_batch(s
|
||||
extent, 1)) )
|
||||
return -EFAULT;
|
||||
|
||||
- rc = xenmem_add_to_physmap_one(d, xatpb->space,
|
||||
- xatpb->u,
|
||||
+ rc = xenmem_add_to_physmap_one(d, xatpb->space, extra,
|
||||
idx, _gfn(gpfn));
|
||||
|
||||
if ( unlikely(__copy_to_guest_offset(xatpb->errs, extent, &rc, 1)) )
|
||||
--- a/xen/include/xen/mm.h
|
||||
+++ b/xen/include/xen/mm.h
|
||||
@@ -583,8 +583,22 @@ void scrub_one_page(struct page_info *);
|
||||
&(d)->xenpage_list : &(d)->page_list)
|
||||
#endif
|
||||
|
||||
+union add_to_physmap_extra {
|
||||
+ /*
|
||||
+ * XENMAPSPACE_gmfn: When deferring TLB flushes, a page reference needs
|
||||
+ * to be kept until after the flush, so the page can't get removed from
|
||||
+ * the domain (and re-used for another purpose) beforehand. By passing
|
||||
+ * non-NULL, the caller of xenmem_add_to_physmap_one() indicates it wants
|
||||
+ * to have ownership of such a reference transferred in the success case.
|
||||
+ */
|
||||
+ struct page_info **ppage;
|
||||
+
|
||||
+ /* XENMAPSPACE_gmfn_foreign */
|
||||
+ domid_t foreign_domid;
|
||||
+};
|
||||
+
|
||||
int xenmem_add_to_physmap_one(struct domain *d, unsigned int space,
|
||||
- union xen_add_to_physmap_batch_extra extra,
|
||||
+ union add_to_physmap_extra extra,
|
||||
unsigned long idx, gfn_t gfn);
|
||||
|
||||
int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp,
|
||||
52
xsa347-4.12-1.patch
Normal file
52
xsa347-4.12-1.patch
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: AMD/IOMMU: update live PTEs atomically
|
||||
|
||||
Updating a live PTE word by word allows the IOMMU to see a partially
|
||||
updated entry. Construct the new entry fully in a local variable and
|
||||
then write the new entry by a single insn.
|
||||
|
||||
This is part of XSA-347.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Paul Durrant <paul@xen.org>
|
||||
|
||||
--- a/xen/drivers/passthrough/amd/iommu_map.c
|
||||
+++ b/xen/drivers/passthrough/amd/iommu_map.c
|
||||
@@ -49,7 +49,7 @@ static unsigned int clear_iommu_pte_pres
|
||||
IOMMU_PTE_PRESENT_SHIFT) ?
|
||||
IOMMU_FLUSHF_modified : 0;
|
||||
|
||||
- *pte = 0;
|
||||
+ write_atomic(pte, 0);
|
||||
unmap_domain_page(table);
|
||||
|
||||
return flush_flags;
|
||||
@@ -60,7 +60,7 @@ static unsigned int set_iommu_pde_presen
|
||||
unsigned int next_level, bool iw,
|
||||
bool ir)
|
||||
{
|
||||
- uint64_t maddr_next;
|
||||
+ uint64_t maddr_next, full;
|
||||
uint32_t addr_lo, addr_hi, entry;
|
||||
bool old_present;
|
||||
unsigned int flush_flags = IOMMU_FLUSHF_added;
|
||||
@@ -119,7 +119,7 @@ static unsigned int set_iommu_pde_presen
|
||||
if ( next_level == 0 )
|
||||
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
|
||||
IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT, &entry);
|
||||
- pde[1] = entry;
|
||||
+ full = (uint64_t)entry << 32;
|
||||
|
||||
/* mark next level as 'present' */
|
||||
set_field_in_reg_u32(addr_lo >> PAGE_SHIFT, 0,
|
||||
@@ -131,7 +131,9 @@ static unsigned int set_iommu_pde_presen
|
||||
set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
|
||||
IOMMU_PDE_PRESENT_MASK,
|
||||
IOMMU_PDE_PRESENT_SHIFT, &entry);
|
||||
- pde[0] = entry;
|
||||
+ full |= entry;
|
||||
+
|
||||
+ write_atomic((uint64_t *)pde, full);
|
||||
|
||||
return flush_flags;
|
||||
}
|
||||
80
xsa347-4.12-2.patch
Normal file
80
xsa347-4.12-2.patch
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: AMD/IOMMU: ensure suitable ordering of DTE modifications
|
||||
|
||||
DMA and interrupt translation should be enabled only after other
|
||||
applicable DTE fields have been written. Similarly when disabling
|
||||
translation or when moving a device between domains, translation should
|
||||
first be disabled, before other entry fields get modified. Note however
|
||||
that the "moving" aspect doesn't apply to the interrupt remapping side,
|
||||
as domain specifics are maintained in the IRTEs here, not the DTE. We
|
||||
also never disable interrupt remapping once it got enabled for a device
|
||||
(the respective argument passed is always the immutable iommu_intremap).
|
||||
|
||||
This is part of XSA-347.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Paul Durrant <paul@xen.org>
|
||||
|
||||
--- a/xen/drivers/passthrough/amd/iommu_map.c
|
||||
+++ b/xen/drivers/passthrough/amd/iommu_map.c
|
||||
@@ -162,7 +162,22 @@ void amd_iommu_set_root_page_table(uint3
|
||||
uint16_t domain_id, uint8_t paging_mode,
|
||||
uint8_t valid)
|
||||
{
|
||||
- uint32_t addr_hi, addr_lo, entry;
|
||||
+ uint32_t addr_hi, addr_lo, entry, dte0 = dte[0];
|
||||
+
|
||||
+ if ( valid ||
|
||||
+ get_field_from_reg_u32(dte0, IOMMU_DEV_TABLE_VALID_MASK,
|
||||
+ IOMMU_DEV_TABLE_VALID_SHIFT) )
|
||||
+ {
|
||||
+ set_field_in_reg_u32(IOMMU_CONTROL_DISABLED, dte0,
|
||||
+ IOMMU_DEV_TABLE_TRANSLATION_VALID_MASK,
|
||||
+ IOMMU_DEV_TABLE_TRANSLATION_VALID_SHIFT, &dte0);
|
||||
+ set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, dte0,
|
||||
+ IOMMU_DEV_TABLE_VALID_MASK,
|
||||
+ IOMMU_DEV_TABLE_VALID_SHIFT, &dte0);
|
||||
+ dte[0] = dte0;
|
||||
+ smp_wmb();
|
||||
+ }
|
||||
+
|
||||
set_field_in_reg_u32(domain_id, 0,
|
||||
IOMMU_DEV_TABLE_DOMAIN_ID_MASK,
|
||||
IOMMU_DEV_TABLE_DOMAIN_ID_SHIFT, &entry);
|
||||
@@ -181,8 +196,9 @@ void amd_iommu_set_root_page_table(uint3
|
||||
IOMMU_DEV_TABLE_IO_READ_PERMISSION_MASK,
|
||||
IOMMU_DEV_TABLE_IO_READ_PERMISSION_SHIFT, &entry);
|
||||
dte[1] = entry;
|
||||
+ smp_wmb();
|
||||
|
||||
- set_field_in_reg_u32(addr_lo >> PAGE_SHIFT, 0,
|
||||
+ set_field_in_reg_u32(addr_lo >> PAGE_SHIFT, dte0,
|
||||
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_MASK,
|
||||
IOMMU_DEV_TABLE_PAGE_TABLE_PTR_LOW_SHIFT, &entry);
|
||||
set_field_in_reg_u32(paging_mode, entry,
|
||||
@@ -195,7 +211,7 @@ void amd_iommu_set_root_page_table(uint3
|
||||
IOMMU_CONTROL_DISABLED, entry,
|
||||
IOMMU_DEV_TABLE_VALID_MASK,
|
||||
IOMMU_DEV_TABLE_VALID_SHIFT, &entry);
|
||||
- dte[0] = entry;
|
||||
+ write_atomic(&dte[0], entry);
|
||||
}
|
||||
|
||||
void iommu_dte_set_iotlb(uint32_t *dte, uint8_t i)
|
||||
@@ -226,6 +242,7 @@ void __init amd_iommu_set_intremap_table
|
||||
IOMMU_DEV_TABLE_INT_CONTROL_MASK,
|
||||
IOMMU_DEV_TABLE_INT_CONTROL_SHIFT, &entry);
|
||||
dte[5] = entry;
|
||||
+ smp_wmb();
|
||||
|
||||
set_field_in_reg_u32(addr_lo >> 6, 0,
|
||||
IOMMU_DEV_TABLE_INT_TABLE_PTR_LOW_MASK,
|
||||
@@ -243,7 +260,7 @@ void __init amd_iommu_set_intremap_table
|
||||
IOMMU_CONTROL_DISABLED, entry,
|
||||
IOMMU_DEV_TABLE_INT_VALID_MASK,
|
||||
IOMMU_DEV_TABLE_INT_VALID_SHIFT, &entry);
|
||||
- dte[4] = entry;
|
||||
+ write_atomic(&dte[4], entry);
|
||||
}
|
||||
|
||||
void __init iommu_dte_add_device_entry(uint32_t *dte,
|
||||
30
xsa483.patch
30
xsa483.patch
|
|
@ -1,30 +0,0 @@
|
|||
From: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
Subject: tools/oxenstored: Reset quota when resetting permissions
|
||||
|
||||
The quota object contains both limits and the current node usage counts.
|
||||
|
||||
When a domain is torn down, the node data itself is cleaned up but the node
|
||||
usage counts are not. A later domain reusing the same domid can create fewer
|
||||
nodes before being deemed to be over quota.
|
||||
|
||||
Reset the count when the node permissions are cleaned up.
|
||||
|
||||
This is XSA-483 / CVE-2026-23556.
|
||||
|
||||
Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
|
||||
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
|
||||
index 9b8dd2812df0..aa9204ead3ec 100644
|
||||
--- a/tools/ocaml/xenstored/store.ml
|
||||
+++ b/tools/ocaml/xenstored/store.ml
|
||||
@@ -465,7 +465,8 @@ let reset_permissions store domid =
|
||||
if perms <> node.perms then
|
||||
Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
|
||||
Some { node with Node.perms }
|
||||
- ) store.root
|
||||
+ ) store.root;
|
||||
+ store.quota <- Quota.del store.quota domid
|
||||
|
||||
type ops = {
|
||||
store: t;
|
||||
89
xsa484.patch
89
xsa484.patch
|
|
@ -1,89 +0,0 @@
|
|||
From 3d0d19ad17f29c64dde4a7baf392da4fd58f3654 Mon Sep 17 00:00:00 2001
|
||||
From: Juergen Gross <jgross@suse.com>
|
||||
Date: Mon, 16 Mar 2026 15:06:11 +0100
|
||||
Subject: [PATCH] tools/xenstored: make conn_delete_all_transactions()
|
||||
idempotent
|
||||
|
||||
conn_delete_all_transactions() should be callable in any context,
|
||||
resetting ALL transaction related data.
|
||||
|
||||
This includes number of active transactions and the transaction
|
||||
pointer in struct connection.
|
||||
|
||||
So reset conn->trans to NULL in conn_delete_all_transactions() and
|
||||
do the cleanup for each transaction in destroy_transaction().
|
||||
|
||||
This avoids triggering the assert() in conn_delete_all_transactions()
|
||||
in case e.g. ignore_connection() was called while an operation inside
|
||||
a transaction was performed, or XS_RESET_WATCHES was called in a
|
||||
transaction.
|
||||
|
||||
This is XSA-484 / CVE-2026-23557.
|
||||
|
||||
Reported-by: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
Fixes: 1f9d04fb021c ("xenstored: allow guest to shutdown all its watches/transactions")
|
||||
Signed-off-by: Juergen Gross <jgross@suse.com>
|
||||
---
|
||||
tools/xenstored/transaction.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/tools/xenstored/transaction.c b/tools/xenstored/transaction.c
|
||||
index 167cd597fd..0825c48859 100644
|
||||
--- a/tools/xenstored/transaction.c
|
||||
+++ b/tools/xenstored/transaction.c
|
||||
@@ -432,17 +432,23 @@ static int finalize_transaction(struct connection *conn,
|
||||
static int destroy_transaction(void *_transaction)
|
||||
{
|
||||
struct transaction *trans = _transaction;
|
||||
+ struct connection *conn = trans->conn;
|
||||
struct accessed_node *i;
|
||||
|
||||
wrl_ntransactions--;
|
||||
trace_destroy(trans, "transaction");
|
||||
while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
|
||||
if (i->ta_node)
|
||||
- db_delete(trans->conn, i->trans_name, NULL);
|
||||
+ db_delete(conn, i->trans_name, NULL);
|
||||
list_del(&i->list);
|
||||
talloc_free(i);
|
||||
}
|
||||
|
||||
+ list_del(&trans->list);
|
||||
+ domain_transaction_dec(conn);
|
||||
+ if (list_empty(&conn->transaction_list))
|
||||
+ conn->ta_start_time = 0;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -523,10 +529,6 @@ int do_transaction_end(const void *ctx, struct connection *conn,
|
||||
return ENOENT;
|
||||
|
||||
conn->transaction = NULL;
|
||||
- list_del(&trans->list);
|
||||
- domain_transaction_dec(conn);
|
||||
- if (list_empty(&conn->transaction_list))
|
||||
- conn->ta_start_time = 0;
|
||||
|
||||
chk_quota = trans->node_created && domain_is_unprivileged(conn);
|
||||
|
||||
@@ -572,14 +574,10 @@ void conn_delete_all_transactions(struct connection *conn)
|
||||
struct transaction *trans;
|
||||
|
||||
while ((trans = list_top(&conn->transaction_list,
|
||||
- struct transaction, list))) {
|
||||
- list_del(&trans->list);
|
||||
+ struct transaction, list)))
|
||||
talloc_free(trans);
|
||||
- }
|
||||
-
|
||||
- assert(conn->transaction == NULL);
|
||||
|
||||
- conn->ta_start_time = 0;
|
||||
+ conn->transaction = NULL;
|
||||
}
|
||||
|
||||
int check_transactions(struct hashtable *hash)
|
||||
--
|
||||
2.53.0
|
||||
|
||||
181
xsa486.patch
181
xsa486.patch
|
|
@ -1,181 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: gnttab: split gnttab_map_frame()
|
||||
|
||||
If a domain tries to map status frames in parallel to switching grant
|
||||
table version from 2 to 1, the mapping operation may put in place P2M
|
||||
entries referencing MFNs which gnttab_unpopulate_status_frames() is in the
|
||||
process of freeing.
|
||||
|
||||
Ideally we would refcount pages when entered into P2M tables, but that's a
|
||||
significant change. Extend the grant-table-locked region instead in
|
||||
xenmem_add_to_physmap_one() (being the sole caller of gnttab_map_frame()),
|
||||
such that a race with gnttab_unpopulate_status_frames() is no longer
|
||||
possible.
|
||||
|
||||
This is XSA-486 / CVE-2026-23558.
|
||||
|
||||
Fixes: 5ce8fafa947c ("Dynamic grant-table sizing")
|
||||
Fixes: a98dc13703e0 ("Introduce a grant_entry_v2 structure")
|
||||
Reported-by: Rafal Wojtczuk <rafal.wojtczuk@7bulls.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/arm/mm.c
|
||||
+++ b/xen/arch/arm/mm.c
|
||||
@@ -174,12 +174,10 @@ int xenmem_add_to_physmap_one(
|
||||
switch ( space )
|
||||
{
|
||||
case XENMAPSPACE_grant_table:
|
||||
- rc = gnttab_map_frame(d, idx, gfn, &mfn);
|
||||
+ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
- /* Need to take care of the reference obtained in gnttab_map_frame(). */
|
||||
- page = mfn_to_page(mfn);
|
||||
t = p2m_ram_rw;
|
||||
|
||||
break;
|
||||
@@ -281,10 +279,23 @@ int xenmem_add_to_physmap_one(
|
||||
* to drop the reference we took earlier. In all other cases we need to
|
||||
* drop any reference we took earlier (perhaps indirectly).
|
||||
*/
|
||||
- if ( space == XENMAPSPACE_gmfn_foreign ? rc : page != NULL )
|
||||
+ switch ( space )
|
||||
{
|
||||
+ default:
|
||||
+ if ( page )
|
||||
+ put_page(page);
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_grant_table:
|
||||
+ gnttab_map_frame_end(d, mfn);
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_gmfn_foreign:
|
||||
+ if ( !rc )
|
||||
+ break;
|
||||
ASSERT(page != NULL);
|
||||
put_page(page);
|
||||
+ break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
--- a/xen/arch/x86/mm/p2m.c
|
||||
+++ b/xen/arch/x86/mm/p2m.c
|
||||
@@ -2009,11 +2009,9 @@ int xenmem_add_to_physmap_one(
|
||||
break;
|
||||
|
||||
case XENMAPSPACE_grant_table:
|
||||
- rc = gnttab_map_frame(d, idx, gfn, &mfn);
|
||||
+ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn);
|
||||
if ( rc )
|
||||
return rc;
|
||||
- /* Need to take care of the reference obtained in gnttab_map_frame(). */
|
||||
- page = mfn_to_page(mfn);
|
||||
break;
|
||||
|
||||
case XENMAPSPACE_gmfn:
|
||||
@@ -2095,19 +2093,28 @@ int xenmem_add_to_physmap_one(
|
||||
put_gfn(d, gfn_x(gfn));
|
||||
|
||||
put_both:
|
||||
- /*
|
||||
- * In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top.
|
||||
- * We also may need to transfer ownership of the page reference to our
|
||||
- * caller.
|
||||
- */
|
||||
- if ( space == XENMAPSPACE_gmfn )
|
||||
+ switch ( space )
|
||||
{
|
||||
+ case XENMAPSPACE_gmfn:
|
||||
+ /*
|
||||
+ * We took a ref of the gfn at the top. We also may need to transfer
|
||||
+ * ownership of the page reference to our caller.
|
||||
+ */
|
||||
put_gfn(d, gmfn);
|
||||
if ( !rc && extra.ppage )
|
||||
{
|
||||
*extra.ppage = page;
|
||||
page = NULL;
|
||||
}
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_grant_table:
|
||||
+ /*
|
||||
+ * We (gnttab_map_frame_begin()) acquired a lock and took a ref of the
|
||||
+ * page underlying the MFN at the top.
|
||||
+ */
|
||||
+ gnttab_map_frame_end(d, mfn);
|
||||
+ break;
|
||||
}
|
||||
|
||||
if ( page )
|
||||
--- a/xen/common/grant_table.c
|
||||
+++ b/xen/common/grant_table.c
|
||||
@@ -4250,7 +4250,8 @@ int gnttab_acquire_resource(
|
||||
return rc;
|
||||
}
|
||||
|
||||
-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn)
|
||||
+int gnttab_map_frame_begin(
|
||||
+ struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn)
|
||||
{
|
||||
int rc = 0;
|
||||
struct grant_table *gt = d->grant_table;
|
||||
@@ -4288,11 +4289,19 @@ int gnttab_map_frame(struct domain *d, u
|
||||
put_page(pg);
|
||||
}
|
||||
|
||||
- grant_write_unlock(gt);
|
||||
+ if ( rc )
|
||||
+ grant_write_unlock(d->grant_table);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
+void gnttab_map_frame_end(struct domain *d, mfn_t mfn)
|
||||
+{
|
||||
+ put_page(mfn_to_page(mfn));
|
||||
+
|
||||
+ grant_write_unlock(d->grant_table);
|
||||
+}
|
||||
+
|
||||
static void gnttab_usage_print(struct domain *rd)
|
||||
{
|
||||
int first = 1;
|
||||
--- a/xen/include/xen/grant_table.h
|
||||
+++ b/xen/include/xen/grant_table.h
|
||||
@@ -60,8 +60,13 @@ int gnttab_release_mappings(struct domai
|
||||
int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
|
||||
gfn_t *gfn, uint16_t *status);
|
||||
|
||||
-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
- mfn_t *mfn);
|
||||
+/*
|
||||
+ * These need to be used as a pair, as the first (in the success case) returns
|
||||
+ * with a lock and page reference held which the second needs to drop.
|
||||
+ */
|
||||
+int gnttab_map_frame_begin(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
+ mfn_t *mfn);
|
||||
+void gnttab_map_frame_end(struct domain *d, mfn_t mfn);
|
||||
|
||||
unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id);
|
||||
|
||||
@@ -100,12 +105,14 @@ static inline int mem_sharing_gref_to_gf
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
-static inline int gnttab_map_frame(struct domain *d, unsigned long idx,
|
||||
- gfn_t gfn, mfn_t *mfn)
|
||||
+static inline int gnttab_map_frame_begin(struct domain *d, unsigned long idx,
|
||||
+ gfn_t gfn, mfn_t *mfn)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+static inline void gnttab_map_frame_end(struct domain *d, mfn_t mfn) {}
|
||||
+
|
||||
static inline unsigned int gnttab_resource_max_frames(
|
||||
const struct domain *d, unsigned int id)
|
||||
{
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/amd: Mitigate AMD-SN-7052
|
||||
|
||||
This is XSA-490 / CVE-2025-54518.
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
|
||||
index 1bb0766ebf13..b5bf2b732e8f 100644
|
||||
--- a/xen/arch/x86/cpu/amd.c
|
||||
+++ b/xen/arch/x86/cpu/amd.c
|
||||
@@ -1116,11 +1116,25 @@ static void amd_check_bp_cfg(void)
|
||||
{
|
||||
uint64_t val, new = 0;
|
||||
|
||||
- /*
|
||||
- * AMD Erratum #1485. Set bit 5, as instructed.
|
||||
- */
|
||||
- if (!cpu_has_hypervisor && boot_cpu_data.x86 == 0x19 && is_zen4_uarch())
|
||||
- new |= (1 << 5);
|
||||
+ if (!cpu_has_hypervisor) {
|
||||
+ /*
|
||||
+ * AMD Erratum #1485. If SMT is enabled and STIBP disabled,
|
||||
+ * the CPU may fetch incorrect instruction bytes.
|
||||
+ *
|
||||
+ * Set bit 5, as instructed.
|
||||
+ */
|
||||
+ if (boot_cpu_data.x86 == 0x19 && is_zen4_uarch())
|
||||
+ new |= (1 << 5);
|
||||
+
|
||||
+ /*
|
||||
+ * AMD SB-7052. CPU OP Cache corruption, causing instructions
|
||||
+ * to be executed at a higher privilege.
|
||||
+ *
|
||||
+ * Set bit 33, as instructed.
|
||||
+ */
|
||||
+ if (boot_cpu_data.x86 == 0x17 && is_zen2_uarch())
|
||||
+ new |= (1UL << 33);
|
||||
+ }
|
||||
|
||||
/*
|
||||
* On hardware supporting SRSO_MSR_FIX, activate BP_SPEC_REDUCE by
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/HVM: add locking to I/O port translation list traversal
|
||||
|
||||
XEN_DOMCTL_ioport_mapping is usable by DM stubdoms, and hence we can't
|
||||
assume the list to be left unaltered while the guest (really: the
|
||||
hypervisor on behalf of the guest) is accessing it.
|
||||
|
||||
This is XSA-491 / CVE-2026-42487.
|
||||
|
||||
Fixes: 192c4dabc344 ("domctl and p2m changes for PCI passthru")
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/x86/domctl.c
|
||||
+++ b/xen/arch/x86/domctl.c
|
||||
@@ -663,6 +663,7 @@ long arch_do_domctl(
|
||||
"ioport_map:add: dom%d gport=%x mport=%x nr=%x\n",
|
||||
d->domain_id, fgp, fmp, np);
|
||||
|
||||
+ write_lock(&hvm->g2m_ioport_lock);
|
||||
list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list)
|
||||
if (g2m_ioport->mport == fmp )
|
||||
{
|
||||
@@ -684,11 +685,14 @@ long arch_do_domctl(
|
||||
g2m_ioport->np = np;
|
||||
list_add_tail(&g2m_ioport->list, &hvm->g2m_ioport_list);
|
||||
}
|
||||
+ write_unlock(&hvm->g2m_ioport_lock);
|
||||
if ( !ret )
|
||||
ret = ioports_permit_access(d, fmp, fmp + np - 1);
|
||||
if ( ret && !found && g2m_ioport )
|
||||
{
|
||||
+ write_lock(&hvm->g2m_ioport_lock);
|
||||
list_del(&g2m_ioport->list);
|
||||
+ write_unlock(&hvm->g2m_ioport_lock);
|
||||
xfree(g2m_ioport);
|
||||
}
|
||||
}
|
||||
@@ -697,6 +701,8 @@ long arch_do_domctl(
|
||||
printk(XENLOG_G_INFO
|
||||
"ioport_map:remove: dom%d gport=%x mport=%x nr=%x\n",
|
||||
d->domain_id, fgp, fmp, np);
|
||||
+
|
||||
+ write_lock(&hvm->g2m_ioport_lock);
|
||||
list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list)
|
||||
if ( g2m_ioport->mport == fmp )
|
||||
{
|
||||
@@ -704,6 +710,8 @@ long arch_do_domctl(
|
||||
xfree(g2m_ioport);
|
||||
break;
|
||||
}
|
||||
+ write_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
ret = ioports_deny_access(d, fmp, fmp + np - 1);
|
||||
if ( ret && is_hardware_domain(currd) )
|
||||
printk(XENLOG_ERR
|
||||
--- a/xen/arch/x86/hvm/emulate.c
|
||||
+++ b/xen/arch/x86/hvm/emulate.c
|
||||
@@ -160,7 +160,6 @@ void hvmemul_cancel(struct vcpu *v)
|
||||
hvio->mmio_insn_bytes = 0;
|
||||
hvio->mmio_access = (struct npfec){};
|
||||
hvio->mmio_retry = false;
|
||||
- hvio->g2m_ioport = NULL;
|
||||
|
||||
hvmemul_cache_disable(v);
|
||||
}
|
||||
--- a/xen/arch/x86/hvm/hvm.c
|
||||
+++ b/xen/arch/x86/hvm/hvm.c
|
||||
@@ -610,6 +610,7 @@ int hvm_domain_initialise(struct domain
|
||||
spin_lock_init(&d->arch.hvm.irq_lock);
|
||||
spin_lock_init(&d->arch.hvm.uc_lock);
|
||||
spin_lock_init(&d->arch.hvm.write_map.lock);
|
||||
+ rwlock_init(&d->arch.hvm.g2m_ioport_lock);
|
||||
rwlock_init(&d->arch.hvm.mmcfg_lock);
|
||||
INIT_LIST_HEAD(&d->arch.hvm.write_map.list);
|
||||
INIT_LIST_HEAD(&d->arch.hvm.g2m_ioport_list);
|
||||
--- a/xen/arch/x86/hvm/io.c
|
||||
+++ b/xen/arch/x86/hvm/io.c
|
||||
@@ -143,36 +143,56 @@ bool handle_pio(uint16_t port, unsigned
|
||||
return true;
|
||||
}
|
||||
|
||||
-static bool cf_check g2m_portio_accept(
|
||||
- const struct hvm_io_handler *handler, const ioreq_t *p)
|
||||
+/* NB: Returns with the lock held in the success case. */
|
||||
+static const struct g2m_ioport *g2m_portio_find_and_lock(struct hvm_domain *hvm,
|
||||
+ uint64_t addr,
|
||||
+ uint32_t size)
|
||||
{
|
||||
- struct vcpu *curr = current;
|
||||
- const struct hvm_domain *hvm = &curr->domain->arch.hvm;
|
||||
- struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io;
|
||||
- struct g2m_ioport *g2m_ioport;
|
||||
- unsigned int start, end;
|
||||
+ const struct g2m_ioport *g2m_ioport;
|
||||
+
|
||||
+ read_lock(&hvm->g2m_ioport_lock);
|
||||
|
||||
list_for_each_entry( g2m_ioport, &hvm->g2m_ioport_list, list )
|
||||
{
|
||||
- start = g2m_ioport->gport;
|
||||
- end = start + g2m_ioport->np;
|
||||
- if ( (p->addr >= start) && (p->addr + p->size <= end) )
|
||||
- {
|
||||
- hvio->g2m_ioport = g2m_ioport;
|
||||
- return 1;
|
||||
- }
|
||||
+ unsigned int start = g2m_ioport->gport;
|
||||
+
|
||||
+ if ( addr >= start && addr + size <= start + g2m_ioport->np )
|
||||
+ return g2m_ioport;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static bool cf_check g2m_portio_accept(
|
||||
+ const struct hvm_io_handler *handler, const ioreq_t *p)
|
||||
+{
|
||||
+ struct hvm_domain *hvm = ¤t->domain->arch.hvm;
|
||||
+ const struct g2m_ioport *g2m_ioport =
|
||||
+ g2m_portio_find_and_lock(hvm, p->addr, p->size);
|
||||
+
|
||||
+ if ( !g2m_ioport )
|
||||
+ return false;
|
||||
+
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
+ return true;
|
||||
}
|
||||
|
||||
static int cf_check g2m_portio_read(
|
||||
const struct hvm_io_handler *handler, uint64_t addr, uint32_t size,
|
||||
uint64_t *data)
|
||||
{
|
||||
- struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io;
|
||||
- const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport;
|
||||
- unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport;
|
||||
+ struct hvm_domain *hvm = ¤t->domain->arch.hvm;
|
||||
+ const struct g2m_ioport *g2m_ioport =
|
||||
+ g2m_portio_find_and_lock(hvm, addr, size);
|
||||
+ unsigned int mport;
|
||||
+
|
||||
+ if ( !g2m_ioport )
|
||||
+ return X86EMUL_RETRY;
|
||||
+
|
||||
+ mport = addr - g2m_ioport->gport + g2m_ioport->mport;
|
||||
|
||||
switch ( size )
|
||||
{
|
||||
@@ -189,6 +209,8 @@ static int cf_check g2m_portio_read(
|
||||
BUG();
|
||||
}
|
||||
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
@@ -196,9 +218,15 @@ static int cf_check g2m_portio_write(
|
||||
const struct hvm_io_handler *handler, uint64_t addr, uint32_t size,
|
||||
uint64_t data)
|
||||
{
|
||||
- struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io;
|
||||
- const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport;
|
||||
- unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport;
|
||||
+ struct hvm_domain *hvm = ¤t->domain->arch.hvm;
|
||||
+ const struct g2m_ioport *g2m_ioport =
|
||||
+ g2m_portio_find_and_lock(hvm, addr, size);
|
||||
+ unsigned int mport;
|
||||
+
|
||||
+ if ( !g2m_ioport )
|
||||
+ return X86EMUL_RETRY;
|
||||
+
|
||||
+ mport = addr - g2m_ioport->gport + g2m_ioport->mport;
|
||||
|
||||
switch ( size )
|
||||
{
|
||||
@@ -215,6 +243,8 @@ static int cf_check g2m_portio_write(
|
||||
BUG();
|
||||
}
|
||||
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
--- a/xen/arch/x86/include/asm/hvm/domain.h
|
||||
+++ b/xen/arch/x86/include/asm/hvm/domain.h
|
||||
@@ -125,6 +125,7 @@ struct hvm_domain {
|
||||
|
||||
/* List of guest to machine IO ports mapping. */
|
||||
struct list_head g2m_ioport_list;
|
||||
+ rwlock_t g2m_ioport_lock;
|
||||
|
||||
/* List of MMCFG regions trapped by Xen. */
|
||||
struct list_head mmcfg_regions;
|
||||
--- a/xen/arch/x86/include/asm/hvm/vcpu.h
|
||||
+++ b/xen/arch/x86/include/asm/hvm/vcpu.h
|
||||
@@ -54,8 +54,6 @@ struct hvm_vcpu_io {
|
||||
unsigned long msix_unmask_address;
|
||||
unsigned long msix_snoop_address;
|
||||
unsigned long msix_snoop_gpa;
|
||||
-
|
||||
- const struct g2m_ioport *g2m_ioport;
|
||||
};
|
||||
|
||||
struct nestedvcpu {
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: sched: use sequence counter to enlighten vcpu_runstate_get()
|
||||
|
||||
Subsequently XEN_DOMCTL_getdomaininfo will want to invoke the function
|
||||
without holding a lock, thus allowing parallel execution of potentially
|
||||
many instances. As was learned from 228ab9992ffb ("domctl: improve
|
||||
locking during domain destruction"), reverted by d0887cc6b16e, such
|
||||
parallelism can result in severe lock contention on any (previously)
|
||||
inner lock. To avoid taking that risk replace the use of the scheduler
|
||||
lock in vcpu_runstate_get() by a newly introduced sequence counter.
|
||||
Convert the "no lock if current" property to "use a local counter
|
||||
instance", thus guaranteeing the loop to exit after the first iteration.
|
||||
|
||||
Skeleton and commentary of the seqcount implementation based on /
|
||||
derived from Linux 6.11-rc.
|
||||
|
||||
To have runstate_seq placed next to runstate in struct vcpu, without
|
||||
introducing a new obvious padding hole, yet while keeping the latter
|
||||
adjacent to runstate_guest{,_area} as well, move runstate down a little.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Requested-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Juergen Gross <jgross@suse.com>
|
||||
|
||||
--- a/xen/common/sched/core.c
|
||||
+++ b/xen/common/sched/core.c
|
||||
@@ -281,13 +281,18 @@ static inline void vcpu_runstate_change(
|
||||
}
|
||||
|
||||
delta = new_entry_time - v->runstate.state_entry_time;
|
||||
- if ( delta > 0 )
|
||||
+
|
||||
+ /* Serialization: ->schedule_lock (see ASSERT() above). */
|
||||
+ with_seq_write(&v->runstate_seq)
|
||||
{
|
||||
- v->runstate.time[v->runstate.state] += delta;
|
||||
- v->runstate.state_entry_time = new_entry_time;
|
||||
- }
|
||||
+ if ( delta > 0 )
|
||||
+ {
|
||||
+ v->runstate.time[v->runstate.state] += delta;
|
||||
+ v->runstate.state_entry_time = new_entry_time;
|
||||
+ }
|
||||
|
||||
- v->runstate.state = new_state;
|
||||
+ v->runstate.state = new_state;
|
||||
+ }
|
||||
}
|
||||
|
||||
void sched_guest_idle(void (*idle) (void), unsigned int cpu)
|
||||
@@ -307,30 +312,18 @@ void sched_guest_idle(void (*idle) (void
|
||||
void vcpu_runstate_get(const struct vcpu *v,
|
||||
struct vcpu_runstate_info *runstate)
|
||||
{
|
||||
- spinlock_t *lock;
|
||||
- s_time_t delta;
|
||||
- struct sched_unit *unit;
|
||||
+ struct seqcount seq = SEQCNT_ZERO();
|
||||
+ const struct seqcount *s = likely(v == current) ? &seq : &v->runstate_seq;
|
||||
|
||||
- rcu_read_lock(&sched_res_rculock);
|
||||
-
|
||||
- /*
|
||||
- * Be careful in case of an idle vcpu: the assignment to a unit might
|
||||
- * change even with the scheduling lock held, so be sure to use the
|
||||
- * correct unit for locking in order to avoid triggering an ASSERT() in
|
||||
- * the unlock function.
|
||||
- */
|
||||
- unit = is_idle_vcpu(v) ? get_sched_res(v->processor)->sched_unit_idle
|
||||
- : v->sched_unit;
|
||||
- lock = likely(v == current) ? NULL : unit_schedule_lock_irq(unit);
|
||||
- memcpy(runstate, &v->runstate, sizeof(*runstate));
|
||||
- delta = NOW() - runstate->state_entry_time;
|
||||
- if ( delta > 0 )
|
||||
- runstate->time[runstate->state] += delta;
|
||||
-
|
||||
- if ( unlikely(lock != NULL) )
|
||||
- unit_schedule_unlock_irq(lock, unit);
|
||||
+ until_seq_read(s)
|
||||
+ {
|
||||
+ s_time_t delta;
|
||||
|
||||
- rcu_read_unlock(&sched_res_rculock);
|
||||
+ *runstate = v->runstate;
|
||||
+ delta = NOW() - runstate->state_entry_time;
|
||||
+ if ( delta > 0 )
|
||||
+ runstate->time[runstate->state] += delta;
|
||||
+ }
|
||||
}
|
||||
|
||||
uint64_t get_cpu_idle_time(unsigned int cpu)
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xen/radix-tree.h>
|
||||
#include <xen/multicall.h>
|
||||
#include <xen/nospec.h>
|
||||
+#include <xen/seqcount.h>
|
||||
#include <xen/tasklet.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/smp.h>
|
||||
@@ -198,7 +199,6 @@ struct vcpu
|
||||
|
||||
struct sched_unit *sched_unit;
|
||||
|
||||
- struct vcpu_runstate_info runstate;
|
||||
#ifndef CONFIG_COMPAT
|
||||
# define runstate_guest(v) ((v)->runstate_guest)
|
||||
XEN_GUEST_HANDLE(vcpu_runstate_info_t) runstate_guest; /* guest address */
|
||||
@@ -210,6 +210,8 @@ struct vcpu
|
||||
} runstate_guest; /* guest address */
|
||||
#endif
|
||||
struct guest_area runstate_guest_area;
|
||||
+ struct vcpu_runstate_info runstate;
|
||||
+ struct seqcount runstate_seq;
|
||||
unsigned int new_state;
|
||||
|
||||
/* Has the FPU been initialised? */
|
||||
--- /dev/null
|
||||
+++ b/xen/include/xen/seqcount.h
|
||||
@@ -0,0 +1,139 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+#ifndef XEN_SEQCOUNT_H
|
||||
+#define XEN_SEQCOUNT_H
|
||||
+
|
||||
+#include <xen/lib.h>
|
||||
+#include <xen/nospec.h>
|
||||
+
|
||||
+#include <asm/atomic.h>
|
||||
+#include <asm/system.h>
|
||||
+
|
||||
+/*
|
||||
+ * Sequence counters (seqcount_t)
|
||||
+ *
|
||||
+ * This is the raw counting mechanism, without any writer protection.
|
||||
+ *
|
||||
+ * Write side critical sections must be serialized (and non-preemptible).
|
||||
+ *
|
||||
+ * If readers can be invoked from interrupt contexts, interrupts must also
|
||||
+ * be respectively disabled before entering the write section.
|
||||
+ *
|
||||
+ * This mechanism can't be used if the protected data contains pointers,
|
||||
+ * as the writer can invalidate a pointer that a reader is following.
|
||||
+ */
|
||||
+struct seqcount {
|
||||
+ unsigned int sequence;
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * SEQCNT_ZERO() - initializer for seqcount_t
|
||||
+ * @name: Name of the struct seqcount instance
|
||||
+ */
|
||||
+#define SEQCNT_ZERO() { .sequence = 0 }
|
||||
+
|
||||
+static inline unsigned int seqprop_sequence(const struct seqcount *s)
|
||||
+{
|
||||
+ return ACCESS_ONCE(s->sequence);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * read_seqcount_begin() - begin a seqcount read critical section
|
||||
+ * @s: Pointer to struct seqcount
|
||||
+ *
|
||||
+ * Return: count to be passed to read_seqcount_retry()
|
||||
+ */
|
||||
+static inline unsigned int _read_seqcount_begin(const struct seqcount *s)
|
||||
+{
|
||||
+ unsigned int seq;
|
||||
+
|
||||
+ while ((seq = seqprop_sequence(s)) & 1)
|
||||
+ cpu_relax();
|
||||
+
|
||||
+ smp_rmb();
|
||||
+
|
||||
+ return seq;
|
||||
+}
|
||||
+
|
||||
+static always_inline unsigned int read_seqcount_begin(const struct seqcount *s)
|
||||
+{
|
||||
+ unsigned int seq = _read_seqcount_begin(s);
|
||||
+
|
||||
+ block_lock_speculation();
|
||||
+
|
||||
+ return seq;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * read_seqcount_retry() - end a seqcount read critical section
|
||||
+ * @s: Pointer to struct seqcount
|
||||
+ * @start: count, from read_seqcount_begin()
|
||||
+ *
|
||||
+ * read_seqcount_retry closes the read critical section of given struct
|
||||
+ * seqcount. If the critical section was invalid, it must be ignored
|
||||
+ * (and typically retried).
|
||||
+ *
|
||||
+ * Return: true if a read section retry is required, else false
|
||||
+ */
|
||||
+static inline bool _read_seqcount_retry(const struct seqcount *s,
|
||||
+ unsigned int start)
|
||||
+{
|
||||
+ smp_rmb();
|
||||
+ return unlikely(seqprop_sequence(s) != start);
|
||||
+}
|
||||
+
|
||||
+static always_inline bool read_seqcount_retry(const struct seqcount *s,
|
||||
+ unsigned int start)
|
||||
+{
|
||||
+ return lock_evaluate_nospec(_read_seqcount_retry(s, start));
|
||||
+}
|
||||
+
|
||||
+/* Loops until a consistent count has been observed across the loop body. */
|
||||
+#define until_seq_read(seq) \
|
||||
+ for ( unsigned int retry_ = 1, count_; \
|
||||
+ retry_ && (count_ = read_seqcount_begin(seq), true); \
|
||||
+ retry_ = read_seqcount_retry(seq, count_) )
|
||||
+
|
||||
+/*
|
||||
+ * write_seqcount_begin() - start a struct seqcount write side critical section
|
||||
+ * @s: Pointer to struct seqcount
|
||||
+ *
|
||||
+ * Context: sequence counter write side sections must be serialized.
|
||||
+ * If readers can be invoked from interrupt context, interrupts must be
|
||||
+ * respectively disabled.
|
||||
+ */
|
||||
+static inline void write_seqcount_begin(struct seqcount *s)
|
||||
+{
|
||||
+ add_sized(&s->sequence, 1);
|
||||
+ smp_wmb();
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * write_seqcount_end() - end a struct seqcount write side critical section
|
||||
+ * @s: Pointer to seqcount
|
||||
+ */
|
||||
+static inline void write_seqcount_end(struct seqcount *s)
|
||||
+{
|
||||
+ smp_wmb();
|
||||
+ add_sized(&s->sequence, 1);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Not really a loop, but we need write_seqcount_{begin,end}() in the correct
|
||||
+ * position.
|
||||
+ */
|
||||
+#define with_seq_write(seq) \
|
||||
+ for ( bool once_ = true; \
|
||||
+ once_ && (write_seqcount_begin(seq), true); \
|
||||
+ (write_seqcount_end(seq), once_ = false) )
|
||||
+
|
||||
+#endif /* XEN_SEQCOUNT_H */
|
||||
+
|
||||
+/*
|
||||
+ * Local variables:
|
||||
+ * mode: C
|
||||
+ * c-file-style: "BSD"
|
||||
+ * c-basic-offset: 4
|
||||
+ * tab-width: 4
|
||||
+ * indent-tabs-mode: nil
|
||||
+ * End:
|
||||
+ */
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domctl: handle XEN_DOMCTL_getdomaininfo without acquiring domctl lock
|
||||
|
||||
getdomaininfo() is not called under consistently the same lock. Thus,
|
||||
with caller side locking irrelevant, it can as well be called with the
|
||||
domctl lock not held. (Callers not pausing the domain they want to
|
||||
retrieve information for already need to be aware that not all of the
|
||||
data returned can be relied on as being consistent; most data will also
|
||||
be stale by the time the caller gets to look at it.)
|
||||
|
||||
Move the handling not only ahead of acquiring the lock, but also ahead
|
||||
of the XSM check, leveraging that the sub-op has its own hook.
|
||||
|
||||
While moving, convert an assignment to an assertion: The domain in
|
||||
question was determined from the field which previously was "updated".
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Fixes: 5513bd0b4675 ("add xenstore domain flag to hypervisor")
|
||||
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -318,6 +318,26 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* Handle sub-ops not requiring the domctl lock. */
|
||||
+ switch ( op->cmd )
|
||||
+ {
|
||||
+ case XEN_DOMCTL_getdomaininfo:
|
||||
+ ret = xsm_getdomaininfo(XSM_XS_PRIV, d);
|
||||
+ if ( !ret )
|
||||
+ {
|
||||
+ getdomaininfo(d, &op->u.getdomaininfo);
|
||||
+
|
||||
+ ASSERT(op->domain == op->u.getdomaininfo.domain);
|
||||
+ copyback = true;
|
||||
+ }
|
||||
+
|
||||
+ goto domctl_out_unlock_domonly;
|
||||
+
|
||||
+ default:
|
||||
+ /* Everything else handled further down. */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
ret = xsm_domctl(XSM_OTHER, d, op->cmd,
|
||||
/* SSIDRef only applicable for cmd == createdomain */
|
||||
op->u.createdomain.ssidref);
|
||||
@@ -516,17 +536,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
copyback = 1;
|
||||
break;
|
||||
|
||||
- case XEN_DOMCTL_getdomaininfo:
|
||||
- ret = xsm_getdomaininfo(XSM_XS_PRIV, d);
|
||||
- if ( ret )
|
||||
- break;
|
||||
-
|
||||
- getdomaininfo(d, &op->u.getdomaininfo);
|
||||
-
|
||||
- op->domain = op->u.getdomaininfo.domain;
|
||||
- copyback = 1;
|
||||
- break;
|
||||
-
|
||||
case XEN_DOMCTL_getvcpucontext:
|
||||
{
|
||||
vcpu_guest_context_u c = { .nat = NULL };
|
||||
--- a/xen/include/xsm/dummy.h
|
||||
+++ b/xen/include/xsm/dummy.h
|
||||
@@ -172,9 +172,13 @@ static XSM_INLINE int cf_check xsm_domct
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
case XEN_DOMCTL_unbind_pt_irq:
|
||||
return xsm_default_action(XSM_DM_PRIV, current->domain, d);
|
||||
- case XEN_DOMCTL_getdomaininfo:
|
||||
case XEN_DOMCTL_get_domain_state:
|
||||
return xsm_default_action(XSM_XS_PRIV, current->domain, d);
|
||||
+
|
||||
+ case XEN_DOMCTL_getdomaininfo:
|
||||
+ ASSERT_UNREACHABLE();
|
||||
+ return -EILSEQ;
|
||||
+
|
||||
default:
|
||||
return xsm_default_action(XSM_PRIV, current->domain, d);
|
||||
}
|
||||
--- a/xen/xsm/flask/hooks.c
|
||||
+++ b/xen/xsm/flask/hooks.c
|
||||
@@ -682,8 +682,12 @@ static int cf_check flask_domctl(struct
|
||||
*/
|
||||
return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL);
|
||||
|
||||
- /* These have individual XSM hooks (common/domctl.c) */
|
||||
+ /* These have individual XSM hooks and don't make it here. */
|
||||
case XEN_DOMCTL_getdomaininfo:
|
||||
+ ASSERT_UNREACHABLE();
|
||||
+ return -EILSEQ;
|
||||
+
|
||||
+ /* These have individual XSM hooks (common/domctl.c) */
|
||||
case XEN_DOMCTL_scheduler_op:
|
||||
case XEN_DOMCTL_irq_permission:
|
||||
case XEN_DOMCTL_iomem_permission:
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
From: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Subject: domctl: protect locking for get_domain_state
|
||||
|
||||
When DOMID_INVALID is passed, the dom exec handler lock is being taken
|
||||
without any check that the domain is even allowed to take the lock. This
|
||||
allows for an unauthorized domain to DoS the get_domain_state domctl op.
|
||||
Move to consider the op effectively being called against the hypervisor.
|
||||
Thus it is the target of the call being invoked to identify the last
|
||||
domain with a state change. The subsequent check of whether the source
|
||||
domain is allowed the state of the last domain to change state is still
|
||||
relevant.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/tools/flask/policy/modules/xenstore.te
|
||||
+++ b/tools/flask/policy/modules/xenstore.te
|
||||
@@ -14,6 +14,7 @@ allow xenstore_t xen_t:xen writeconsole;
|
||||
# Xenstore queries domaininfo on all domains
|
||||
allow xenstore_t domain_type:domain getdomaininfo;
|
||||
allow xenstore_t domain_type:domain2 get_domain_state;
|
||||
+allow xenstore_t domxen_t:domain2 get_domain_state;
|
||||
|
||||
# As a shortcut, the following 3 rules are used instead of adding a domain_comms
|
||||
# rule between xenstore_t and every domain type that talks to xenstore
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -216,12 +216,8 @@ int get_domain_state(struct xen_domctl_g
|
||||
if ( info->pad0 )
|
||||
return -EINVAL;
|
||||
|
||||
- if ( d )
|
||||
+ if ( d != dom_xen )
|
||||
{
|
||||
- rc = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
- if ( rc )
|
||||
- return rc;
|
||||
-
|
||||
set_domain_state_info(info, d);
|
||||
|
||||
return 0;
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -304,13 +304,19 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
fallthrough;
|
||||
case XEN_DOMCTL_test_assign_device:
|
||||
case XEN_DOMCTL_vm_event_op:
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
if ( op->domain == DOMID_INVALID )
|
||||
{
|
||||
d = NULL;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
+ if ( op->domain == DOMID_INVALID )
|
||||
+ {
|
||||
+ d = dom_xen;
|
||||
+ break;
|
||||
+ }
|
||||
+ fallthrough;
|
||||
default:
|
||||
d = rcu_lock_domain_by_id(op->domain);
|
||||
if ( !d )
|
||||
@@ -863,7 +869,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_get_domain_state:
|
||||
- ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
+ ret = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
+ if ( !ret )
|
||||
+ ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
if ( !ret )
|
||||
copyback = true;
|
||||
break;
|
||||
@@ -876,7 +884,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
domctl_lock_release();
|
||||
|
||||
domctl_out_unlock_domonly:
|
||||
- if ( d && d != dom_io )
|
||||
+ if ( d && !is_system_domain(d) )
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
if ( copyback && __copy_to_guest(u_domctl, op, 1) )
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domctl: handle XEN_DOMCTL_get_domain_state without acquiring domctl lock
|
||||
|
||||
get_domain_state() uses its own locking. Thus, with caller side locking
|
||||
irrelevant, it can as well be called with the domctl lock not held.
|
||||
|
||||
Move the handling not only ahead of acquiring the lock, but also ahead
|
||||
of the XSM check, leveraging that the sub-op has its own hook.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Fixes: 3ad3df1bd0aa ("xen: add new domctl get_domain_state")
|
||||
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -339,6 +339,14 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
|
||||
goto domctl_out_unlock_domonly;
|
||||
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
+ ret = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
+ if ( !ret )
|
||||
+ ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
+ if ( !ret )
|
||||
+ copyback = true;
|
||||
+ goto domctl_out_unlock_domonly;
|
||||
+
|
||||
default:
|
||||
/* Everything else handled further down. */
|
||||
break;
|
||||
@@ -868,14 +876,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
- ret = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
- if ( !ret )
|
||||
- ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
- if ( !ret )
|
||||
- copyback = true;
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
ret = arch_do_domctl(op, d, u_domctl);
|
||||
break;
|
||||
--- a/xen/include/xsm/dummy.h
|
||||
+++ b/xen/include/xsm/dummy.h
|
||||
@@ -172,10 +172,9 @@ static XSM_INLINE int cf_check xsm_domct
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
case XEN_DOMCTL_unbind_pt_irq:
|
||||
return xsm_default_action(XSM_DM_PRIV, current->domain, d);
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
- return xsm_default_action(XSM_XS_PRIV, current->domain, d);
|
||||
|
||||
case XEN_DOMCTL_getdomaininfo:
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
ASSERT_UNREACHABLE();
|
||||
return -EILSEQ;
|
||||
|
||||
--- a/xen/xsm/flask/hooks.c
|
||||
+++ b/xen/xsm/flask/hooks.c
|
||||
@@ -684,6 +684,7 @@ static int cf_check flask_domctl(struct
|
||||
|
||||
/* These have individual XSM hooks and don't make it here. */
|
||||
case XEN_DOMCTL_getdomaininfo:
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
ASSERT_UNREACHABLE();
|
||||
return -EILSEQ;
|
||||
|
||||
@@ -694,7 +695,6 @@ static int cf_check flask_domctl(struct
|
||||
case XEN_DOMCTL_memory_mapping:
|
||||
case XEN_DOMCTL_set_target:
|
||||
case XEN_DOMCTL_vm_event_op:
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
|
||||
/* These have individual XSM hooks (arch/../domctl.c) */
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domain: locking for iomem_caps accesses
|
||||
|
||||
In order to be able to pull at least the XEN_DOMCTL_iomem_mapping handling
|
||||
out of the domctl-locked region, a separate (per-domain) lock is needed to
|
||||
synchronize in particular with XEN_DOMCTL_iomem_permission.
|
||||
|
||||
Locking is added only as far as domctl-s are affected. Uses presently
|
||||
outside of the domctl lock may want dealing with subsequently (perhaps
|
||||
limited to non-__init code).
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -518,10 +518,15 @@ static int late_hwdom_init(struct domain
|
||||
* may be modified after this hypercall returns if a more complex
|
||||
* device model is desired.
|
||||
*/
|
||||
+ write_lock(&dom0->caps_lock);
|
||||
rangeset_swap(d->irq_caps, dom0->irq_caps);
|
||||
rangeset_swap(d->iomem_caps, dom0->iomem_caps);
|
||||
#ifdef CONFIG_X86
|
||||
rangeset_swap(d->arch.ioport_caps, dom0->arch.ioport_caps);
|
||||
+#endif
|
||||
+ write_unlock(&dom0->caps_lock);
|
||||
+
|
||||
+#ifdef CONFIG_X86
|
||||
setup_io_bitmap(d);
|
||||
setup_io_bitmap(dom0);
|
||||
#endif
|
||||
@@ -873,6 +878,7 @@ struct domain *domain_create(domid_t dom
|
||||
rspin_lock_init_prof(d, domain_lock);
|
||||
rspin_lock_init_prof(d, page_alloc_lock);
|
||||
spin_lock_init(&d->hypercall_deadlock_mutex);
|
||||
+ rwlock_init(&d->caps_lock);
|
||||
INIT_PAGE_LIST_HEAD(&d->page_list);
|
||||
INIT_PAGE_LIST_HEAD(&d->extra_page_list);
|
||||
INIT_PAGE_LIST_HEAD(&d->xenpage_list);
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -267,6 +267,35 @@ static struct vnuma_info *vnuma_init(con
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
+void iocaps_double_lock(struct domain *d, bool write)
|
||||
+{
|
||||
+ struct domain *currd = current->domain;
|
||||
+
|
||||
+ if ( d->domain_id > currd->domain_id )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( write )
|
||||
+ write_lock(&d->caps_lock);
|
||||
+ else
|
||||
+ read_lock(&d->caps_lock);
|
||||
+
|
||||
+ if ( d->domain_id < currd->domain_id )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+}
|
||||
+
|
||||
+void iocaps_double_unlock(struct domain *d, bool write)
|
||||
+{
|
||||
+ struct domain *currd = current->domain;
|
||||
+
|
||||
+ if ( d != currd )
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( write )
|
||||
+ write_unlock(&d->caps_lock);
|
||||
+ else
|
||||
+ read_unlock(&d->caps_lock);
|
||||
+}
|
||||
+
|
||||
static bool is_stable_domctl(uint32_t cmd)
|
||||
{
|
||||
return cmd == XEN_DOMCTL_get_domain_state;
|
||||
@@ -687,6 +716,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
|
||||
break;
|
||||
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
if ( !iomem_access_permitted(current->domain,
|
||||
mfn, mfn + nr_mfns - 1) ||
|
||||
xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) )
|
||||
@@ -695,6 +726,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
|
||||
else
|
||||
ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -719,19 +752,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
break;
|
||||
#endif
|
||||
|
||||
+ iocaps_double_lock(d, false);
|
||||
+
|
||||
ret = -EPERM;
|
||||
if ( !iomem_access_permitted(current->domain, mfn, mfn_end) ||
|
||||
- !iomem_access_permitted(d, mfn, mfn_end) )
|
||||
- break;
|
||||
-
|
||||
- ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add);
|
||||
- if ( ret )
|
||||
- break;
|
||||
-
|
||||
- if ( !paging_mode_translate(d) )
|
||||
- break;
|
||||
-
|
||||
- if ( add )
|
||||
+ !iomem_access_permitted(d, mfn, mfn_end) ||
|
||||
+ (ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add)) ||
|
||||
+ !paging_mode_translate(d) )
|
||||
+ /* Nothing. */;
|
||||
+ else if ( add )
|
||||
{
|
||||
printk(XENLOG_G_DEBUG
|
||||
"memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n",
|
||||
@@ -755,6 +784,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
"memory_map: error %ld removing dom%d access to [%lx,%lx]\n",
|
||||
ret, d->domain_id, mfn, mfn_end);
|
||||
}
|
||||
+
|
||||
+ iocaps_double_unlock(d, false);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/include/xen/iocap.h
|
||||
+++ b/xen/include/xen/iocap.h
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <asm/iocap.h>
|
||||
#include <asm/p2m.h>
|
||||
|
||||
+void iocaps_double_lock(struct domain *d, bool write);
|
||||
+void iocaps_double_unlock(struct domain *d, bool write);
|
||||
+
|
||||
static inline int iomem_permit_access(struct domain *d, unsigned long s,
|
||||
unsigned long e)
|
||||
{
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -536,6 +536,7 @@ struct domain
|
||||
#endif
|
||||
|
||||
/* I/O capabilities (access to IRQs and memory-mapped I/O). */
|
||||
+ rwlock_t caps_lock;
|
||||
struct rangeset *iomem_caps;
|
||||
struct rangeset *irq_caps;
|
||||
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/domain: locking for ioport_caps accesses
|
||||
|
||||
In order to be able to pull at least the XEN_DOMCTL_ioport_mapping
|
||||
handling out of the domctl-locked region, the new separate (per-domain)
|
||||
lock is used to synchronize in particular with
|
||||
XEN_DOMCTL_ioport_permission.
|
||||
|
||||
Locking is added only as far as domctl-s are affected. Uses presently
|
||||
outside of the domctl lock may want dealing with subsequently (perhaps
|
||||
limited to non-__init code).
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/x86/domctl.c
|
||||
+++ b/xen/arch/x86/domctl.c
|
||||
@@ -233,6 +233,8 @@ long arch_do_domctl(
|
||||
unsigned int np = domctl->u.ioport_permission.nr_ports;
|
||||
int allow = domctl->u.ioport_permission.allow_access;
|
||||
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS )
|
||||
ret = -EINVAL;
|
||||
else if ( !ioports_access_permitted(currd, fp, fp + np - 1) ||
|
||||
@@ -242,6 +244,8 @@ long arch_do_domctl(
|
||||
ret = ioports_permit_access(d, fp, fp + np - 1);
|
||||
else
|
||||
ret = ioports_deny_access(d, fp, fp + np - 1);
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -648,16 +652,13 @@ long arch_do_domctl(
|
||||
break;
|
||||
}
|
||||
|
||||
- ret = -EPERM;
|
||||
- if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) )
|
||||
- break;
|
||||
-
|
||||
- ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add);
|
||||
- if ( ret )
|
||||
- break;
|
||||
-
|
||||
hvm = &d->arch.hvm;
|
||||
- if ( add )
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
+ if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) ||
|
||||
+ (ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add)) )
|
||||
+ ret = ret ?: -EPERM;
|
||||
+ else if ( add )
|
||||
{
|
||||
printk(XENLOG_G_INFO
|
||||
"ioport_map:add: dom%d gport=%x mport=%x nr=%x\n",
|
||||
@@ -718,6 +720,8 @@ long arch_do_domctl(
|
||||
"ioport_map: error %ld denying dom%d access to [%x,%x]\n",
|
||||
ret, d->domain_id, fmp, fmp + np - 1);
|
||||
}
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/arch/x86/setup.c
|
||||
+++ b/xen/arch/x86/setup.c
|
||||
@@ -2339,9 +2339,12 @@ void __hwdom_init setup_io_bitmap(struct
|
||||
return;
|
||||
|
||||
bitmap_fill(d->arch.hvm.io_bitmap, 0x10000);
|
||||
+
|
||||
+ read_lock(&d->caps_lock);
|
||||
if ( rangeset_report_ranges(d->arch.ioport_caps, 0, 0x10000,
|
||||
io_bitmap_cb, d) )
|
||||
BUG();
|
||||
+ read_unlock(&d->caps_lock);
|
||||
|
||||
/*
|
||||
* We need to trap 4-byte accesses to 0xcf8 (see admin_io_okay(),
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domain: locking for irq_caps accesses
|
||||
|
||||
In order to be able to pull at least the XEN_DOMCTL_{,un}bind_pt_irq
|
||||
handling out of the domctl-locked region, a separate (per-domain) lock is
|
||||
needed to synchronize in particular with XEN_DOMCTL_{irq,gsi}_permission.
|
||||
|
||||
Locking is added only as far as domctl-s are affected. Uses presently
|
||||
outside of the domctl lock may want dealing with subsequently (perhaps
|
||||
limited to non-__init code).
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Julien Grall <julien@xen.org>
|
||||
|
||||
--- a/xen/arch/arm/domctl.c
|
||||
+++ b/xen/arch/arm/domctl.c
|
||||
@@ -76,6 +76,7 @@ long arch_do_domctl(struct xen_domctl *d
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
{
|
||||
int rc;
|
||||
+ struct domain *currd = current->domain;
|
||||
struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq;
|
||||
uint32_t irq = bind->u.spi.spi;
|
||||
uint32_t virq = bind->machine_irq;
|
||||
@@ -107,21 +108,26 @@ long arch_do_domctl(struct xen_domctl *d
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
- if ( !irq_access_permitted(current->domain, irq) )
|
||||
- return -EPERM;
|
||||
+ read_lock(&currd->caps_lock);
|
||||
|
||||
- if ( !vgic_reserve_virq(d, virq) )
|
||||
- return -EBUSY;
|
||||
-
|
||||
- rc = route_irq_to_guest(d, virq, irq, "routed IRQ");
|
||||
- if ( rc )
|
||||
- vgic_free_virq(d, virq);
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ rc = -EPERM;
|
||||
+ else if ( !vgic_reserve_virq(d, virq) )
|
||||
+ rc = -EBUSY;
|
||||
+ else
|
||||
+ {
|
||||
+ rc = route_irq_to_guest(d, virq, irq, "routed IRQ");
|
||||
+ if ( rc )
|
||||
+ vgic_free_virq(d, virq);
|
||||
+ }
|
||||
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
return rc;
|
||||
}
|
||||
case XEN_DOMCTL_unbind_pt_irq:
|
||||
{
|
||||
int rc;
|
||||
+ struct domain *currd = current->domain;
|
||||
struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq;
|
||||
uint32_t irq = bind->u.spi.spi;
|
||||
uint32_t virq = bind->machine_irq;
|
||||
@@ -138,16 +144,15 @@ long arch_do_domctl(struct xen_domctl *d
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
- if ( !irq_access_permitted(current->domain, irq) )
|
||||
- return -EPERM;
|
||||
-
|
||||
- rc = release_guest_irq(d, virq);
|
||||
- if ( rc )
|
||||
- return rc;
|
||||
+ read_lock(&currd->caps_lock);
|
||||
|
||||
- vgic_free_virq(d, virq);
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ rc = -EPERM;
|
||||
+ else if ( !(rc = release_guest_irq(d, virq)) )
|
||||
+ vgic_free_virq(d, virq);
|
||||
|
||||
- return 0;
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
case XEN_DOMCTL_vuart_op:
|
||||
--- a/xen/arch/x86/domctl.c
|
||||
+++ b/xen/arch/x86/domctl.c
|
||||
@@ -267,16 +267,17 @@ long arch_do_domctl(
|
||||
break;
|
||||
}
|
||||
|
||||
- ret = -EPERM;
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
if ( !irq_access_permitted(currd, irq) ||
|
||||
xsm_irq_permission(XSM_HOOK, d, irq, flags) )
|
||||
- break;
|
||||
-
|
||||
- if ( flags )
|
||||
+ ret = -EPERM;
|
||||
+ else if ( flags )
|
||||
ret = irq_permit_access(d, irq);
|
||||
else
|
||||
ret = irq_deny_access(d, irq);
|
||||
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -579,20 +580,27 @@ long arch_do_domctl(
|
||||
break;
|
||||
|
||||
irq = domain_pirq_to_irq(d, bind->machine_irq);
|
||||
- ret = -EPERM;
|
||||
- if ( irq <= 0 || !irq_access_permitted(currd, irq) )
|
||||
- break;
|
||||
+ if ( irq <= 0 )
|
||||
+ ret = -EPERM;
|
||||
|
||||
- ret = -ESRCH;
|
||||
- if ( is_iommu_enabled(d) )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ ret = -EPERM;
|
||||
+ else if ( is_iommu_enabled(d) )
|
||||
{
|
||||
pcidevs_lock();
|
||||
ret = pt_irq_create_bind(d, bind);
|
||||
pcidevs_unlock();
|
||||
+
|
||||
+ if ( ret < 0 )
|
||||
+ printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for %pd\n",
|
||||
+ ret, d);
|
||||
}
|
||||
- if ( ret < 0 )
|
||||
- printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for dom%d\n",
|
||||
- ret, d->domain_id);
|
||||
+ else
|
||||
+ ret = -ESRCH;
|
||||
+
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -605,23 +613,26 @@ long arch_do_domctl(
|
||||
if ( !is_hvm_domain(d) )
|
||||
break;
|
||||
|
||||
- ret = -EPERM;
|
||||
- if ( irq <= 0 || !irq_access_permitted(currd, irq) )
|
||||
- break;
|
||||
-
|
||||
ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind);
|
||||
if ( ret )
|
||||
break;
|
||||
|
||||
- if ( is_iommu_enabled(d) )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ ret = -EPERM;
|
||||
+ else if ( is_iommu_enabled(d) )
|
||||
{
|
||||
pcidevs_lock();
|
||||
ret = pt_irq_destroy_bind(d, bind);
|
||||
pcidevs_unlock();
|
||||
+
|
||||
+ if ( ret < 0 )
|
||||
+ printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for %pd\n",
|
||||
+ ret, d);
|
||||
}
|
||||
- if ( ret < 0 )
|
||||
- printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for dom%d\n",
|
||||
- ret, d->domain_id);
|
||||
+
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -695,6 +695,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
irq = pirq_access_permitted(current->domain, pirq);
|
||||
if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) )
|
||||
ret = -EPERM;
|
||||
@@ -702,6 +705,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = irq_permit_access(d, irq);
|
||||
else
|
||||
ret = irq_deny_access(d, irq);
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: XSM/Flask: split the .iomem_mapping() hook
|
||||
|
||||
It's used twice in entirely different situations. The use in do_domctl()
|
||||
wants to become an ordinary XSM_DM_PRIV invocation, while the one in vPCI
|
||||
code need to remain XSM_HOOK (it may plausibly become XSM_TARGET). For
|
||||
Flask, the same backing function will continue to be used for the time
|
||||
being.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- a/xen/drivers/vpci/header.c
|
||||
+++ b/xen/drivers/vpci/header.c
|
||||
@@ -67,7 +67,7 @@ static int cf_check map_range(
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
- rc = xsm_iomem_mapping(XSM_HOOK, map->d, map_mfn, m_end, map->map);
|
||||
+ rc = xsm_iomem_mapping_vpci(XSM_HOOK, map->d, map_mfn, m_end, map->map);
|
||||
if ( rc )
|
||||
{
|
||||
printk(XENLOG_G_WARNING
|
||||
--- a/xen/include/xsm/dummy.h
|
||||
+++ b/xen/include/xsm/dummy.h
|
||||
@@ -580,6 +580,13 @@ static XSM_INLINE int cf_check xsm_iomem
|
||||
return xsm_default_action(action, current->domain, d);
|
||||
}
|
||||
|
||||
+static XSM_INLINE int cf_check xsm_iomem_mapping_vpci(
|
||||
+ XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow)
|
||||
+{
|
||||
+ XSM_ASSERT_ACTION(XSM_HOOK);
|
||||
+ return xsm_default_action(action, current->domain, d);
|
||||
+}
|
||||
+
|
||||
static XSM_INLINE int cf_check xsm_pci_config_permission(
|
||||
XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf, uint16_t start,
|
||||
uint16_t end, uint8_t access)
|
||||
--- a/xen/include/xsm/xsm.h
|
||||
+++ b/xen/include/xsm/xsm.h
|
||||
@@ -118,6 +118,8 @@ struct xsm_ops {
|
||||
uint8_t allow);
|
||||
int (*iomem_mapping)(struct domain *d, uint64_t s, uint64_t e,
|
||||
uint8_t allow);
|
||||
+ int (*iomem_mapping_vpci)(struct domain *d, uint64_t s, uint64_t e,
|
||||
+ uint8_t allow);
|
||||
int (*pci_config_permission)(struct domain *d, uint32_t machine_bdf,
|
||||
uint16_t start, uint16_t end, uint8_t access);
|
||||
|
||||
@@ -523,6 +525,12 @@ static inline int xsm_iomem_mapping(
|
||||
return alternative_call(xsm_ops.iomem_mapping, d, s, e, allow);
|
||||
}
|
||||
|
||||
+static inline int xsm_iomem_mapping_vpci(
|
||||
+ xsm_default_t def, struct domain *d, uint64_t s, uint64_t e, uint8_t allow)
|
||||
+{
|
||||
+ return alternative_call(xsm_ops.iomem_mapping_vpci, d, s, e, allow);
|
||||
+}
|
||||
+
|
||||
static inline int xsm_pci_config_permission(
|
||||
xsm_default_t def, struct domain *d, uint32_t machine_bdf, uint16_t start,
|
||||
uint16_t end, uint8_t access)
|
||||
--- a/xen/xsm/dummy.c
|
||||
+++ b/xen/xsm/dummy.c
|
||||
@@ -76,6 +76,7 @@ static const struct xsm_ops __initconst_
|
||||
.irq_permission = xsm_irq_permission,
|
||||
.iomem_permission = xsm_iomem_permission,
|
||||
.iomem_mapping = xsm_iomem_mapping,
|
||||
+ .iomem_mapping_vpci = xsm_iomem_mapping_vpci,
|
||||
.pci_config_permission = xsm_pci_config_permission,
|
||||
.get_vnumainfo = xsm_get_vnumainfo,
|
||||
|
||||
--- a/xen/xsm/flask/hooks.c
|
||||
+++ b/xen/xsm/flask/hooks.c
|
||||
@@ -1950,6 +1950,7 @@ static const struct xsm_ops __initconst_
|
||||
.irq_permission = flask_irq_permission,
|
||||
.iomem_permission = flask_iomem_permission,
|
||||
.iomem_mapping = flask_iomem_mapping,
|
||||
+ .iomem_mapping_vpci = flask_iomem_mapping,
|
||||
.pci_config_permission = flask_pci_config_permission,
|
||||
|
||||
.resource_plug_core = flask_resource_plug_core,
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue