Compare commits

..

11 commits

Author SHA1 Message Date
Michael Young
5d5bea92a5 revised patch for XSA-286 (mitigating performance impact) 2020-11-03 22:14:30 +00:00
Michael Young
8cfa1f224d x86 PV guest INVLPG-like flushes may leave stale TLB entries
[XSA-286, CVE-2020-27674]
2020-10-29 20:42:36 +00:00
Michael Young
47e68f69a5 3 security updates
x86: Race condition in Xen mapping code [XSA-345]
undue deferral of IOMMU TLB flushes [XSA-346]
unsafe AMD IOMMU page table updates [XSA-347]
2020-10-20 20:47:19 +01:00
Michael Young
c1dd47a6db 10 security updates, remove some stray files
x86 pv: Crash when handling guest access to MSR_MISC_ENABLE [XSA-333,
	CVE-2020-25602] (#1881619)
Missing unlock in XENMEM_acquire_resource error path [XSA-334,
	CVE-2020-25598] (#1881616)
race when migrating timers between x86 HVM vCPU-s [XSA-336,
	CVE-2020-25604] (#1881618)
PCI passthrough code reading back hardware registers [XSA-337,
	CVE-2020-25595] (#1881587)
once valid event channels may not turn invalid [XSA-338, CVE-2020-25597]
	(#1881588)
x86 pv guest kernel DoS via SYSENTER [XSA-339, CVE-2020-25596]
	(#1881617)
Missing memory barriers when accessing/allocating an event channel [XSA-340,
	CVE-2020-25603] (#1881583)
out of bounds event channels available to 32-bit x86 domains [XSA-342,
	CVE-2020-25600] (#1881582)
races with evtchn_reset() [XSA-343, CVE-2020-25599] (#1881581)
lack of preemption in evtchn_reset() / evtchn_destroy() [XSA-344,
	CVE-2020-25601] (#1881586)
2020-09-22 22:12:48 +01:00
Michael Young
d1afe2704c QEMU: usb: out-of-bounds r/w access issue [XSA-335, CVE-2020-14364]
(#1871850)
2020-08-25 15:52:30 +01:00
Michael Young
9cb1314e73 5 security updates
incorrect error handling in event channel port allocation leads to
        DoS [XSA-317, CVE-2020-15566] (#1854465)
inverted code paths in x86 dirty VRAM tracking leads to DoS
        [XSA-319, CVE-2020-15563] (#1854463)
xen: insufficient cache write-back under VT-d leads to DoS
        [XSA-321, CVE-2020-15565] (#1854467)
missing alignment check in VCPUOP_register_vcpu_info leads to DoS
        [XSA-327, CVE-2020-15564] (#1854458)
non-atomic modification of live EPT PTE leads to DoS
        [XSA-328, CVE-2020-15567] (#1854464)
2020-07-07 20:47:58 +01:00
Michael Young
7a127d3fbe Special Register Buffer speculative side channel [XSA-320] 2020-06-10 21:20:12 +01:00
Michael Young
ceaeefb05a update to 4.12.3 2020-05-19 20:05:03 +01:00
Michael Young
ec4c2c59a0 4 security updates
multiple xenoprof issues [XSA-313, CVE-2020-11740, CVE-2020-11741]
	(#1823912, #1823914)
Missing memory barriers in read-write unlock paths [XSA-314,
	CVE-2020-11739] (#1823784)
Bad error path in GNTTABOP_map_grant [XSA-316, CVE-2020-11743] (#1823926)
Bad continuation handling in GNTTABOP_copy [XSA-318, CVE-2020-11742]
	(#1823943)
2020-04-15 21:22:51 +01:00
Michael Young
d759d346c3 arm: a CPU may speculate past the ERET instruction [XSA-312] 2020-01-14 21:38:40 +00:00
Michael Young
132ad1fbee update to xen-4.12.2 2020-01-06 19:37:28 +00:00
117 changed files with 8367 additions and 5716 deletions

3
.gitignore vendored
View file

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

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

View 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:

View 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");

View 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)

View 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

View 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

View 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

View 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)

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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);

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View file

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

View 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
}

View file

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

View file

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

View 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')

View file

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

View file

@ -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. */

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

94
xen.python38.patch Normal file
View 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;

1394
xen.spec

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 = &current->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 = &current->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 = &current->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 = &current->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 = &current->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 {

View file

@ -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:
+ */

View file

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

View file

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

View file

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

View file

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

View file

@ -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(),

View file

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

View file

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