Compare commits

..

12 commits

Author SHA1 Message Date
Michael Young
5813d5853a 2 security issues
x86/AMD: mismatch in IOMMU quarantine page table levels [XSA-445,
	CVE-2023-46835]
x86: BTC/SRSO fixes not fully effective [XSA-446, CVE-2023-46836]
2023-11-15 20:40:53 +00:00
Michael Young
8b84ab579c 4 security issues
xenstored: A transaction conflict can crash C Xenstored [XSA-440,
	CVE-2023-34323]
x86/AMD: missing IOMMU TLB flushing [XSA-442, CVE-2023-34326]
Multiple vulnerabilities in libfsimage disk handling [XSA-443,
	CVE-2023-34325]
x86/AMD: Debug Mask handling [XSA-444, CVE-2023-34327,
	CVE-2023-34328]
2023-10-11 19:47:00 +01:00
Michael Young
a65ac23041 3 security issues
- arm32: The cache may not be properly cleaned/invalidated [XSA-437,
        CVE-2023-34321]
- top-level shadow reference dropped too early for 64-bit PV guests
        [XSA-438, CVE-2023-34322]
- x86/AMD: Divide speculative information leak [XSA-439, CVE-2023-20588]
2023-09-26 16:50:31 +01:00
Michael Young
046e9e564a update to xen-4.16.5 which includes security updates
x86/AMD: Speculative Return Stack Overflow [XSA-434, CVE-2023-20569]
x86/Intel: Gather Data Sampling [XSA-435, CVE-2022-40982]
remove patches now included upstream
2023-08-11 19:41:01 +01:00
Michael Young
5b38fd1c96 arm: Guests can trigger a deadlock on Cortex-A77 [XSA-436, CVE-2023-34320] 2023-08-01 22:13:54 +01:00
Michael Young
8f43f4c45b bugfix for x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] 2023-07-31 22:08:57 +01:00
Michael Young
4a3496d719 x86/AMD: Zenbleed [XSA-433, CVE-2023-20593] 2023-07-26 19:57:13 +01:00
Michael Young
01f64a0113 update to xen-4.16.4
remove patches now included upstream
2023-05-02 22:54:41 +01:00
Michael Young
85b6cafcb8 3 security issues (#2180425)
x86 shadow plus log-dirty mode use-after-free [XSA-427, CVE-2022-42332]
x86/HVM pinned cache attributes mis-handling [XSA-428, CVE-2022-42333,
        CVE-2022-42334]
x86: speculative vulnerability in 32bit SYSCALL path [XSA-429,
        CVE-2022-42331]
2023-03-21 23:50:32 +00:00
Michael Young
0b14ad1009 use OVMF.fd from new edk2-ovmf-xen package
ovmf.bin file built from edk2-ovmf package no longer supports xen (#2170930)
2023-02-18 11:40:29 +00:00
Michael Young
06e1d41034 x86: Cross-Thread Return Address Predictions [XSA-426, CVE-2022-27672] 2023-02-15 20:11:24 +00:00
Michael Young
158b3ce973 update to xen-4.16.3 2022-12-19 19:58:48 +00:00
103 changed files with 5391 additions and 5148 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.16.5.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.16.5.tar.gz) = 2f370787b72b2cd9d81c0b5f138133e676d2b9c8c76e31e6439649d7145242a6b7be0d51a7ff4f4197a99e3f6b24ac50e63d2fa49368da440d3f555e70c4ebd3

View file

@ -1,54 +1,45 @@
--- 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
@@ -215,7 +215,7 @@
goto inval;
} else {
*relative = !strstarts(*path, "/");
- *path = canonicalize(conn, ctx, *path);
+ *path = xenstore_canonicalize(conn, ctx, *path);
if (!*path)
return errno;
if (!is_valid_nodename(*path))
@@ -305,7 +305,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, ctx, vec[0]);
+ node = xenstore_canonicalize(conn, ctx, 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);
@@ -874,7 +874,7 @@
if (!canonical_name)
canonical_name = &tmp_name;
- *canonical_name = canonicalize(conn, ctx, name);
+ *canonical_name = xenstore_canonicalize(conn, ctx, name);
if (!*canonical_name)
return NULL;
@@ -1320,7 +1320,7 @@
const char *tmp_name;
const struct node *node;
- tmp_name = canonicalize(conn, ctx, name, allow_special);
+ tmp_name = xenstore_canonicalize(conn, ctx, name, allow_special);
if (!tmp_name)
return NULL;
--- 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
return get_node(conn, ctx, *canonical_name, perm);
--- 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 +76,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 +96,14 @@
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 @@
--- xen-4.14.1/tools/xenstore/xenstored_core.h.orig 2020-12-17 16:47:25.000000000 +0000
+++ xen-4.14.1/tools/xenstore/xenstored_core.h 2020-12-17 20:13:10.806887309 +0000
@@ -153,7 +153,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);
-char *canonicalize(struct connection *conn, const void *ctx, const char *node);
+char *xenstore_canonicalize(struct connection *conn, const void *ctx, const char *node);
/* Get access permissions. */
unsigned int perm_for_conn(struct connection *conn,

8
xen.drop.brctl.patch Normal file
View file

@ -0,0 +1,8 @@
--- 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 +1,12 @@
--- 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)
--- xen-4.16.0/xen/arch/x86/Makefile.orig 2021-11-30 11:42:42.000000000 +0000
+++ xen-4.16.0/xen/arch/x86/Makefile 2022-03-17 22:43:21.077990559 +0000
@@ -127,7 +127,8 @@
CFLAGS-$(XEN_BUILD_EFI) += -DXEN_BUILD_EFI
# 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)
-EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(XEN_LDFLAGS)) --subsystem=10
+#EFI_LDFLAGS = $(patsubst -m%,-mi386pep,$(XEN_LDFLAGS)) --subsystem=10
+EFI_LDFLAGS = --as-needed --build-id=sha1 -mi386pep --subsystem=10
XEN_BUILD_PE := $(if $(XEN_BUILD_EFI),$(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o efi/check.efi efi/check.o))
# If the above failed, it may be merely because of the linker not dealing well
# with debug info. Try again with stripping it.

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

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

10
xen.gcc10.fixes.patch Normal file
View file

@ -0,0 +1,10 @@
--- xen-4.13.0/tools/xenpmd/Makefile.orig 2019-12-17 14:23:09.000000000 +0000
+++ xen-4.13.0/tools/xenpmd/Makefile 2020-01-22 22:13:16.564873608 +0000
@@ -3,6 +3,7 @@
CFLAGS += -Werror
CFLAGS += $(CFLAGS_libxenstore)
+CFLAGS += -Wno-error=format-truncation
LDLIBS += $(LDLIBS_libxenstore)

View file

@ -1,7 +1,7 @@
--- 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,-Wdeclaration-after-statement)
$(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)

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,50 +1,32 @@
#
# Automatically generated file; DO NOT EDIT.
# Xen/x86 4.20 Configuration
# Xen/x86 4.14.0-rc Configuration
#
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=150001
CONFIG_GCC_VERSION=100101
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_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_TBOOT=y
CONFIG_XEN_ALIGN_DEFAULT=y
# CONFIG_XEN_ALIGN_2M is not set
# CONFIG_X2APIC_PHYSICAL is not set
CONFIG_X2APIC_MIXED=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
#
@ -53,55 +35,42 @@ CONFIG_ALTP2M=y
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_PDX=y
CONFIG_HAS_UBSAN=y
CONFIG_HAS_KEXEC=y
CONFIG_HAS_IOPORTS=y
CONFIG_HAS_SCHED_GRANULARITY=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_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
@ -110,63 +79,35 @@ CONFIG_TRACEBUFFER=y
#
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
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 +115,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 +125,17 @@ 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,

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

801
xen.spec

File diff suppressed because it is too large Load diff

145
xsa376.patch Normal file
View file

@ -0,0 +1,145 @@
From 02d3a57d6466363b316b60ffbba414a4a2cb90c5 Mon Sep 17 00:00:00 2001
From: Juergen Gross <jgross@suse.com>
Date: Thu, 25 Nov 2021 13:38:29 +0100
Subject: [PATCH] SUPPORT.md: limit support statement for Linux and Windows
frontends
Change the support state of Linux and Windows pv frontends from
"supported" to "supported with caveats" in order to reflect that the
frontends can probably be harmed by their respective backends.
Some of the Linux frontends have been hardened already.
This is XSA-376
Signed-off-by: Juergen Gross <jgross@suse.com>
---
SUPPORT.md | 57 +++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 48 insertions(+), 9 deletions(-)
diff --git a/SUPPORT.md b/SUPPORT.md
index 3a34933c89..6e3e305b01 100644
--- a/SUPPORT.md
+++ b/SUPPORT.md
@@ -411,7 +411,11 @@ Guest-side driver capable of speaking the Xen PV block protocol
Status, FreeBSD: Supported, Security support external
Status, NetBSD: Supported, Security support external
Status, OpenBSD: Supported, Security support external
- Status, Windows: Supported
+ Status, Windows: Supported, with caveats
+
+Windows frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### Netfront
@@ -421,20 +425,32 @@ Guest-side driver capable of speaking the Xen PV networking protocol
Status, FreeBSD: Supported, Security support external
Status, NetBSD: Supported, Security support external
Status, OpenBSD: Supported, Security support external
- Status, Windows: Supported
+ Status, Windows: Supported, with caveats
+
+Windows frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### PV Framebuffer (frontend)
Guest-side driver capable of speaking the Xen PV Framebuffer protocol
- Status, Linux (xen-fbfront): Supported
+ Status, Linux (xen-fbfront): Supported, with caveats
+
+Linux frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### PV display (frontend)
Guest-side driver capable of speaking the Xen PV display protocol
- Status, Linux: Supported (outside of "backend allocation" mode)
- Status, Linux: Experimental (in "backend allocation" mode)
+ Status, Linux, outside of "backend allocation" mode: Supported, with caveats
+ Status, Linux, "backend allocation" mode: Experimental
+
+Linux frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### PV Console (frontend)
@@ -443,7 +459,11 @@ Guest-side driver capable of speaking the Xen PV console protocol
Status, Linux (hvc_xen): Supported
Status, FreeBSD: Supported, Security support external
Status, NetBSD: Supported, Security support external
- Status, Windows: Supported
+ Status, Windows: Supported, with caveats
+
+Windows frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### PV keyboard (frontend)
@@ -451,11 +471,19 @@ Guest-side driver capable of speaking the Xen PV keyboard protocol.
Note that the "keyboard protocol" includes mouse / pointer /
multi-touch support as well.
- Status, Linux (xen-kbdfront): Supported
+ Status, Linux (xen-kbdfront): Supported, with caveats
+
+Linux frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### PV USB (frontend)
- Status, Linux: Supported
+ Status, Linux: Supported, with caveats
+
+Linux frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
### PV SCSI protocol (frontend)
@@ -464,6 +492,10 @@ multi-touch support as well.
NB that while the PV SCSI frontend is in Linux and tested regularly,
there is currently no xl support.
+Linux frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
+
### PV TPM (frontend)
Guest-side driver capable of speaking the Xen PV TPM protocol
@@ -486,7 +518,11 @@ Guest-side driver capable of making pv system calls
Guest-side driver capable of speaking the Xen PV sound protocol
- Status, Linux: Supported
+ Status, Linux: Supported, with caveats
+
+Linux frontend currently trusts the backend;
+bugs in the frontend which allow backend to cause mischief will not be
+considered security vulnerabilities.
## Virtual device support, host side
@@ -987,6 +1023,9 @@ are given the following labels:
This feature is security supported
by a different organization (not the XenProject).
+ The extent of support is defined by that organization.
+ It might be limited, e.g. like described in **Supported, with caveats**
+ below.
See **External security support** below.
* **Supported, with caveats**
--
2.26.2

110
xsa437-4.16.patch Normal file
View file

@ -0,0 +1,110 @@
From 2b21319eecd8623078f27f0bccbbfdeb26606ff1 Mon Sep 17 00:00:00 2001
From: Stefano Stabellini <stefano.stabellini@amd.com>
Date: Thu, 17 Aug 2023 13:41:35 +0100
Subject: [PATCH] xen/arm: page: Handle cache flush of an element at the top of
the address space
The region that needs to be cleaned/invalidated may be at the top
of the address space. This means that 'end' (i.e. 'p + size') will
be 0 and therefore nothing will be cleaned/invalidated as the check
in the loop will always be false.
On Arm64, we only support we only support up to 48-bit Virtual
address space. So this is not a concern there. However, for 32-bit,
the mapcache is using the last 2GB of the address space. Therefore
we may not clean/invalidate properly some pages. This could lead
to memory corruption or data leakage (the scrubbed value may
still sit in the cache when the guest could read directly the memory
and therefore read the old content).
Rework invalidate_dcache_va_range(), clean_dcache_va_range(),
clean_and_invalidate_dcache_va_range() to handle a cache flush
with an element at the top of the address space.
This is CVE-2023-34321 / XSA-437.
Reported-by: Julien Grall <jgrall@amazon.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>
Acked-by: Bertrand Marquis <bertrand.marquis@arm.com>
---
xen/include/asm-arm/page.h | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/xen/include/asm-arm/page.h b/xen/include/asm-arm/page.h
index c6f9fb0d4e0c..eff5883ef87b 100644
--- a/xen/include/asm-arm/page.h
+++ b/xen/include/asm-arm/page.h
@@ -152,26 +152,25 @@ static inline size_t read_dcache_line_bytes(void)
static inline int invalidate_dcache_va_range(const void *p, unsigned long size)
{
- const void *end = p + size;
size_t cacheline_mask = dcache_line_bytes - 1;
dsb(sy); /* So the CPU issues all writes to the range */
if ( (uintptr_t)p & cacheline_mask )
{
+ size -= dcache_line_bytes - ((uintptr_t)p & cacheline_mask);
p = (void *)((uintptr_t)p & ~cacheline_mask);
asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p));
p += dcache_line_bytes;
}
- if ( (uintptr_t)end & cacheline_mask )
- {
- end = (void *)((uintptr_t)end & ~cacheline_mask);
- asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (end));
- }
- for ( ; p < end; p += dcache_line_bytes )
+ for ( ; size >= dcache_line_bytes;
+ p += dcache_line_bytes, size -= dcache_line_bytes )
asm volatile (__invalidate_dcache_one(0) : : "r" (p));
+ if ( size > 0 )
+ asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p));
+
dsb(sy); /* So we know the flushes happen before continuing */
return 0;
@@ -179,10 +178,14 @@ static inline int invalidate_dcache_va_range(const void *p, unsigned long size)
static inline int clean_dcache_va_range(const void *p, unsigned long size)
{
- const void *end = p + size;
+ size_t cacheline_mask = dcache_line_bytes - 1;
+
dsb(sy); /* So the CPU issues all writes to the range */
- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1));
- for ( ; p < end; p += dcache_line_bytes )
+ size += (uintptr_t)p & cacheline_mask;
+ size = (size + cacheline_mask) & ~cacheline_mask;
+ p = (void *)((uintptr_t)p & ~cacheline_mask);
+ for ( ; size >= dcache_line_bytes;
+ p += dcache_line_bytes, size -= dcache_line_bytes )
asm volatile (__clean_dcache_one(0) : : "r" (p));
dsb(sy); /* So we know the flushes happen before continuing */
/* ARM callers assume that dcache_* functions cannot fail. */
@@ -192,10 +195,14 @@ static inline int clean_dcache_va_range(const void *p, unsigned long size)
static inline int clean_and_invalidate_dcache_va_range
(const void *p, unsigned long size)
{
- const void *end = p + size;
+ size_t cacheline_mask = dcache_line_bytes - 1;
+
dsb(sy); /* So the CPU issues all writes to the range */
- p = (void *)((uintptr_t)p & ~(dcache_line_bytes - 1));
- for ( ; p < end; p += dcache_line_bytes )
+ size += (uintptr_t)p & cacheline_mask;
+ size = (size + cacheline_mask) & ~cacheline_mask;
+ p = (void *)((uintptr_t)p & ~cacheline_mask);
+ for ( ; size >= dcache_line_bytes;
+ p += dcache_line_bytes, size -= dcache_line_bytes )
asm volatile (__clean_and_invalidate_dcache_one(0) : : "r" (p));
dsb(sy); /* So we know the flushes happen before continuing */
/* ARM callers assume that dcache_* functions cannot fail. */
--
2.40.1

414
xsa438-4.16.patch Normal file
View file

@ -0,0 +1,414 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: x86/shadow: defer releasing of PV's top-level shadow reference
sh_set_toplevel_shadow() re-pinning the top-level shadow we may be
running on is not enough (and at the same time unnecessary when the
shadow isn't what we're running on): That shadow becomes eligible for
blowing away (from e.g. shadow_prealloc()) immediately after the
paging lock was dropped. Yet it needs to remain valid until the actual
page table switch occurred.
Propagate up the call chain the shadow entry that needs releasing
eventually, and carry out the release immediately after switching page
tables. Handle update_cr3() failures by switching to idle pagetables.
Note that various further uses of update_cr3() are HVM-only or only act
on paused vCPU-s, in which case sh_set_toplevel_shadow() will not defer
releasing of the reference.
While changing the update_cr3() hook, also convert the "do_locking"
parameter to boolean.
This is CVE-2023-34322 / XSA-438.
Reported-by: Tim Deegan <tim@xen.org>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: George Dunlap <george.dunlap@cloud.com>
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -728,10 +728,12 @@ static bool_t hap_invlpg(struct vcpu *v,
return 1;
}
-static void hap_update_cr3(struct vcpu *v, int do_locking, bool noflush)
+static pagetable_t hap_update_cr3(struct vcpu *v, bool do_locking, bool noflush)
{
v->arch.hvm.hw_cr[3] = v->arch.hvm.guest_cr[3];
hvm_update_guest_cr3(v, noflush);
+
+ return pagetable_null();
}
/*
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -2574,13 +2574,13 @@ void shadow_update_paging_modes(struct v
}
/* Set up the top-level shadow and install it in slot 'slot' of shadow_table */
-void sh_set_toplevel_shadow(struct vcpu *v,
- unsigned int slot,
- mfn_t gmfn,
- unsigned int root_type,
- mfn_t (*make_shadow)(struct vcpu *v,
- mfn_t gmfn,
- uint32_t shadow_type))
+pagetable_t sh_set_toplevel_shadow(struct vcpu *v,
+ unsigned int slot,
+ mfn_t gmfn,
+ unsigned int root_type,
+ mfn_t (*make_shadow)(struct vcpu *v,
+ mfn_t gmfn,
+ uint32_t shadow_type))
{
mfn_t smfn;
pagetable_t old_entry, new_entry;
@@ -2637,20 +2637,37 @@ void sh_set_toplevel_shadow(struct vcpu
mfn_x(gmfn), mfn_x(pagetable_get_mfn(new_entry)));
v->arch.paging.shadow.shadow_table[slot] = new_entry;
- /* Decrement the refcount of the old contents of this slot */
- if ( !pagetable_is_null(old_entry) )
+ /*
+ * Decrement the refcount of the old contents of this slot, unless
+ * we're still running on that shadow - in that case it'll need holding
+ * on to until the actual page table switch did occur.
+ */
+ if ( !pagetable_is_null(old_entry) && (v != current || !is_pv_domain(d)) )
{
- mfn_t old_smfn = pagetable_get_mfn(old_entry);
- /* Need to repin the old toplevel shadow if it's been unpinned
- * by shadow_prealloc(): in PV mode we're still running on this
- * shadow and it's not safe to free it yet. */
- if ( !mfn_to_page(old_smfn)->u.sh.pinned && !sh_pin(d, old_smfn) )
- {
- printk(XENLOG_G_ERR "can't re-pin %"PRI_mfn"\n", mfn_x(old_smfn));
- domain_crash(d);
- }
- sh_put_ref(d, old_smfn, 0);
+ sh_put_ref(d, pagetable_get_mfn(old_entry), 0);
+ old_entry = pagetable_null();
}
+
+ /*
+ * 2- and 3-level shadow mode is used for HVM only. Therefore we never run
+ * on such a shadow, so only call sites requesting an L4 shadow need to pay
+ * attention to the returned value.
+ */
+ ASSERT(pagetable_is_null(old_entry) || root_type == SH_type_l4_64_shadow);
+
+ return old_entry;
+}
+
+/*
+ * Helper invoked when releasing of a top-level shadow's reference was
+ * deferred in sh_set_toplevel_shadow() above.
+ */
+void shadow_put_top_level(struct domain *d, pagetable_t old_entry)
+{
+ ASSERT(!pagetable_is_null(old_entry));
+ paging_lock(d);
+ sh_put_ref(d, pagetable_get_mfn(old_entry), 0);
+ paging_unlock(d);
}
/**************************************************************************/
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -3219,8 +3219,8 @@ sh_detach_old_tables(struct vcpu *v)
}
}
-static void
-sh_update_cr3(struct vcpu *v, int do_locking, bool noflush)
+static pagetable_t
+sh_update_cr3(struct vcpu *v, bool do_locking, bool noflush)
/* Updates vcpu->arch.cr3 after the guest has changed CR3.
* Paravirtual guests should set v->arch.guest_table (and guest_table_user,
* if appropriate).
@@ -3234,6 +3234,7 @@ sh_update_cr3(struct vcpu *v, int do_loc
{
struct domain *d = v->domain;
mfn_t gmfn;
+ pagetable_t old_entry = pagetable_null();
#if GUEST_PAGING_LEVELS == 3 && defined(CONFIG_HVM)
const guest_l3e_t *gl3e;
unsigned int i, guest_idx;
@@ -3243,7 +3244,7 @@ sh_update_cr3(struct vcpu *v, int do_loc
if ( !is_hvm_domain(d) && !v->is_initialised )
{
ASSERT(v->arch.cr3 == 0);
- return;
+ return old_entry;
}
if ( do_locking ) paging_lock(v->domain);
@@ -3316,11 +3317,12 @@ sh_update_cr3(struct vcpu *v, int do_loc
#if GUEST_PAGING_LEVELS == 4
if ( sh_remove_write_access(d, gmfn, 4, 0) != 0 )
guest_flush_tlb_mask(d, d->dirty_cpumask);
- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow, sh_make_shadow);
+ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow,
+ sh_make_shadow);
if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) )
{
ASSERT(d->is_dying || d->is_shutting_down);
- return;
+ return old_entry;
}
if ( !shadow_mode_external(d) && !is_pv_32bit_domain(d) )
{
@@ -3366,24 +3368,30 @@ sh_update_cr3(struct vcpu *v, int do_loc
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
gl2mfn = get_gfn_query_unlocked(d, gfn_x(gl2gfn), &p2mt);
if ( p2m_is_ram(p2mt) )
- sh_set_toplevel_shadow(v, i, gl2mfn, SH_type_l2_shadow,
- sh_make_shadow);
+ old_entry = sh_set_toplevel_shadow(v, i, gl2mfn,
+ SH_type_l2_shadow,
+ sh_make_shadow);
else
- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0,
- sh_make_shadow);
+ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0,
+ sh_make_shadow);
}
else
- sh_set_toplevel_shadow(v, i, INVALID_MFN, 0, sh_make_shadow);
+ old_entry = sh_set_toplevel_shadow(v, i, INVALID_MFN, 0,
+ sh_make_shadow);
+
+ ASSERT(pagetable_is_null(old_entry));
}
}
#elif GUEST_PAGING_LEVELS == 2
if ( sh_remove_write_access(d, gmfn, 2, 0) != 0 )
guest_flush_tlb_mask(d, d->dirty_cpumask);
- sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow, sh_make_shadow);
+ old_entry = sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l2_shadow,
+ sh_make_shadow);
+ ASSERT(pagetable_is_null(old_entry));
if ( unlikely(pagetable_is_null(v->arch.paging.shadow.shadow_table[0])) )
{
ASSERT(d->is_dying || d->is_shutting_down);
- return;
+ return old_entry;
}
#else
#error This should never happen
@@ -3477,6 +3485,8 @@ sh_update_cr3(struct vcpu *v, int do_loc
/* Release the lock, if we took it (otherwise it's the caller's problem) */
if ( do_locking ) paging_unlock(v->domain);
+
+ return old_entry;
}
--- a/xen/arch/x86/mm/shadow/none.c
+++ b/xen/arch/x86/mm/shadow/none.c
@@ -52,9 +52,10 @@ static unsigned long _gva_to_gfn(struct
}
#endif
-static void _update_cr3(struct vcpu *v, int do_locking, bool noflush)
+static pagetable_t _update_cr3(struct vcpu *v, bool do_locking, bool noflush)
{
ASSERT_UNREACHABLE();
+ return pagetable_null();
}
static void _update_paging_modes(struct vcpu *v)
--- a/xen/arch/x86/mm/shadow/private.h
+++ b/xen/arch/x86/mm/shadow/private.h
@@ -391,13 +391,13 @@ mfn_t shadow_alloc(struct domain *d,
void shadow_free(struct domain *d, mfn_t smfn);
/* Set up the top-level shadow and install it in slot 'slot' of shadow_table */
-void sh_set_toplevel_shadow(struct vcpu *v,
- unsigned int slot,
- mfn_t gmfn,
- unsigned int root_type,
- mfn_t (*make_shadow)(struct vcpu *v,
- mfn_t gmfn,
- uint32_t shadow_type));
+pagetable_t sh_set_toplevel_shadow(struct vcpu *v,
+ unsigned int slot,
+ mfn_t gmfn,
+ unsigned int root_type,
+ mfn_t (*make_shadow)(struct vcpu *v,
+ mfn_t gmfn,
+ uint32_t shadow_type));
/* Update the shadows in response to a pagetable write from Xen */
int sh_validate_guest_entry(struct vcpu *v, mfn_t gmfn, void *entry, u32 size);
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -565,15 +565,12 @@ void write_ptbase(struct vcpu *v)
*
* Update ref counts to shadow tables appropriately.
*/
-void update_cr3(struct vcpu *v)
+pagetable_t update_cr3(struct vcpu *v)
{
mfn_t cr3_mfn;
if ( paging_mode_enabled(v->domain) )
- {
- paging_update_cr3(v, false);
- return;
- }
+ return paging_update_cr3(v, false);
if ( !(v->arch.flags & TF_kernel_mode) )
cr3_mfn = pagetable_get_mfn(v->arch.guest_table_user);
@@ -581,6 +578,8 @@ void update_cr3(struct vcpu *v)
cr3_mfn = pagetable_get_mfn(v->arch.guest_table);
make_cr3(v, cr3_mfn);
+
+ return pagetable_null();
}
static inline void set_tlbflush_timestamp(struct page_info *page)
@@ -3254,6 +3253,7 @@ int new_guest_cr3(mfn_t mfn)
struct domain *d = curr->domain;
int rc;
mfn_t old_base_mfn;
+ pagetable_t old_shadow;
if ( is_pv_32bit_domain(d) )
{
@@ -3321,9 +3321,22 @@ int new_guest_cr3(mfn_t mfn)
if ( !VM_ASSIST(d, m2p_strict) )
fill_ro_mpt(mfn);
curr->arch.guest_table = pagetable_from_mfn(mfn);
- update_cr3(curr);
+ old_shadow = update_cr3(curr);
+
+ /*
+ * In shadow mode update_cr3() can fail, in which case here we're still
+ * running on the prior top-level shadow (which we're about to release).
+ * Switch to the idle page tables in such an event; the guest will have
+ * been crashed already.
+ */
+ if ( likely(!mfn_eq(pagetable_get_mfn(old_shadow),
+ maddr_to_mfn(curr->arch.cr3 & ~X86_CR3_NOFLUSH))) )
+ write_ptbase(curr);
+ else
+ write_ptbase(idle_vcpu[curr->processor]);
- write_ptbase(curr);
+ if ( !pagetable_is_null(old_shadow) )
+ shadow_put_top_level(d, old_shadow);
if ( likely(mfn_x(old_base_mfn) != 0) )
{
--- a/xen/arch/x86/pv/domain.c
+++ b/xen/arch/x86/pv/domain.c
@@ -424,10 +424,13 @@ bool __init xpti_pcid_enabled(void)
static void _toggle_guest_pt(struct vcpu *v)
{
+ bool guest_update;
+ pagetable_t old_shadow;
unsigned long cr3;
v->arch.flags ^= TF_kernel_mode;
- update_cr3(v);
+ guest_update = v->arch.flags & TF_kernel_mode;
+ old_shadow = update_cr3(v);
/*
* Don't flush user global mappings from the TLB. Don't tick TLB clock.
@@ -436,13 +439,31 @@ static void _toggle_guest_pt(struct vcpu
* TLB flush (for just the incoming PCID), as the top level page table may
* have changed behind our backs. To be on the safe side, suppress the
* no-flush unconditionally in this case.
+ *
+ * Furthermore in shadow mode update_cr3() can fail, in which case here
+ * we're still running on the prior top-level shadow (which we're about
+ * to release). Switch to the idle page tables in such an event; the
+ * guest will have been crashed already.
*/
cr3 = v->arch.cr3;
if ( shadow_mode_enabled(v->domain) )
+ {
cr3 &= ~X86_CR3_NOFLUSH;
+
+ if ( unlikely(mfn_eq(pagetable_get_mfn(old_shadow),
+ maddr_to_mfn(cr3))) )
+ {
+ cr3 = idle_vcpu[v->processor]->arch.cr3;
+ /* Also suppress runstate/time area updates below. */
+ guest_update = false;
+ }
+ }
write_cr3(cr3);
- if ( !(v->arch.flags & TF_kernel_mode) )
+ if ( !pagetable_is_null(old_shadow) )
+ shadow_put_top_level(v->domain, old_shadow);
+
+ if ( !guest_update )
return;
if ( v->arch.pv.need_update_runstate_area && update_runstate_area(v) )
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -564,7 +564,7 @@ void audit_domains(void);
#endif
void make_cr3(struct vcpu *v, mfn_t mfn);
-void update_cr3(struct vcpu *v);
+pagetable_t update_cr3(struct vcpu *v);
int vcpu_destroy_pagetables(struct vcpu *);
void *do_page_walk(struct vcpu *v, unsigned long addr);
--- a/xen/include/asm-x86/paging.h
+++ b/xen/include/asm-x86/paging.h
@@ -138,7 +138,7 @@ struct paging_mode {
paddr_t ga, uint32_t *pfec,
unsigned int *page_order);
#endif
- void (*update_cr3 )(struct vcpu *v, int do_locking,
+ pagetable_t (*update_cr3 )(struct vcpu *v, bool do_locking,
bool noflush);
void (*update_paging_modes )(struct vcpu *v);
bool (*flush_tlb )(bool (*flush_vcpu)(void *ctxt,
@@ -315,9 +315,9 @@ static inline unsigned long paging_ga_to
/* Update all the things that are derived from the guest's CR3.
* Called when the guest changes CR3; the caller can then use v->arch.cr3
* as the value to load into the host CR3 to schedule this vcpu */
-static inline void paging_update_cr3(struct vcpu *v, bool noflush)
+static inline pagetable_t paging_update_cr3(struct vcpu *v, bool noflush)
{
- paging_get_hostmode(v)->update_cr3(v, 1, noflush);
+ return paging_get_hostmode(v)->update_cr3(v, 1, noflush);
}
/* Update all the things that are derived from the guest's CR0/CR3/CR4.
--- a/xen/include/asm-x86/shadow.h
+++ b/xen/include/asm-x86/shadow.h
@@ -97,6 +97,9 @@ void shadow_blow_tables_per_domain(struc
int shadow_set_allocation(struct domain *d, unsigned int pages,
bool *preempted);
+/* Helper to invoke for deferred releasing of a top-level shadow's reference. */
+void shadow_put_top_level(struct domain *d, pagetable_t old);
+
#else /* !CONFIG_SHADOW_PAGING */
#define shadow_vcpu_teardown(v) ASSERT(is_pv_vcpu(v))
@@ -118,6 +121,11 @@ static inline void shadow_prepare_page_t
static inline void shadow_blow_tables_per_domain(struct domain *d) {}
+static inline void shadow_put_top_level(struct domain *d, pagetable_t old)
+{
+ ASSERT_UNREACHABLE();
+}
+
static inline int shadow_domctl(struct domain *d,
struct xen_domctl_shadow_op *sc,
XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)

View file

@ -0,0 +1,49 @@
From 08539e8315fdae5f5bfd655d53ed35fd2922fe6c Mon Sep 17 00:00:00 2001
Message-ID: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Jan Beulich <jbeulich@suse.com>
Date: Wed, 23 Aug 2023 09:26:36 +0200
Subject: [XEN PATCH 01/10] x86/AMD: extend Zenbleed check to models "good"
ucode isn't known for
Reportedly the AMD Custom APU 0405 found on SteamDeck, models 0x90 and
0x91, (quoting the respective Linux commit) is similarly affected. Put
another instance of our Zen1 vs Zen2 distinction checks in
amd_check_zenbleed(), forcing use of the chickenbit irrespective of
ucode version (building upon real hardware never surfacing a version of
0xffffffff).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
(cherry picked from commit 145a69c0944ac70cfcf9d247c85dee9e99d9d302)
---
xen/arch/x86/cpu/amd.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 60c6d88edf..a591038757 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -800,10 +800,17 @@ void amd_check_zenbleed(void)
case 0xa0 ... 0xaf: good_rev = 0x08a00008; break;
default:
/*
- * With the Fam17h check above, parts getting here are Zen1.
- * They're not affected.
+ * With the Fam17h check above, most parts getting here are
+ * Zen1. They're not affected. Assume Zen2 ones making it
+ * here are affected regardless of microcode version.
+ *
+ * Zen1 vs Zen2 isn't a simple model number comparison, so use
+ * STIBP as a heuristic to distinguish.
*/
- return;
+ if (!boot_cpu_has(X86_FEATURE_AMD_STIBP))
+ return;
+ good_rev = ~0U;
+ break;
}
rdmsrl(MSR_AMD64_DE_CFG, val);
--
2.41.0

View file

@ -0,0 +1,77 @@
From 1e52cdf07cdf52e5d99957c3ecbddf5b1feda963 Mon Sep 17 00:00:00 2001
Message-ID: <1e52cdf07cdf52e5d99957c3ecbddf5b1feda963.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Tue, 12 Sep 2023 15:06:49 +0100
Subject: [XEN PATCH 02/10] x86/spec-ctrl: Fix confusion between
SPEC_CTRL_EXIT_TO_XEN{,_IST}
c/s 3fffaf9c13e9 ("x86/entry: Avoid using alternatives in NMI/#MC paths")
dropped the only user, leaving behind the (incorrect) implication that Xen had
split exit paths.
Delete the unused SPEC_CTRL_EXIT_TO_XEN and rename SPEC_CTRL_EXIT_TO_XEN_IST
to SPEC_CTRL_EXIT_TO_XEN for consistency.
No functional change.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 1c18d73774533a55ba9d1cbee8bdace03efdb5e7)
---
xen/arch/x86/x86_64/entry.S | 2 +-
xen/include/asm-x86/spec_ctrl_asm.h | 10 ++--------
2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index db2ea7871e..59f2040787 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -664,7 +664,7 @@ UNLIKELY_START(ne, exit_cr3)
UNLIKELY_END(exit_cr3)
/* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */
- SPEC_CTRL_EXIT_TO_XEN_IST /* Req: %rbx=end, Clob: acd */
+ SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */
RESTORE_ALL adj=8
iretq
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index b61a5571ae..f5110616e4 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -79,7 +79,6 @@
* - SPEC_CTRL_ENTRY_FROM_PV
* - SPEC_CTRL_ENTRY_FROM_INTR
* - SPEC_CTRL_ENTRY_FROM_INTR_IST
- * - SPEC_CTRL_EXIT_TO_XEN_IST
* - SPEC_CTRL_EXIT_TO_XEN
* - SPEC_CTRL_EXIT_TO_PV
*
@@ -273,11 +272,6 @@
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \
X86_FEATURE_SC_MSR_PV
-/* Use when exiting to Xen context. */
-#define SPEC_CTRL_EXIT_TO_XEN \
- ALTERNATIVE "", \
- DO_SPEC_CTRL_EXIT_TO_XEN, X86_FEATURE_SC_MSR_PV
-
/* Use when exiting to PV guest context. */
#define SPEC_CTRL_EXIT_TO_PV \
ALTERNATIVE "", \
@@ -344,8 +338,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
UNLIKELY_END(\@_serialise)
.endm
-/* Use when exiting to Xen in IST context. */
-.macro SPEC_CTRL_EXIT_TO_XEN_IST
+/* Use when exiting to Xen context. */
+.macro SPEC_CTRL_EXIT_TO_XEN
/*
* Requires %rbx=stack_end
* Clobbers %rax, %rcx, %rdx
--
2.41.0

View file

@ -0,0 +1,88 @@
From afa5b17f385372226de6b0862f12ab39fda16b5c Mon Sep 17 00:00:00 2001
Message-ID: <afa5b17f385372226de6b0862f12ab39fda16b5c.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Tue, 12 Sep 2023 17:03:16 +0100
Subject: [XEN PATCH 03/10] x86/spec-ctrl: Fold DO_SPEC_CTRL_EXIT_TO_XEN into
it's single user
With the SPEC_CTRL_EXIT_TO_XEN{,_IST} confusion fixed, it's now obvious that
there's only a single EXIT_TO_XEN path. Fold DO_SPEC_CTRL_EXIT_TO_XEN into
SPEC_CTRL_EXIT_TO_XEN to simplify further fixes.
When merging labels, switch the name to .L\@_skip_sc_msr as "skip" on its own
is going to be too generic shortly.
No functional change.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 694bb0f280fd08a4377e36e32b84b5062def4de2)
---
xen/include/asm-x86/spec_ctrl_asm.h | 40 ++++++++++++-----------------
1 file changed, 16 insertions(+), 24 deletions(-)
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index f5110616e4..251c30eee5 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -216,27 +216,6 @@
wrmsr
.endm
-.macro DO_SPEC_CTRL_EXIT_TO_XEN
-/*
- * Requires %rbx=stack_end
- * Clobbers %rax, %rcx, %rdx
- *
- * When returning to Xen context, look to see whether SPEC_CTRL shadowing is
- * in effect, and reload the shadow value. This covers race conditions which
- * exist with an NMI/MCE/etc hitting late in the return-to-guest path.
- */
- xor %edx, %edx
-
- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
- jz .L\@_skip
-
- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax
- mov $MSR_SPEC_CTRL, %ecx
- wrmsr
-
-.L\@_skip:
-.endm
-
.macro DO_SPEC_CTRL_EXIT_TO_GUEST
/*
* Requires %eax=spec_ctrl, %rsp=regs/cpuinfo
@@ -345,11 +324,24 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
* Clobbers %rax, %rcx, %rdx
*/
testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
- jz .L\@_skip
+ jz .L\@_skip_sc_msr
- DO_SPEC_CTRL_EXIT_TO_XEN
+ /*
+ * When returning to Xen context, look to see whether SPEC_CTRL shadowing
+ * is in effect, and reload the shadow value. This covers race conditions
+ * which exist with an NMI/MCE/etc hitting late in the return-to-guest
+ * path.
+ */
+ xor %edx, %edx
-.L\@_skip:
+ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
+ jz .L\@_skip_sc_msr
+
+ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax
+ mov $MSR_SPEC_CTRL, %ecx
+ wrmsr
+
+.L\@_skip_sc_msr:
.endm
#endif /* __ASSEMBLY__ */
--
2.41.0

View file

@ -0,0 +1,86 @@
From 353e876a9dd5a93d0bf8819e77613c33db0de97b Mon Sep 17 00:00:00 2001
Message-ID: <353e876a9dd5a93d0bf8819e77613c33db0de97b.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Fri, 1 Sep 2023 11:38:44 +0100
Subject: [XEN PATCH 04/10] x86/spec-ctrl: Turn the remaining
SPEC_CTRL_{ENTRY,EXIT}_* into asm macros
These have grown more complex over time, with some already having been
converted.
Provide full Requires/Clobbers comments, otherwise missing at this level of
indirection.
No functional change.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 7125429aafb9e3c9c88fc93001fc2300e0ac2cc8)
---
xen/include/asm-x86/spec_ctrl_asm.h | 37 ++++++++++++++++++++++-------
1 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index 251c30eee5..94ed5dc880 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -236,26 +236,45 @@
.endm
/* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */
-#define SPEC_CTRL_ENTRY_FROM_PV \
+.macro SPEC_CTRL_ENTRY_FROM_PV
+/*
+ * Requires %rsp=regs/cpuinfo, %rdx=0
+ * Clobbers %rax, %rcx, %rdx
+ */
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=0), \
- X86_FEATURE_IBPB_ENTRY_PV; \
- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \
+ X86_FEATURE_IBPB_ENTRY_PV
+
+ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV
+
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=0), \
X86_FEATURE_SC_MSR_PV
+.endm
/* Use in interrupt/exception context. May interrupt Xen or PV context. */
-#define SPEC_CTRL_ENTRY_FROM_INTR \
+.macro SPEC_CTRL_ENTRY_FROM_INTR
+/*
+ * Requires %rsp=regs, %r14=stack_end, %rdx=0
+ * Clobbers %rax, %rcx, %rdx
+ */
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_COND_IBPB maybexen=1), \
- X86_FEATURE_IBPB_ENTRY_PV; \
- ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV; \
+ X86_FEATURE_IBPB_ENTRY_PV
+
+ ALTERNATIVE "", DO_OVERWRITE_RSB, X86_FEATURE_SC_RSB_PV
+
ALTERNATIVE "", __stringify(DO_SPEC_CTRL_ENTRY maybexen=1), \
X86_FEATURE_SC_MSR_PV
+.endm
/* Use when exiting to PV guest context. */
-#define SPEC_CTRL_EXIT_TO_PV \
- ALTERNATIVE "", \
- DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV; \
+.macro SPEC_CTRL_EXIT_TO_PV
+/*
+ * Requires %rax=spec_ctrl, %rsp=regs/info
+ * Clobbers %rcx, %rdx
+ */
+ ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV
+
DO_SPEC_CTRL_COND_VERW
+.endm
/*
* Use in IST interrupt/exception context. May interrupt Xen or PV context.
--
2.41.0

View file

@ -0,0 +1,109 @@
From 6cc49c355e952f4ff564c6b817e7eff57c5a02c7 Mon Sep 17 00:00:00 2001
Message-ID: <6cc49c355e952f4ff564c6b817e7eff57c5a02c7.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Wed, 30 Aug 2023 20:11:50 +0100
Subject: [XEN PATCH 05/10] x86/spec-ctrl: Improve all SPEC_CTRL_{ENTER,EXIT}_*
comments
... to better explain how they're used.
Doing so highlights that SPEC_CTRL_EXIT_TO_XEN is missing a VERW flush for the
corner case when e.g. an NMI hits late in an exit-to-guest path.
Leave a TODO, which will be addressed in subsequent patches which arrange for
VERW flushing to be safe within SPEC_CTRL_EXIT_TO_XEN.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 45f00557350dc7d0756551069803fc49c29184ca)
---
xen/include/asm-x86/spec_ctrl_asm.h | 36 +++++++++++++++++++++++++----
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index 94ed5dc880..9c397f7cbd 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -235,7 +235,10 @@
wrmsr
.endm
-/* Use after an entry from PV context (syscall/sysenter/int80/int82/etc). */
+/*
+ * Used after an entry from PV context: SYSCALL, SYSENTER, INT,
+ * etc. There is always a guest speculation state in context.
+ */
.macro SPEC_CTRL_ENTRY_FROM_PV
/*
* Requires %rsp=regs/cpuinfo, %rdx=0
@@ -250,7 +253,11 @@
X86_FEATURE_SC_MSR_PV
.endm
-/* Use in interrupt/exception context. May interrupt Xen or PV context. */
+/*
+ * Used after an exception or maskable interrupt, hitting Xen or PV context.
+ * There will either be a guest speculation context, or (barring fatal
+ * exceptions) a well-formed Xen speculation context.
+ */
.macro SPEC_CTRL_ENTRY_FROM_INTR
/*
* Requires %rsp=regs, %r14=stack_end, %rdx=0
@@ -265,7 +272,10 @@
X86_FEATURE_SC_MSR_PV
.endm
-/* Use when exiting to PV guest context. */
+/*
+ * Used when exiting from any entry context, back to PV context. This
+ * includes from an IST entry which moved onto the primary stack.
+ */
.macro SPEC_CTRL_EXIT_TO_PV
/*
* Requires %rax=spec_ctrl, %rsp=regs/info
@@ -277,7 +287,13 @@
.endm
/*
- * Use in IST interrupt/exception context. May interrupt Xen or PV context.
+ * Used after an IST entry hitting Xen or PV context. Special care is needed,
+ * because when hitting Xen context, there may not be a well-formed
+ * speculation context. (i.e. it can hit in the middle of
+ * SPEC_CTRL_{ENTRY,EXIT}_* regions.)
+ *
+ * An IST entry which hits PV context moves onto the primary stack and leaves
+ * via SPEC_CTRL_EXIT_TO_PV, *not* SPEC_CTRL_EXIT_TO_XEN.
*/
.macro SPEC_CTRL_ENTRY_FROM_INTR_IST
/*
@@ -336,7 +352,14 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
UNLIKELY_END(\@_serialise)
.endm
-/* Use when exiting to Xen context. */
+/*
+ * Use when exiting from any entry context, back to Xen context. This
+ * includes returning to other SPEC_CTRL_{ENTRY,EXIT}_* regions with an
+ * incomplete speculation context.
+ *
+ * Because we might have interrupted Xen beyond SPEC_CTRL_EXIT_TO_$GUEST, we
+ * need to treat this as if it were an EXIT_TO_$GUEST case too.
+ */
.macro SPEC_CTRL_EXIT_TO_XEN
/*
* Requires %rbx=stack_end
@@ -361,6 +384,9 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
wrmsr
.L\@_skip_sc_msr:
+
+ /* TODO VERW */
+
.endm
#endif /* __ASSEMBLY__ */
--
2.41.0

View file

@ -0,0 +1,77 @@
From 19aca8f32778f289112fc8db2ee547cdf29c81ca Mon Sep 17 00:00:00 2001
Message-ID: <19aca8f32778f289112fc8db2ee547cdf29c81ca.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Wed, 13 Sep 2023 13:48:16 +0100
Subject: [XEN PATCH 06/10] x86/entry: Adjust restore_all_xen to hold stack_end
in %r14
All other SPEC_CTRL_{ENTRY,EXIT}_* helpers hold stack_end in %r14. Adjust it
for consistency.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 7aa28849a1155d856e214e9a80a7e65fffdc3e58)
---
xen/arch/x86/x86_64/entry.S | 8 ++++----
xen/include/asm-x86/spec_ctrl_asm.h | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index 59f2040787..266c0a0990 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -656,15 +656,15 @@ restore_all_xen:
* Check whether we need to switch to the per-CPU page tables, in
* case we return to late PV exit code (from an NMI or #MC).
*/
- GET_STACK_END(bx)
- cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%rbx)
+ GET_STACK_END(14)
+ cmpb $0, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14)
UNLIKELY_START(ne, exit_cr3)
- mov STACK_CPUINFO_FIELD(pv_cr3)(%rbx), %rax
+ mov STACK_CPUINFO_FIELD(pv_cr3)(%r14), %rax
mov %rax, %cr3
UNLIKELY_END(exit_cr3)
/* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */
- SPEC_CTRL_EXIT_TO_XEN /* Req: %rbx=end, Clob: acd */
+ SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */
RESTORE_ALL adj=8
iretq
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index 9c397f7cbd..3e745813cf 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -362,10 +362,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
*/
.macro SPEC_CTRL_EXIT_TO_XEN
/*
- * Requires %rbx=stack_end
+ * Requires %r14=stack_end
* Clobbers %rax, %rcx, %rdx
*/
- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
+ testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14)
jz .L\@_skip_sc_msr
/*
@@ -376,10 +376,10 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
*/
xor %edx, %edx
- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%rbx)
+ testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14)
jz .L\@_skip_sc_msr
- mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%rbx), %eax
+ mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax
mov $MSR_SPEC_CTRL, %ecx
wrmsr
--
2.41.0

View file

@ -0,0 +1,112 @@
From 8064cbdbef79e328fad5158beeaf1c45bd0f5bd3 Mon Sep 17 00:00:00 2001
Message-ID: <8064cbdbef79e328fad5158beeaf1c45bd0f5bd3.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Wed, 13 Sep 2023 12:20:12 +0100
Subject: [XEN PATCH 07/10] x86/entry: Track the IST-ness of an entry for the
exit paths
Use %r12 to hold an ist_exit boolean. This register is zero elsewhere in the
entry/exit asm, so it only needs setting in the IST path.
As this is subtle and fragile, add check_ist_exit() to be used in debugging
builds to cross-check that the ist_exit boolean matches the entry vector.
Write check_ist_exit() it in C, because it's debug only and the logic more
complicated than I care to maintain in asm.
For now, we only need to use this signal in the exit-to-Xen path, but some
exit-to-guest paths happen in IST context too. Check the correctness in all
exit paths to avoid the logic bit-rotting.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 21bdc25b05a0f8ab6bc73520a9ca01327360732c)
x86/entry: Partially revert IST-exit checks
The patch adding check_ist_exit() didn't account for the fact that
reset_stack_and_jump() is not an ABI-preserving boundary. The IST-ness in
%r12 doesn't survive into the next context, and is a stale value C.
This shows up in Gitlab CI for the Clang build:
https://gitlab.com/xen-project/people/andyhhp/xen/-/jobs/5112783827
and in OSSTest for GCC 8:
http://logs.test-lab.xenproject.org/osstest/logs/183045/test-amd64-amd64-xl-qemuu-debianhvm-amd64/serial-pinot0.log
There's no straightforward way to reconstruct the IST-exit-ness on the
exit-to-guest path after a context switch. For now, we only need IST-exit on
the return-to-Xen path.
Fixes: 21bdc25b05a0 ("x86/entry: Track the IST-ness of an entry for the exit paths")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 9b57c800b79b96769ea3dcd6468578fa664d19f9)
---
xen/arch/x86/traps.c | 13 +++++++++++++
xen/arch/x86/x86_64/entry.S | 13 ++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 9679bfdb08..f7992ff230 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -2348,6 +2348,19 @@ void asm_domain_crash_synchronous(unsigned long addr)
do_softirq();
}
+#ifdef CONFIG_DEBUG
+void check_ist_exit(const struct cpu_user_regs *regs, bool ist_exit)
+{
+ const unsigned int ist_mask =
+ (1U << X86_EXC_NMI) | (1U << X86_EXC_DB) |
+ (1U << X86_EXC_DF) | (1U << X86_EXC_MC);
+ uint8_t ev = regs->entry_vector;
+ bool is_ist = (ev < TRAP_nr) && ((1U << ev) & ist_mask);
+
+ ASSERT(is_ist == ist_exit);
+}
+#endif
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index 266c0a0990..671e3b3fd5 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -650,8 +650,15 @@ ret_from_intr:
.section .text.entry, "ax", @progbits
ALIGN
-/* No special register assumptions. */
+/* %r12=ist_exit */
restore_all_xen:
+
+#ifdef CONFIG_DEBUG
+ mov %rsp, %rdi
+ mov %r12, %rsi
+ call check_ist_exit
+#endif
+
/*
* Check whether we need to switch to the per-CPU page tables, in
* case we return to late PV exit code (from an NMI or #MC).
@@ -1032,6 +1039,10 @@ handle_ist_exception:
INDIRECT_CALL %rdx
mov %r15, STACK_CPUINFO_FIELD(xen_cr3)(%r14)
mov %bl, STACK_CPUINFO_FIELD(use_pv_cr3)(%r14)
+
+ /* This is an IST exit */
+ mov $1, %r12d
+
cmpb $TRAP_nmi,UREGS_entry_vector(%rsp)
jne ret_from_intr
--
2.41.0

View file

@ -0,0 +1,92 @@
From 3e51782ebb088fde39fdcfa30d002baddd1a9e06 Mon Sep 17 00:00:00 2001
Message-ID: <3e51782ebb088fde39fdcfa30d002baddd1a9e06.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Wed, 13 Sep 2023 13:53:33 +0100
Subject: [XEN PATCH 08/10] x86/spec-ctrl: Issue VERW during IST exit to Xen
There is a corner case where e.g. an NMI hitting an exit-to-guest path after
SPEC_CTRL_EXIT_TO_* would have run the entire NMI handler *after* the VERW
flush to scrub potentially sensitive data from uarch buffers.
In order to compensate, issue VERW when exiting to Xen from an IST entry.
SPEC_CTRL_EXIT_TO_XEN already has two reads of spec_ctrl_flags off the stack,
and we're about to add a third. Load the field into %ebx, and list the
register as clobbered.
%r12 has been arranged to be the ist_exit signal, so add this as an input
dependency and use it to identify when to issue a VERW.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit 3ee6066bcd737756b0990d417d94eddc0b0d2585)
---
xen/arch/x86/x86_64/entry.S | 2 +-
xen/include/asm-x86/spec_ctrl_asm.h | 20 +++++++++++++++-----
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index 671e3b3fd5..88ff5c150f 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -671,7 +671,7 @@ UNLIKELY_START(ne, exit_cr3)
UNLIKELY_END(exit_cr3)
/* WARNING! `ret`, `call *`, `jmp *` not safe beyond this point. */
- SPEC_CTRL_EXIT_TO_XEN /* Req: %r14=end, Clob: acd */
+ SPEC_CTRL_EXIT_TO_XEN /* Req: %r12=ist_exit %r14=end, Clob: abcd */
RESTORE_ALL adj=8
iretq
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index 3e745813cf..8a816b8cf6 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -362,10 +362,12 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
*/
.macro SPEC_CTRL_EXIT_TO_XEN
/*
- * Requires %r14=stack_end
- * Clobbers %rax, %rcx, %rdx
+ * Requires %r12=ist_exit, %r14=stack_end
+ * Clobbers %rax, %rbx, %rcx, %rdx
*/
- testb $SCF_ist_sc_msr, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14)
+ movzbl STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14), %ebx
+
+ testb $SCF_ist_sc_msr, %bl
jz .L\@_skip_sc_msr
/*
@@ -376,7 +378,7 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
*/
xor %edx, %edx
- testb $SCF_use_shadow, STACK_CPUINFO_FIELD(spec_ctrl_flags)(%r14)
+ testb $SCF_use_shadow, %bl
jz .L\@_skip_sc_msr
mov STACK_CPUINFO_FIELD(shadow_spec_ctrl)(%r14), %eax
@@ -385,8 +387,16 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
.L\@_skip_sc_msr:
- /* TODO VERW */
+ test %r12, %r12
+ jz .L\@_skip_ist_exit
+
+ /* Logically DO_SPEC_CTRL_COND_VERW but without the %rsp=cpuinfo dependency */
+ testb $SCF_verw, %bl
+ jz .L\@_skip_verw
+ verw STACK_CPUINFO_FIELD(verw_sel)(%r14)
+.L\@_skip_verw:
+.L\@_skip_ist_exit:
.endm
#endif /* __ASSEMBLY__ */
--
2.41.0

View file

@ -0,0 +1,94 @@
From a5857f1eca17a609119ae928c9fa73bb0996ddd9 Mon Sep 17 00:00:00 2001
Message-ID: <a5857f1eca17a609119ae928c9fa73bb0996ddd9.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Fri, 15 Sep 2023 12:13:51 +0100
Subject: [XEN PATCH 09/10] x86/amd: Introduce is_zen{1,2}_uarch() predicates
We already have 3 cases using STIBP as a Zen1/2 heuristic, and are about to
introduce a 4th. Wrap the heuristic into a pair of predicates rather than
opencoding it, and the explanation of the heuristic, at each usage site.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit de1d265001397f308c5c3c5d3ffc30e7ef8c0705)
---
xen/arch/x86/cpu/amd.c | 18 ++++--------------
xen/include/asm-x86/amd.h | 11 +++++++++++
2 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index a591038757..b71d891901 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -746,15 +746,13 @@ void amd_init_ssbd(const struct cpuinfo_x86 *c)
* non-branch instructions to be ignored. It is to be set unilaterally in
* newer microcode.
*
- * This chickenbit is something unrelated on Zen1, and Zen1 vs Zen2 isn't a
- * simple model number comparison, so use STIBP as a heuristic to separate the
- * two uarches in Fam17h(AMD)/18h(Hygon).
+ * This chickenbit is something unrelated on Zen1.
*/
void amd_init_spectral_chicken(void)
{
uint64_t val, chickenbit = 1 << 1;
- if (cpu_has_hypervisor || !boot_cpu_has(X86_FEATURE_AMD_STIBP))
+ if (cpu_has_hypervisor || !is_zen2_uarch())
return;
if (rdmsr_safe(MSR_AMD64_DE_CFG2, val) == 0 && !(val & chickenbit))
@@ -803,11 +801,8 @@ void amd_check_zenbleed(void)
* With the Fam17h check above, most parts getting here are
* Zen1. They're not affected. Assume Zen2 ones making it
* here are affected regardless of microcode version.
- *
- * Zen1 vs Zen2 isn't a simple model number comparison, so use
- * STIBP as a heuristic to distinguish.
*/
- if (!boot_cpu_has(X86_FEATURE_AMD_STIBP))
+ if (is_zen1_uarch())
return;
good_rev = ~0U;
break;
@@ -1168,12 +1163,7 @@ static int __init zen2_c6_errata_check(void)
*/
s_time_t delta;
- /*
- * Zen1 vs Zen2 isn't a simple model number comparison, so use STIBP as
- * a heuristic to separate the two uarches in Fam17h.
- */
- if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 ||
- !boot_cpu_has(X86_FEATURE_AMD_STIBP))
+ if (cpu_has_hypervisor || boot_cpu_data.x86 != 0x17 || !is_zen2_uarch())
return 0;
/*
diff --git a/xen/include/asm-x86/amd.h b/xen/include/asm-x86/amd.h
index a82382e6bf..7fe1e19217 100644
--- a/xen/include/asm-x86/amd.h
+++ b/xen/include/asm-x86/amd.h
@@ -140,6 +140,17 @@
AMD_MODEL_RANGE(0x11, 0x0, 0x0, 0xff, 0xf), \
AMD_MODEL_RANGE(0x12, 0x0, 0x0, 0xff, 0xf))
+/*
+ * The Zen1 and Zen2 microarchitectures are implemented by AMD (Fam17h) and
+ * Hygon (Fam18h) but without simple model number rules. Instead, use STIBP
+ * as a heuristic that distinguishes the two.
+ *
+ * The caller is required to perform the appropriate vendor/family checks
+ * first.
+ */
+#define is_zen1_uarch() (!boot_cpu_has(X86_FEATURE_AMD_STIBP))
+#define is_zen2_uarch() boot_cpu_has(X86_FEATURE_AMD_STIBP)
+
struct cpuinfo_x86;
int cpu_has_amd_erratum(const struct cpuinfo_x86 *, int, ...);
--
2.41.0

View file

@ -0,0 +1,239 @@
From de751c3d906d17b2e25ee429f81b17a689c7c6c0 Mon Sep 17 00:00:00 2001
Message-ID: <de751c3d906d17b2e25ee429f81b17a689c7c6c0.1695742580.git.m.a.young@durham.ac.uk>
In-Reply-To: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
References: <08539e8315fdae5f5bfd655d53ed35fd2922fe6c.1695742580.git.m.a.young@durham.ac.uk>
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Wed, 30 Aug 2023 20:24:25 +0100
Subject: [XEN PATCH 10/10] x86/spec-ctrl: Mitigate the Zen1 DIV leakage
In the Zen1 microarchitecure, there is one divider in the pipeline which
services uops from both threads. In the case of #DE, the latched result from
the previous DIV to execute will be forwarded speculatively.
This is an interesting covert channel that allows two threads to communicate
without any system calls. In also allows userspace to obtain the result of
the most recent DIV instruction executed (even speculatively) in the core,
which can be from a higher privilege context.
Scrub the result from the divider by executing a non-faulting divide. This
needs performing on the exit-to-guest paths, and ist_exit-to-Xen.
Alternatives in IST context is believed safe now that it's done in NMI
context.
This is XSA-439 / CVE-2023-20588.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit b5926c6ecf05c28ee99c6248c42d691ccbf0c315)
---
docs/misc/xen-command-line.pandoc | 6 +++-
xen/arch/x86/hvm/svm/entry.S | 1 +
xen/arch/x86/spec_ctrl.c | 49 ++++++++++++++++++++++++++++-
xen/include/asm-x86/cpufeatures.h | 2 +-
xen/include/asm-x86/spec_ctrl_asm.h | 17 ++++++++++
5 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
index a37a3890d1..a7a1362bac 100644
--- a/docs/misc/xen-command-line.pandoc
+++ b/docs/misc/xen-command-line.pandoc
@@ -2263,7 +2263,7 @@ By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`).
> {msr-sc,rsb,md-clear,ibpb-entry}=<bool>|{pv,hvm}=<bool>,
> bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,psfd,
> eager-fpu,l1d-flush,branch-harden,srb-lock,
-> unpriv-mmio,gds-mit}=<bool> ]`
+> unpriv-mmio,gds-mit,div-scrub}=<bool> ]`
Controls for speculative execution sidechannel mitigations. By default, Xen
will pick the most appropriate mitigations based on compiled in support,
@@ -2383,6 +2383,10 @@ has elected not to lock the configuration, Xen will use GDS_CTRL to mitigate
GDS with. Otherwise, Xen will mitigate by disabling AVX, which blocks the use
of the AVX2 Gather instructions.
+On all hardware, the `div-scrub=` option can be used to force or prevent Xen
+from mitigating the DIV-leakage vulnerability. By default, Xen will mitigate
+DIV-leakage on hardware believed to be vulnerable.
+
### sync_console
> `= <boolean>`
diff --git a/xen/arch/x86/hvm/svm/entry.S b/xen/arch/x86/hvm/svm/entry.S
index 0ff4008060..ad5ca50c12 100644
--- a/xen/arch/x86/hvm/svm/entry.S
+++ b/xen/arch/x86/hvm/svm/entry.S
@@ -72,6 +72,7 @@ __UNLIKELY_END(nsvm_hap)
1: /* No Spectre v1 concerns. Execution will hit VMRUN imminently. */
.endm
ALTERNATIVE "", svm_vmentry_spec_ctrl, X86_FEATURE_SC_MSR_HVM
+ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV
pop %r15
pop %r14
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index 082445179d..6e82a126a3 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -22,6 +22,7 @@
#include <xen/param.h>
#include <xen/warning.h>
+#include <asm/amd.h>
#include <asm/hvm/svm/svm.h>
#include <asm/microcode.h>
#include <asm/msr.h>
@@ -78,6 +79,7 @@ static int8_t __initdata opt_srb_lock = -1;
static bool __initdata opt_unpriv_mmio;
static bool __read_mostly opt_fb_clear_mmio;
static int8_t __initdata opt_gds_mit = -1;
+static int8_t __initdata opt_div_scrub = -1;
static int __init parse_spec_ctrl(const char *s)
{
@@ -132,6 +134,7 @@ static int __init parse_spec_ctrl(const char *s)
opt_srb_lock = 0;
opt_unpriv_mmio = false;
opt_gds_mit = 0;
+ opt_div_scrub = 0;
}
else if ( val > 0 )
rc = -EINVAL;
@@ -284,6 +287,8 @@ static int __init parse_spec_ctrl(const char *s)
opt_unpriv_mmio = val;
else if ( (val = parse_boolean("gds-mit", s, ss)) >= 0 )
opt_gds_mit = val;
+ else if ( (val = parse_boolean("div-scrub", s, ss)) >= 0 )
+ opt_div_scrub = val;
else
rc = -EINVAL;
@@ -484,7 +489,7 @@ static void __init print_details(enum ind_thunk thunk)
"\n");
/* Settings for Xen's protection, irrespective of guests. */
- printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s\n",
+ printk(" Xen settings: BTI-Thunk %s, SPEC_CTRL: %s%s%s%s%s, Other:%s%s%s%s%s%s\n",
thunk == THUNK_NONE ? "N/A" :
thunk == THUNK_RETPOLINE ? "RETPOLINE" :
thunk == THUNK_LFENCE ? "LFENCE" :
@@ -509,6 +514,7 @@ static void __init print_details(enum ind_thunk thunk)
opt_l1d_flush ? " L1D_FLUSH" : "",
opt_md_clear_pv || opt_md_clear_hvm ||
opt_fb_clear_mmio ? " VERW" : "",
+ opt_div_scrub ? " DIV" : "",
opt_branch_harden ? " BRANCH_HARDEN" : "");
/* L1TF diagnostics, printed if vulnerable or PV shadowing is in use. */
@@ -962,6 +968,45 @@ static void __init srso_calculations(bool hw_smt_enabled)
setup_force_cpu_cap(X86_FEATURE_SRSO_NO);
}
+/*
+ * The Div leakage issue is specific to the AMD Zen1 microarchitecure.
+ *
+ * However, there's no $FOO_NO bit defined, so if we're virtualised we have no
+ * hope of spotting the case where we might move to vulnerable hardware. We
+ * also can't make any useful conclusion about SMT-ness.
+ *
+ * Don't check the hypervisor bit, so at least we do the safe thing when
+ * booting on something that looks like a Zen1 CPU.
+ */
+static bool __init has_div_vuln(void)
+{
+ if ( !(boot_cpu_data.x86_vendor &
+ (X86_VENDOR_AMD | X86_VENDOR_HYGON)) )
+ return false;
+
+ if ( boot_cpu_data.x86 != 0x17 && boot_cpu_data.x86 != 0x18 )
+ return false;
+
+ return is_zen1_uarch();
+}
+
+static void __init div_calculations(bool hw_smt_enabled)
+{
+ bool cpu_bug_div = has_div_vuln();
+
+ if ( opt_div_scrub == -1 )
+ opt_div_scrub = cpu_bug_div;
+
+ if ( opt_div_scrub )
+ setup_force_cpu_cap(X86_FEATURE_SC_DIV);
+
+ if ( opt_smt == -1 && !cpu_has_hypervisor && cpu_bug_div && hw_smt_enabled )
+ warning_add(
+ "Booted on leaky-DIV hardware with SMT/Hyperthreading\n"
+ "enabled. Please assess your configuration and choose an\n"
+ "explicit 'smt=<bool>' setting. See XSA-439.\n");
+}
+
static void __init ibpb_calculations(void)
{
bool def_ibpb_entry = false;
@@ -1716,6 +1761,8 @@ void __init init_speculation_mitigations(void)
ibpb_calculations();
+ div_calculations(hw_smt_enabled);
+
/* Check whether Eager FPU should be enabled by default. */
if ( opt_eager_fpu == -1 )
opt_eager_fpu = should_use_eager_fpu();
diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h
index ccf9d7287c..70b93b6b44 100644
--- a/xen/include/asm-x86/cpufeatures.h
+++ b/xen/include/asm-x86/cpufeatures.h
@@ -35,7 +35,7 @@ XEN_CPUFEATURE(SC_RSB_HVM, X86_SYNTH(19)) /* RSB overwrite needed for HVM
XEN_CPUFEATURE(XEN_SELFSNOOP, X86_SYNTH(20)) /* SELFSNOOP gets used by Xen itself */
XEN_CPUFEATURE(SC_MSR_IDLE, X86_SYNTH(21)) /* Clear MSR_SPEC_CTRL on idle */
XEN_CPUFEATURE(XEN_LBR, X86_SYNTH(22)) /* Xen uses MSR_DEBUGCTL.LBR */
-/* Bits 23 unused. */
+XEN_CPUFEATURE(SC_DIV, X86_SYNTH(23)) /* DIV scrub needed */
XEN_CPUFEATURE(SC_RSB_IDLE, X86_SYNTH(24)) /* RSB overwrite needed for idle. */
XEN_CPUFEATURE(SC_VERW_IDLE, X86_SYNTH(25)) /* VERW used by Xen for idle */
XEN_CPUFEATURE(XEN_SHSTK, X86_SYNTH(26)) /* Xen uses CET Shadow Stacks */
diff --git a/xen/include/asm-x86/spec_ctrl_asm.h b/xen/include/asm-x86/spec_ctrl_asm.h
index 8a816b8cf6..0e69971f66 100644
--- a/xen/include/asm-x86/spec_ctrl_asm.h
+++ b/xen/include/asm-x86/spec_ctrl_asm.h
@@ -182,6 +182,19 @@
.L\@_verw_skip:
.endm
+.macro DO_SPEC_CTRL_DIV
+/*
+ * Requires nothing
+ * Clobbers %rax
+ *
+ * Issue a DIV for its flushing side effect (Zen1 uarch specific). Any
+ * non-faulting DIV will do; a byte DIV has least latency, and doesn't clobber
+ * %rdx.
+ */
+ mov $1, %eax
+ div %al
+.endm
+
.macro DO_SPEC_CTRL_ENTRY maybexen:req
/*
* Requires %rsp=regs (also cpuinfo if !maybexen)
@@ -284,6 +297,8 @@
ALTERNATIVE "", DO_SPEC_CTRL_EXIT_TO_GUEST, X86_FEATURE_SC_MSR_PV
DO_SPEC_CTRL_COND_VERW
+
+ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV
.endm
/*
@@ -396,6 +411,8 @@ UNLIKELY_DISPATCH_LABEL(\@_serialise):
verw STACK_CPUINFO_FIELD(verw_sel)(%r14)
.L\@_skip_verw:
+ ALTERNATIVE "", DO_SPEC_CTRL_DIV, X86_FEATURE_SC_DIV
+
.L\@_skip_ist_exit:
.endm
--
2.41.0

58
xsa440-4.17.patch Normal file
View file

@ -0,0 +1,58 @@
From 5d8b3d1ec98e56155d9650d7f4a70cd8ba9dc27d Mon Sep 17 00:00:00 2001
From: Julien Grall <jgrall@amazon.com>
Date: Fri, 22 Sep 2023 11:32:16 +0100
Subject: tools/xenstored: domain_entry_fix(): Handle conflicting transaction
The function domain_entry_fix() will be initially called to check if the
quota is correct before attempt to commit any nodes. So it would be
possible that accounting is temporarily negative. This is the case
in the following sequence:
1) Create 50 nodes
2) Start two transactions
3) Delete all the nodes in each transaction
4) Commit the two transactions
Because the first transaction will have succeed and updated the
accounting, there is no guarantee that 'd->nbentry + num' will still
be above 0. So the assert() would be triggered.
The assert() was introduced in dbef1f748289 ("tools/xenstore: simplify
and fix per domain node accounting") with the assumption that the
value can't be negative. As this is not true revert to the original
check but restricted to the path where we don't update. Take the
opportunity to explain the rationale behind the check.
This CVE-2023-34323 / XSA-440.
Reported-by: Stanislav Uschakow <suschako@amazon.de>
Fixes: dbef1f748289 ("tools/xenstore: simplify and fix per domain node accounting")
Signed-off-by: Julien Grall <jgrall@amazon.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c
index aa86892fed9e..6074df210c6e 100644
--- a/tools/xenstore/xenstored_domain.c
+++ b/tools/xenstore/xenstored_domain.c
@@ -1094,10 +1094,20 @@ int domain_entry_fix(unsigned int domid, int num, bool update)
}
cnt = d->nbentry + num;
- assert(cnt >= 0);
- if (update)
+ if (update) {
+ assert(cnt >= 0);
d->nbentry = cnt;
+ } else if (cnt < 0) {
+ /*
+ * In a transaction when a node is being added/removed AND
+ * the same node has been added/removed outside the
+ * transaction in parallel, the result value may be negative.
+ * This is no problem, as the transaction will fail due to
+ * the resulting conflict. So override 'cnt'.
+ */
+ cnt = 0;
+ }
return domid_is_unprivileged(domid) ? cnt : 0;
}

185
xsa442-4.17.patch Normal file
View file

@ -0,0 +1,185 @@
From 5b2ccb60ff22fbff44dd66214c2956a434ee6271 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Tue, 13 Jun 2023 15:01:05 +0200
Subject: [PATCH] iommu/amd-vi: flush IOMMU TLB when flushing the DTE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The caching invalidation guidelines from the AMD-Vi specification (48882—Rev
3.07-PUB—Oct 2022) seem to be misleading on some hardware, as devices will
malfunction (see stale DMA mappings) if some fields of the DTE are updated but
the IOMMU TLB is not flushed. This has been observed in practice on AMD
systems. Due to the lack of guidance from the currently published
specification this patch aims to increase the flushing done in order to prevent
device malfunction.
In order to fix, issue an INVALIDATE_IOMMU_PAGES command from
amd_iommu_flush_device(), flushing all the address space. Note this requires
callers to be adjusted in order to pass the DomID on the DTE previous to the
modification.
Some call sites don't provide a valid DomID to amd_iommu_flush_device() in
order to avoid the flush. That's because the device had address translations
disabled and hence the previous DomID on the DTE is not valid. Note the
current logic relies on the entity disabling address translations to also flush
the TLB of the in use DomID.
Device I/O TLB flushing when ATS are enabled is not covered by the current
change, as ATS usage is not security supported.
This is XSA-442 / CVE-2023-34326
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
xen/drivers/passthrough/amd/iommu.h | 3 ++-
xen/drivers/passthrough/amd/iommu_cmd.c | 10 +++++++++-
xen/drivers/passthrough/amd/iommu_guest.c | 5 +++--
xen/drivers/passthrough/amd/iommu_init.c | 6 +++++-
xen/drivers/passthrough/amd/pci_amd_iommu.c | 14 ++++++++++----
5 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/xen/drivers/passthrough/amd/iommu.h b/xen/drivers/passthrough/amd/iommu.h
index 5429ada58ef5..a58be28bf96d 100644
--- a/xen/drivers/passthrough/amd/iommu.h
+++ b/xen/drivers/passthrough/amd/iommu.h
@@ -283,7 +283,8 @@ void amd_iommu_flush_pages(struct domain *d, unsigned long dfn,
unsigned int order);
void amd_iommu_flush_iotlb(u8 devfn, const struct pci_dev *pdev,
uint64_t gaddr, unsigned int order);
-void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf);
+void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf,
+ domid_t domid);
void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf);
void amd_iommu_flush_all_caches(struct amd_iommu *iommu);
diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c b/xen/drivers/passthrough/amd/iommu_cmd.c
index 40ddf366bb4d..cb28b36abc38 100644
--- a/xen/drivers/passthrough/amd/iommu_cmd.c
+++ b/xen/drivers/passthrough/amd/iommu_cmd.c
@@ -363,10 +363,18 @@ void amd_iommu_flush_pages(struct domain *d,
_amd_iommu_flush_pages(d, __dfn_to_daddr(dfn), order);
}
-void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf)
+void amd_iommu_flush_device(struct amd_iommu *iommu, uint16_t bdf,
+ domid_t domid)
{
invalidate_dev_table_entry(iommu, bdf);
flush_command_buffer(iommu, 0);
+
+ /* Also invalidate IOMMU TLB entries when flushing the DTE. */
+ if ( domid != DOMID_INVALID )
+ {
+ invalidate_iommu_pages(iommu, INV_IOMMU_ALL_PAGES_ADDRESS, domid, 0);
+ flush_command_buffer(iommu, 0);
+ }
}
void amd_iommu_flush_intremap(struct amd_iommu *iommu, uint16_t bdf)
diff --git a/xen/drivers/passthrough/amd/iommu_guest.c b/xen/drivers/passthrough/amd/iommu_guest.c
index 80a331f546ed..be86bce6fb03 100644
--- a/xen/drivers/passthrough/amd/iommu_guest.c
+++ b/xen/drivers/passthrough/amd/iommu_guest.c
@@ -385,7 +385,7 @@ static int do_completion_wait(struct domain *d, cmd_entry_t *cmd)
static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd)
{
- uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id;
+ uint16_t gbdf, mbdf, req_id, gdom_id, hdom_id, prev_domid;
struct amd_iommu_dte *gdte, *mdte, *dte_base;
struct amd_iommu *iommu = NULL;
struct guest_iommu *g_iommu;
@@ -445,13 +445,14 @@ static int do_invalidate_dte(struct domain *d, cmd_entry_t *cmd)
req_id = get_dma_requestor_id(iommu->seg, mbdf);
dte_base = iommu->dev_table.buffer;
mdte = &dte_base[req_id];
+ prev_domid = mdte->domain_id;
spin_lock_irqsave(&iommu->lock, flags);
dte_set_gcr3_table(mdte, hdom_id, gcr3_mfn << PAGE_SHIFT, gv, glx);
spin_unlock_irqrestore(&iommu->lock, flags);
- amd_iommu_flush_device(iommu, req_id);
+ amd_iommu_flush_device(iommu, req_id, prev_domid);
return 0;
}
diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c
index 166570648d26..101a60ce1794 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -1547,7 +1547,11 @@ static int cf_check _invalidate_all_devices(
req_id = ivrs_mappings[bdf].dte_requestor_id;
if ( iommu )
{
- amd_iommu_flush_device(iommu, req_id);
+ /*
+ * IOMMU TLB flush performed separately (see
+ * invalidate_all_domain_pages()).
+ */
+ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID);
amd_iommu_flush_intremap(iommu, req_id);
}
}
diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c
index 94e37755064b..8641b84712a0 100644
--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
@@ -192,10 +192,13 @@ static int __must_check amd_iommu_setup_domain_device(
spin_unlock_irqrestore(&iommu->lock, flags);
- amd_iommu_flush_device(iommu, req_id);
+ /* DTE didn't have DMA translations enabled, do not flush the TLB. */
+ amd_iommu_flush_device(iommu, req_id, DOMID_INVALID);
}
else if ( dte->pt_root != mfn_x(page_to_mfn(root_pg)) )
{
+ domid_t prev_domid = dte->domain_id;
+
/*
* Strictly speaking if the device is the only one with this requestor
* ID, it could be allowed to be re-assigned regardless of unity map
@@ -252,7 +255,7 @@ static int __must_check amd_iommu_setup_domain_device(
spin_unlock_irqrestore(&iommu->lock, flags);
- amd_iommu_flush_device(iommu, req_id);
+ amd_iommu_flush_device(iommu, req_id, prev_domid);
}
else
spin_unlock_irqrestore(&iommu->lock, flags);
@@ -421,6 +424,8 @@ static void amd_iommu_disable_domain_device(const struct domain *domain,
spin_lock_irqsave(&iommu->lock, flags);
if ( dte->tv || dte->v )
{
+ domid_t prev_domid = dte->domain_id;
+
/* See the comment in amd_iommu_setup_device_table(). */
dte->int_ctl = IOMMU_DEV_TABLE_INT_CONTROL_ABORTED;
smp_wmb();
@@ -439,7 +444,7 @@ static void amd_iommu_disable_domain_device(const struct domain *domain,
spin_unlock_irqrestore(&iommu->lock, flags);
- amd_iommu_flush_device(iommu, req_id);
+ amd_iommu_flush_device(iommu, req_id, prev_domid);
AMD_IOMMU_DEBUG("Disable: device id = %#x, "
"domain = %d, paging mode = %d\n",
@@ -610,7 +615,8 @@ static int cf_check amd_iommu_add_device(u8 devfn, struct pci_dev *pdev)
spin_unlock_irqrestore(&iommu->lock, flags);
- amd_iommu_flush_device(iommu, bdf);
+ /* DTE didn't have DMA translations enabled, do not flush the TLB. */
+ amd_iommu_flush_device(iommu, bdf, DOMID_INVALID);
}
if ( amd_iommu_reserve_domain_unity_map(
--
2.42.0

70
xsa443-4.16-01.patch Normal file
View file

@ -0,0 +1,70 @@
From c4d597f63832a53bbb1b826af7a4677e40e9fded Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Thu, 14 Sep 2023 13:22:50 +0100
Subject: [PATCH 01/11] libfsimage/xfs: Remove dead code
xfs_info.agnolog (and related code) and XFS_INO_AGBNO_BITS are dead code
that serve no purpose.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
tools/libfsimage/xfs/fsys_xfs.c | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c
index d735a88e55f3..2800699f5985 100644
--- a/tools/libfsimage/xfs/fsys_xfs.c
+++ b/tools/libfsimage/xfs/fsys_xfs.c
@@ -37,7 +37,6 @@ struct xfs_info {
int blklog;
int inopblog;
int agblklog;
- int agnolog;
unsigned int nextents;
xfs_daddr_t next;
xfs_daddr_t daddr;
@@ -65,9 +64,7 @@ static struct xfs_info xfs;
#define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1))
#define XFS_INO_OFFSET_BITS xfs.inopblog
-#define XFS_INO_AGBNO_BITS xfs.agblklog
#define XFS_INO_AGINO_BITS (xfs.agblklog + xfs.inopblog)
-#define XFS_INO_AGNO_BITS xfs.agnolog
static inline xfs_agblock_t
agino2agbno (xfs_agino_t agino)
@@ -149,20 +146,6 @@ xt_len (xfs_bmbt_rec_32_t *r)
return le32(r->l3) & mask32lo(21);
}
-static inline int
-xfs_highbit32(xfs_uint32_t v)
-{
- int i;
-
- if (--v) {
- for (i = 0; i < 31; i++, v >>= 1) {
- if (v == 0)
- return i;
- }
- }
- return 0;
-}
-
static int
isinxt (xfs_fileoff_t key, xfs_fileoff_t offset, xfs_filblks_t len)
{
@@ -472,7 +455,6 @@ xfs_mount (fsi_file_t *ffi, const char *options)
xfs.inopblog = super.sb_inopblog;
xfs.agblklog = super.sb_agblklog;
- xfs.agnolog = xfs_highbit32 (le32(super.sb_agcount));
xfs.btnode_ptr0_off =
((xfs.bsize - sizeof(xfs_btree_block_t)) /
--
2.42.0

32
xsa443-4.16-02.patch Normal file
View file

@ -0,0 +1,32 @@
From f75b0a70da392672fb7d9feed2a9e9515d74df2c Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Thu, 14 Sep 2023 13:22:51 +0100
Subject: [PATCH 02/11] libfsimage/xfs: Amend mask32lo() to allow the value 32
agblklog could plausibly be 32, but that would overflow this shift.
Perform the shift as ULL and cast to u32 at the end instead.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
tools/libfsimage/xfs/fsys_xfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c
index 2800699f5985..4720bb4505c8 100644
--- a/tools/libfsimage/xfs/fsys_xfs.c
+++ b/tools/libfsimage/xfs/fsys_xfs.c
@@ -60,7 +60,7 @@ static struct xfs_info xfs;
#define inode ((xfs_dinode_t *)((char *)FSYS_BUF + 8192))
#define icore (inode->di_core)
-#define mask32lo(n) (((xfs_uint32_t)1 << (n)) - 1)
+#define mask32lo(n) ((xfs_uint32_t)((1ull << (n)) - 1))
#define XFS_INO_MASK(k) ((xfs_uint32_t)((1ULL << (k)) - 1))
#define XFS_INO_OFFSET_BITS xfs.inopblog
--
2.42.0

137
xsa443-4.16-03.patch Normal file
View file

@ -0,0 +1,137 @@
From 25fae23b32ee4d990ae11368ee21e28e66dbfa25 Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Thu, 14 Sep 2023 13:22:52 +0100
Subject: [PATCH 03/11] libfsimage/xfs: Sanity-check the superblock during
mounts
Sanity-check the XFS superblock for wellformedness at the mount handler.
This forces pygrub to abort parsing a potentially malformed filesystem and
ensures the invariants assumed throughout the rest of the code hold.
Also, derive parameters from previously sanitized parameters where possible
(rather than reading them off the superblock)
The code doesn't try to avoid overflowing the end of the disk, because
that's an unlikely and benign error. Parameters used in calculations of
xfs_daddr_t (like the root inode index) aren't in critical need of being
sanitized.
The sanitization of agblklog is basically checking that no obvious
overflows happen on agblklog, and then ensuring agblocks is contained in
the range (2^(sb_agblklog-1), 2^sb_agblklog].
This is part of XSA-443 / CVE-2023-34325
Reported-by: Ferdinand Nölscher <noelscher@google.com>
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
tools/libfsimage/xfs/fsys_xfs.c | 48 ++++++++++++++++++++++++++-------
tools/libfsimage/xfs/xfs.h | 12 +++++++++
2 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c
index 4720bb4505c8..e4eb7e1ee26f 100644
--- a/tools/libfsimage/xfs/fsys_xfs.c
+++ b/tools/libfsimage/xfs/fsys_xfs.c
@@ -17,6 +17,7 @@
* along with this program; If not, see <http://www.gnu.org/licenses/>.
*/
+#include <stdbool.h>
#include <xenfsimage_grub.h>
#include "xfs.h"
@@ -433,29 +434,56 @@ first_dentry (fsi_file_t *ffi, xfs_ino_t *ino)
return next_dentry (ffi, ino);
}
+static bool
+xfs_sb_is_invalid (const xfs_sb_t *super)
+{
+ return (le32(super->sb_magicnum) != XFS_SB_MAGIC)
+ || ((le16(super->sb_versionnum) & XFS_SB_VERSION_NUMBITS) !=
+ XFS_SB_VERSION_4)
+ || (super->sb_inodelog < XFS_SB_INODELOG_MIN)
+ || (super->sb_inodelog > XFS_SB_INODELOG_MAX)
+ || (super->sb_blocklog < XFS_SB_BLOCKLOG_MIN)
+ || (super->sb_blocklog > XFS_SB_BLOCKLOG_MAX)
+ || (super->sb_blocklog < super->sb_inodelog)
+ || (super->sb_agblklog > XFS_SB_AGBLKLOG_MAX)
+ || ((1ull << super->sb_agblklog) < le32(super->sb_agblocks))
+ || (((1ull << super->sb_agblklog) >> 1) >=
+ le32(super->sb_agblocks))
+ || ((super->sb_blocklog + super->sb_dirblklog) >=
+ XFS_SB_DIRBLK_NUMBITS);
+}
+
static int
xfs_mount (fsi_file_t *ffi, const char *options)
{
xfs_sb_t super;
if (!devread (ffi, 0, 0, sizeof(super), (char *)&super)
- || (le32(super.sb_magicnum) != XFS_SB_MAGIC)
- || ((le16(super.sb_versionnum)
- & XFS_SB_VERSION_NUMBITS) != XFS_SB_VERSION_4) ) {
+ || xfs_sb_is_invalid(&super)) {
return 0;
}
- xfs.bsize = le32 (super.sb_blocksize);
- xfs.blklog = super.sb_blocklog;
- xfs.bdlog = xfs.blklog - SECTOR_BITS;
+ /*
+ * Not sanitized. It's exclusively used to generate disk addresses,
+ * so it's not important from a security standpoint.
+ */
xfs.rootino = le64 (super.sb_rootino);
- xfs.isize = le16 (super.sb_inodesize);
- xfs.agblocks = le32 (super.sb_agblocks);
- xfs.dirbsize = xfs.bsize << super.sb_dirblklog;
- xfs.inopblog = super.sb_inopblog;
+ /*
+ * Sanitized to be consistent with each other, only used to
+ * generate disk addresses, so it's safe
+ */
+ xfs.agblocks = le32 (super.sb_agblocks);
xfs.agblklog = super.sb_agblklog;
+ /* Derived from sanitized parameters */
+ xfs.bsize = 1 << super.sb_blocklog;
+ xfs.blklog = super.sb_blocklog;
+ xfs.bdlog = super.sb_blocklog - SECTOR_BITS;
+ xfs.isize = 1 << super.sb_inodelog;
+ xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog);
+ xfs.inopblog = super.sb_blocklog - super.sb_inodelog;
+
xfs.btnode_ptr0_off =
((xfs.bsize - sizeof(xfs_btree_block_t)) /
(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t)))
diff --git a/tools/libfsimage/xfs/xfs.h b/tools/libfsimage/xfs/xfs.h
index 40699281e44d..b87e37d3d7e9 100644
--- a/tools/libfsimage/xfs/xfs.h
+++ b/tools/libfsimage/xfs/xfs.h
@@ -134,6 +134,18 @@ typedef struct xfs_sb
xfs_uint8_t sb_dummy[7]; /* padding */
} xfs_sb_t;
+/* Bound taken from xfs.c in GRUB2. It doesn't exist in the spec */
+#define XFS_SB_DIRBLK_NUMBITS 27
+/* Implied by the XFS specification. The minimum block size is 512 octets */
+#define XFS_SB_BLOCKLOG_MIN 9
+/* Implied by the XFS specification. The maximum block size is 65536 octets */
+#define XFS_SB_BLOCKLOG_MAX 16
+/* Implied by the XFS specification. The minimum inode size is 256 octets */
+#define XFS_SB_INODELOG_MIN 8
+/* Implied by the XFS specification. The maximum inode size is 2048 octets */
+#define XFS_SB_INODELOG_MAX 11
+/* High bound for sb_agblklog */
+#define XFS_SB_AGBLKLOG_MAX 32
/* those are from xfs_btree.h */
--
2.42.0

60
xsa443-4.16-04.patch Normal file
View file

@ -0,0 +1,60 @@
From e72c68e702dd930bc6013182bb44d3e8fbbb6bf4 Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Thu, 14 Sep 2023 13:22:53 +0100
Subject: [PATCH 04/11] libfsimage/xfs: Add compile-time check to libfsimage
Adds the common tools include folder to the -I compile flags
of libfsimage. This allows us to use:
xen-tools/common-macros.h:BUILD_BUG_ON()
With it, statically assert a sanitized "blocklog - SECTOR_BITS" cannot
underflow.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
tools/libfsimage/Rules.mk | 2 +-
tools/libfsimage/xfs/fsys_xfs.c | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/tools/libfsimage/Rules.mk b/tools/libfsimage/Rules.mk
index bb6d42abb494..80598fb70aa7 100644
--- a/tools/libfsimage/Rules.mk
+++ b/tools/libfsimage/Rules.mk
@@ -1,6 +1,6 @@
include $(XEN_ROOT)/tools/Rules.mk
-CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ -DFSIMAGE_FSDIR=\"$(FSDIR)\"
+CFLAGS += -Wno-unknown-pragmas -I$(XEN_ROOT)/tools/libfsimage/common/ $(CFLAGS_xeninclude) -DFSIMAGE_FSDIR=\"$(FSDIR)\"
CFLAGS += -Werror -D_GNU_SOURCE
LDFLAGS += -L../common/
diff --git a/tools/libfsimage/xfs/fsys_xfs.c b/tools/libfsimage/xfs/fsys_xfs.c
index e4eb7e1ee26f..4a8dd6f2397b 100644
--- a/tools/libfsimage/xfs/fsys_xfs.c
+++ b/tools/libfsimage/xfs/fsys_xfs.c
@@ -19,6 +19,7 @@
#include <stdbool.h>
#include <xenfsimage_grub.h>
+#include <xen-tools/libs.h>
#include "xfs.h"
#define MAX_LINK_COUNT 8
@@ -477,9 +478,10 @@ xfs_mount (fsi_file_t *ffi, const char *options)
xfs.agblklog = super.sb_agblklog;
/* Derived from sanitized parameters */
+ BUILD_BUG_ON(XFS_SB_BLOCKLOG_MIN < SECTOR_BITS);
+ xfs.bdlog = super.sb_blocklog - SECTOR_BITS;
xfs.bsize = 1 << super.sb_blocklog;
xfs.blklog = super.sb_blocklog;
- xfs.bdlog = super.sb_blocklog - SECTOR_BITS;
xfs.isize = 1 << super.sb_inodelog;
xfs.dirbsize = 1 << (super.sb_blocklog + super.sb_dirblklog);
xfs.inopblog = super.sb_blocklog - super.sb_inodelog;
--
2.42.0

59
xsa443-4.16-05.patch Normal file
View file

@ -0,0 +1,59 @@
From 75fdc03c5a6b7fac0c3a5ac06a5beaac73aad36f Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Mon, 25 Sep 2023 18:32:21 +0100
Subject: [PATCH 05/11] tools/pygrub: Remove unnecessary hypercall
There's a hypercall being issued in order to determine whether PV64 is
supported, but since Xen 4.3 that's strictly true so it's not required.
Plus, this way we can avoid mapping the privcmd interface altogether in the
depriv pygrub.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/pygrub/src/pygrub | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
index ce7ab0eb8cf3..ce4e07d3e823 100755
--- a/tools/pygrub/src/pygrub
+++ b/tools/pygrub/src/pygrub
@@ -18,7 +18,6 @@ import os, sys, string, struct, tempfile, re, traceback, stat, errno
import copy
import logging
import platform
-import xen.lowlevel.xc
import curses, _curses, curses.textpad, curses.ascii
import getopt
@@ -668,14 +667,6 @@ def run_grub(file, entry, fs, cfg_args):
return grubcfg
-def supports64bitPVguest():
- xc = xen.lowlevel.xc.xc()
- caps = xc.xeninfo()['xen_caps'].split(" ")
- for cap in caps:
- if cap == "xen-3.0-x86_64":
- return True
- return False
-
# If nothing has been specified, look for a Solaris domU. If found, perform the
# necessary tweaks.
def sniff_solaris(fs, cfg):
@@ -684,8 +675,7 @@ def sniff_solaris(fs, cfg):
return cfg
if not cfg["kernel"]:
- if supports64bitPVguest() and \
- fs.file_exists("/platform/i86xpv/kernel/amd64/unix"):
+ if fs.file_exists("/platform/i86xpv/kernel/amd64/unix"):
cfg["kernel"] = "/platform/i86xpv/kernel/amd64/unix"
cfg["ramdisk"] = "/platform/i86pc/amd64/boot_archive"
elif fs.file_exists("/platform/i86xpv/kernel/unix"):
--
2.42.0

65
xsa443-4.16-06.patch Normal file
View file

@ -0,0 +1,65 @@
From 1083a16f63461e844e9515ac4d35d48bf55785af Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Mon, 25 Sep 2023 18:32:22 +0100
Subject: [PATCH 06/11] tools/pygrub: Small refactors
Small tidy up to ensure output_directory always has a trailing '/' to ease
concatenating paths and that `output` can only be a filename or None.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/pygrub/src/pygrub | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
index ce4e07d3e823..1042c05b8676 100755
--- a/tools/pygrub/src/pygrub
+++ b/tools/pygrub/src/pygrub
@@ -793,7 +793,7 @@ if __name__ == "__main__":
debug = False
not_really = False
output_format = "sxp"
- output_directory = "/var/run/xen/pygrub"
+ output_directory = "/var/run/xen/pygrub/"
# what was passed in
incfg = { "kernel": None, "ramdisk": None, "args": "" }
@@ -815,7 +815,8 @@ if __name__ == "__main__":
usage()
sys.exit()
elif o in ("--output",):
- output = a
+ if a != "-":
+ output = a
elif o in ("--kernel",):
incfg["kernel"] = a
elif o in ("--ramdisk",):
@@ -847,12 +848,11 @@ if __name__ == "__main__":
if not os.path.isdir(a):
print("%s is not an existing directory" % a)
sys.exit(1)
- output_directory = a
+ output_directory = a + '/'
if debug:
logging.basicConfig(level=logging.DEBUG)
-
try:
os.makedirs(output_directory, 0o700)
except OSError as e:
@@ -861,7 +861,7 @@ if __name__ == "__main__":
else:
raise
- if output is None or output == "-":
+ if output is None:
fd = sys.stdout.fileno()
else:
fd = os.open(output, os.O_WRONLY)
--
2.42.0

105
xsa443-4.16-07.patch Normal file
View file

@ -0,0 +1,105 @@
From 350db30e33f39af40c1e3752d73c0a30ef2d26e7 Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Mon, 25 Sep 2023 18:32:23 +0100
Subject: [PATCH 07/11] tools/pygrub: Open the output files earlier
This patch allows pygrub to get ahold of every RW file descriptor it needs
early on. A later patch will clamp the filesystem it can access so it can't
obtain any others.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/pygrub/src/pygrub | 37 ++++++++++++++++++++++---------------
1 file changed, 22 insertions(+), 15 deletions(-)
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
index 1042c05b8676..91e2ec2ab105 100755
--- a/tools/pygrub/src/pygrub
+++ b/tools/pygrub/src/pygrub
@@ -738,8 +738,7 @@ if __name__ == "__main__":
def usage():
print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] <image>" %(sys.argv[0],), file=sys.stderr)
- def copy_from_image(fs, file_to_read, file_type, output_directory,
- not_really):
+ def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really):
if not_really:
if fs.file_exists(file_to_read):
return "<%s:%s>" % (file_type, file_to_read)
@@ -750,21 +749,18 @@ if __name__ == "__main__":
except Exception as e:
print(e, file=sys.stderr)
sys.exit("Error opening %s in guest" % file_to_read)
- (tfd, ret) = tempfile.mkstemp(prefix="boot_"+file_type+".",
- dir=output_directory)
dataoff = 0
while True:
data = datafile.read(FS_READ_MAX, dataoff)
if len(data) == 0:
- os.close(tfd)
+ os.close(fd_dst)
del datafile
- return ret
+ return
try:
- os.write(tfd, data)
+ os.write(fd_dst, data)
except Exception as e:
print(e, file=sys.stderr)
- os.close(tfd)
- os.unlink(ret)
+ os.unlink(path_dst)
del datafile
sys.exit("Error writing temporary copy of "+file_type)
dataoff += len(data)
@@ -861,6 +857,14 @@ if __name__ == "__main__":
else:
raise
+ if not_really:
+ fd_kernel = path_kernel = fd_ramdisk = path_ramdisk = None
+ else:
+ (fd_kernel, path_kernel) = tempfile.mkstemp(prefix="boot_kernel.",
+ dir=output_directory)
+ (fd_ramdisk, path_ramdisk) = tempfile.mkstemp(prefix="boot_ramdisk.",
+ dir=output_directory)
+
if output is None:
fd = sys.stdout.fileno()
else:
@@ -920,20 +924,23 @@ if __name__ == "__main__":
if fs is None:
raise RuntimeError("Unable to find partition containing kernel")
- bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel",
- output_directory, not_really)
+ copy_from_image(fs, chosencfg["kernel"], "kernel",
+ fd_kernel, path_kernel, not_really)
+ bootcfg["kernel"] = path_kernel
if chosencfg["ramdisk"]:
try:
- bootcfg["ramdisk"] = copy_from_image(fs, chosencfg["ramdisk"],
- "ramdisk", output_directory,
- not_really)
+ copy_from_image(fs, chosencfg["ramdisk"], "ramdisk",
+ fd_ramdisk, path_ramdisk, not_really)
except:
if not not_really:
- os.unlink(bootcfg["kernel"])
+ os.unlink(path_kernel)
raise
+ bootcfg["ramdisk"] = path_ramdisk
else:
initrd = None
+ if not not_really:
+ os.unlink(path_ramdisk)
args = None
if chosencfg["args"]:
--
2.42.0

126
xsa443-4.16-08.patch Normal file
View file

@ -0,0 +1,126 @@
From 1548ad2291ec7a72ae6949c11d2e50cea135a48d Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Mon, 25 Sep 2023 18:32:24 +0100
Subject: [PATCH 08/11] tools/libfsimage: Export a new function to preload all
plugins
This is work required in order to let pygrub operate in highly deprivileged
chroot mode. This patch adds a function that preloads every plugin, hence
ensuring that a on function exit, every shared library is loaded in memory.
The new "init" function is supposed to be used before depriv, but that's
fine because it's not acting on untrusted data.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/libfsimage/common/fsimage_plugin.c | 4 ++--
tools/libfsimage/common/mapfile-GNU | 1 +
tools/libfsimage/common/mapfile-SunOS | 1 +
tools/libfsimage/common/xenfsimage.h | 8 ++++++++
tools/pygrub/src/fsimage/fsimage.c | 15 +++++++++++++++
5 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/tools/libfsimage/common/fsimage_plugin.c b/tools/libfsimage/common/fsimage_plugin.c
index de1412b4233a..d0cb9e96a654 100644
--- a/tools/libfsimage/common/fsimage_plugin.c
+++ b/tools/libfsimage/common/fsimage_plugin.c
@@ -119,7 +119,7 @@ fail:
return (-1);
}
-static int load_plugins(void)
+int fsi_init(void)
{
const char *fsdir = getenv("XEN_FSIMAGE_FSDIR");
struct dirent *dp = NULL;
@@ -180,7 +180,7 @@ int find_plugin(fsi_t *fsi, const char *path, const char *options)
fsi_plugin_t *fp;
int ret = 0;
- if (plugins == NULL && (ret = load_plugins()) != 0)
+ if (plugins == NULL && (ret = fsi_init()) != 0)
goto out;
for (fp = plugins; fp != NULL; fp = fp->fp_next) {
diff --git a/tools/libfsimage/common/mapfile-GNU b/tools/libfsimage/common/mapfile-GNU
index 26d4d7a69ec7..2d54d527d7f5 100644
--- a/tools/libfsimage/common/mapfile-GNU
+++ b/tools/libfsimage/common/mapfile-GNU
@@ -1,6 +1,7 @@
VERSION {
libfsimage.so.1.0 {
global:
+ fsi_init;
fsi_open_fsimage;
fsi_close_fsimage;
fsi_file_exists;
diff --git a/tools/libfsimage/common/mapfile-SunOS b/tools/libfsimage/common/mapfile-SunOS
index e99b90b65077..48deedb4252f 100644
--- a/tools/libfsimage/common/mapfile-SunOS
+++ b/tools/libfsimage/common/mapfile-SunOS
@@ -1,5 +1,6 @@
libfsimage.so.1.0 {
global:
+ fsi_init;
fsi_open_fsimage;
fsi_close_fsimage;
fsi_file_exists;
diff --git a/tools/libfsimage/common/xenfsimage.h b/tools/libfsimage/common/xenfsimage.h
index 201abd54f23a..341883b2d71a 100644
--- a/tools/libfsimage/common/xenfsimage.h
+++ b/tools/libfsimage/common/xenfsimage.h
@@ -35,6 +35,14 @@ extern C {
typedef struct fsi fsi_t;
typedef struct fsi_file fsi_file_t;
+/*
+ * Optional initialization function. If invoked it loads the associated
+ * dynamic libraries for the backends ahead of time. This is required if
+ * the library is to run as part of a highly deprivileged executable, as
+ * the libraries may not be reachable after depriv.
+ */
+int fsi_init(void);
+
fsi_t *fsi_open_fsimage(const char *, uint64_t, const char *);
void fsi_close_fsimage(fsi_t *);
diff --git a/tools/pygrub/src/fsimage/fsimage.c b/tools/pygrub/src/fsimage/fsimage.c
index 2ebbbe35df92..92fbf2851f01 100644
--- a/tools/pygrub/src/fsimage/fsimage.c
+++ b/tools/pygrub/src/fsimage/fsimage.c
@@ -286,6 +286,15 @@ fsimage_getbootstring(PyObject *o, PyObject *args)
return Py_BuildValue("s", bootstring);
}
+static PyObject *
+fsimage_init(PyObject *o, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, ""))
+ return (NULL);
+
+ return Py_BuildValue("i", fsi_init());
+}
+
PyDoc_STRVAR(fsimage_open__doc__,
"open(name, [offset=off]) - Open the given file as a filesystem image.\n"
"\n"
@@ -297,7 +306,13 @@ PyDoc_STRVAR(fsimage_getbootstring__doc__,
"getbootstring(fs) - Return the boot string needed for this file system "
"or NULL if none is needed.\n");
+PyDoc_STRVAR(fsimage_init__doc__,
+ "init() - Loads every dynamic library contained in xenfsimage "
+ "into memory so that it can be used in chrooted environments.\n");
+
static struct PyMethodDef fsimage_module_methods[] = {
+ { "init", (PyCFunction)fsimage_init,
+ METH_VARARGS, fsimage_init__doc__ },
{ "open", (PyCFunction)fsimage_open,
METH_VARARGS|METH_KEYWORDS, fsimage_open__doc__ },
{ "getbootstring", (PyCFunction)fsimage_getbootstring,
--
2.42.0

307
xsa443-4.16-09.patch Normal file
View file

@ -0,0 +1,307 @@
From 4d331b0b914dfc17bd2d883bc55aeb798930832a Mon Sep 17 00:00:00 2001
From: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Date: Mon, 25 Sep 2023 18:32:25 +0100
Subject: [PATCH 09/11] tools/pygrub: Deprivilege pygrub
Introduce a --runas=<uid> flag to deprivilege pygrub on Linux and *BSDs. It
also implicitly creates a chroot env where it drops a deprivileged forked
process. The chroot itself is cleaned up at the end.
If the --runas arg is present, then pygrub forks, leaving the child to
deprivilege itself, and waiting for it to complete. When the child exists,
the parent performs cleanup and exits with the same error code.
This is roughly what the child does:
1. Initialize libfsimage (this loads every .so in memory so the chroot
can avoid bind-mounting /{,usr}/lib*
2. Create a temporary empty chroot directory
3. Mount tmpfs in it
4. Bind mount the disk inside, because libfsimage expects a path, not a
file descriptor.
5. Remount the root tmpfs to be stricter (ro,nosuid,nodev)
6. Set RLIMIT_FSIZE to a sensibly high amount (128 MiB)
7. Depriv gid, groups and uid
With this scheme in place, the "output" files are writable (up to
RLIMIT_FSIZE octets) and the exposed filesystem is immutable and contains
the single only file we can't easily get rid of (the disk).
If running on Linux, the child process also unshares mount, IPC, and
network namespaces before dropping its privileges.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
tools/pygrub/setup.py | 2 +-
tools/pygrub/src/pygrub | 162 +++++++++++++++++++++++++++++++++++++---
2 files changed, 154 insertions(+), 10 deletions(-)
diff --git a/tools/pygrub/setup.py b/tools/pygrub/setup.py
index b8f1dc4590cf..f16187b6d118 100644
--- a/tools/pygrub/setup.py
+++ b/tools/pygrub/setup.py
@@ -17,7 +17,7 @@ xenfsimage = Extension("xenfsimage",
pkgs = [ 'grub' ]
setup(name='pygrub',
- version='0.6',
+ version='0.7',
description='Boot loader that looks a lot like grub for Xen',
author='Jeremy Katz',
author_email='katzj@redhat.com',
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
index 91e2ec2ab105..7cea496ade08 100755
--- a/tools/pygrub/src/pygrub
+++ b/tools/pygrub/src/pygrub
@@ -16,8 +16,11 @@ from __future__ import print_function
import os, sys, string, struct, tempfile, re, traceback, stat, errno
import copy
+import ctypes, ctypes.util
import logging
import platform
+import resource
+import subprocess
import curses, _curses, curses.textpad, curses.ascii
import getopt
@@ -27,10 +30,135 @@ import grub.GrubConf
import grub.LiloConf
import grub.ExtLinuxConf
-PYGRUB_VER = 0.6
+PYGRUB_VER = 0.7
FS_READ_MAX = 1024 * 1024
SECTOR_SIZE = 512
+# Unless provided through the env variable PYGRUB_MAX_FILE_SIZE_MB, then
+# this is the maximum filesize allowed for files written by the depriv
+# pygrub
+LIMIT_FSIZE = 128 << 20
+
+CLONE_NEWNS = 0x00020000 # mount namespace
+CLONE_NEWNET = 0x40000000 # network namespace
+CLONE_NEWIPC = 0x08000000 # IPC namespace
+
+def unshare(flags):
+ if not sys.platform.startswith("linux"):
+ print("skip_unshare reason=not_linux platform=%s", sys.platform, file=sys.stderr)
+ return
+
+ libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
+ unshare_prototype = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, use_errno=True)
+ unshare = unshare_prototype(('unshare', libc))
+
+ if unshare(flags) < 0:
+ raise OSError(ctypes.get_errno(), os.strerror(ctypes.get_errno()))
+
+def bind_mount(src, dst, options):
+ open(dst, "a").close() # touch
+
+ rc = subprocess.call(["mount", "--bind", "-o", options, src, dst])
+ if rc != 0:
+ raise RuntimeError("bad_mount: src=%s dst=%s opts=%s" %
+ (src, dst, options))
+
+def downgrade_rlimits():
+ # Wipe the authority to use unrequired resources
+ resource.setrlimit(resource.RLIMIT_NPROC, (0, 0))
+ resource.setrlimit(resource.RLIMIT_CORE, (0, 0))
+ resource.setrlimit(resource.RLIMIT_MEMLOCK, (0, 0))
+
+ # py2's resource module doesn't know about resource.RLIMIT_MSGQUEUE
+ #
+ # TODO: Use resource.RLIMIT_MSGQUEUE after python2 is deprecated
+ if sys.platform.startswith('linux'):
+ RLIMIT_MSGQUEUE = 12
+ resource.setrlimit(RLIMIT_MSGQUEUE, (0, 0))
+
+ # The final look of the filesystem for this process is fully RO, but
+ # note we have some file descriptor already open (notably, kernel and
+ # ramdisk). In order to avoid a compromised pygrub from filling up the
+ # filesystem we set RLIMIT_FSIZE to a high bound, so that the file
+ # write permissions are bound.
+ fsize = LIMIT_FSIZE
+ if "PYGRUB_MAX_FILE_SIZE_MB" in os.environ.keys():
+ fsize = os.environ["PYGRUB_MAX_FILE_SIZE_MB"] << 20
+
+ resource.setrlimit(resource.RLIMIT_FSIZE, (fsize, fsize))
+
+def depriv(output_directory, output, device, uid, path_kernel, path_ramdisk):
+ # The only point of this call is to force the loading of libfsimage.
+ # That way, we don't need to bind-mount it into the chroot
+ rc = xenfsimage.init()
+ if rc != 0:
+ os.unlink(path_ramdisk)
+ os.unlink(path_kernel)
+ raise RuntimeError("bad_xenfsimage: rc=%d" % rc)
+
+ # Create a temporary directory for the chroot
+ chroot = tempfile.mkdtemp(prefix=str(uid)+'-', dir=output_directory) + '/'
+ device_path = '/device'
+
+ pid = os.fork()
+ if pid:
+ # parent
+ _, rc = os.waitpid(pid, 0)
+
+ for path in [path_kernel, path_ramdisk]:
+ # If the child didn't write anything, just get rid of it,
+ # otherwise we end up consuming a 0-size file when parsing
+ # systems without a ramdisk that the ultimate caller of pygrub
+ # may just be unaware of
+ if rc != 0 or os.path.getsize(path) == 0:
+ os.unlink(path)
+
+ # Normally, unshare(CLONE_NEWNS) will ensure this is not required.
+ # However, this syscall doesn't exist in *BSD systems and doesn't
+ # auto-unmount everything on older Linux kernels (At least as of
+ # Linux 4.19, but it seems fixed in 5.15). Either way,
+ # recursively unmount everything if needed. Quietly.
+ with open('/dev/null', 'w') as devnull:
+ subprocess.call(["umount", "-f", chroot + device_path],
+ stdout=devnull, stderr=devnull)
+ subprocess.call(["umount", "-f", chroot],
+ stdout=devnull, stderr=devnull)
+ os.rmdir(chroot)
+
+ sys.exit(rc)
+
+ # By unsharing the namespace we're making sure it's all bulk-released
+ # at the end, when the namespaces disappear. This means the kernel does
+ # (almost) all the cleanup for us and the parent just has to remove the
+ # temporary directory.
+ unshare(CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET)
+
+ # Set sensible limits using the setrlimit interface
+ downgrade_rlimits()
+
+ # We'll mount tmpfs on the chroot to ensure the deprivileged child
+ # cannot affect the persistent state. It's RW now in order to
+ # bind-mount the device, but note it's remounted RO after that.
+ rc = subprocess.call(["mount", "-t", "tmpfs", "none", chroot])
+ if rc != 0:
+ raise RuntimeError("mount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot))
+
+ # Bind the untrusted device RO
+ bind_mount(device, chroot + device_path, "ro,nosuid,noexec")
+
+ rc = subprocess.call(["mount", "-t", "tmpfs", "-o", "remount,ro,nosuid,noexec,nodev", "none", chroot])
+ if rc != 0:
+ raise RuntimeError("remount_tmpfs rc=%d dst=\"%s\"" % (rc, chroot))
+
+ # Drop superpowers!
+ os.chroot(chroot)
+ os.chdir('/')
+ os.setgid(uid)
+ os.setgroups([uid])
+ os.setuid(uid)
+
+ return device_path
+
def read_size_roundup(fd, size):
if platform.system() != 'FreeBSD':
return size
@@ -736,7 +864,7 @@ if __name__ == "__main__":
sel = None
def usage():
- print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--offset=] <image>" %(sys.argv[0],), file=sys.stderr)
+ print("Usage: %s [-q|--quiet] [-i|--interactive] [-l|--list-entries] [-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] [--output-directory=] [--output-format=sxp|simple|simple0] [--runas=] [--offset=] <image>" %(sys.argv[0],), file=sys.stderr)
def copy_from_image(fs, file_to_read, file_type, fd_dst, path_dst, not_really):
if not_really:
@@ -760,7 +888,8 @@ if __name__ == "__main__":
os.write(fd_dst, data)
except Exception as e:
print(e, file=sys.stderr)
- os.unlink(path_dst)
+ if path_dst:
+ os.unlink(path_dst)
del datafile
sys.exit("Error writing temporary copy of "+file_type)
dataoff += len(data)
@@ -769,7 +898,7 @@ if __name__ == "__main__":
opts, args = getopt.gnu_getopt(sys.argv[1:], 'qilnh::',
["quiet", "interactive", "list-entries", "not-really", "help",
"output=", "output-format=", "output-directory=", "offset=",
- "entry=", "kernel=",
+ "runas=", "entry=", "kernel=",
"ramdisk=", "args=", "isconfig", "debug"])
except getopt.GetoptError:
usage()
@@ -790,6 +919,7 @@ if __name__ == "__main__":
not_really = False
output_format = "sxp"
output_directory = "/var/run/xen/pygrub/"
+ uid = None
# what was passed in
incfg = { "kernel": None, "ramdisk": None, "args": "" }
@@ -813,6 +943,13 @@ if __name__ == "__main__":
elif o in ("--output",):
if a != "-":
output = a
+ elif o in ("--runas",):
+ try:
+ uid = int(a)
+ except ValueError:
+ print("runas value must be an integer user id")
+ usage()
+ sys.exit(1)
elif o in ("--kernel",):
incfg["kernel"] = a
elif o in ("--ramdisk",):
@@ -849,6 +986,10 @@ if __name__ == "__main__":
if debug:
logging.basicConfig(level=logging.DEBUG)
+ if interactive and uid:
+ print("In order to use --runas, you must also set --entry or -q", file=sys.stderr)
+ sys.exit(1)
+
try:
os.makedirs(output_directory, 0o700)
except OSError as e:
@@ -870,6 +1011,9 @@ if __name__ == "__main__":
else:
fd = os.open(output, os.O_WRONLY)
+ if uid:
+ file = depriv(output_directory, output, file, uid, path_kernel, path_ramdisk)
+
# debug
if isconfig:
chosencfg = run_grub(file, entry, fs, incfg["args"])
@@ -925,21 +1069,21 @@ if __name__ == "__main__":
raise RuntimeError("Unable to find partition containing kernel")
copy_from_image(fs, chosencfg["kernel"], "kernel",
- fd_kernel, path_kernel, not_really)
+ fd_kernel, None if uid else path_kernel, not_really)
bootcfg["kernel"] = path_kernel
if chosencfg["ramdisk"]:
try:
copy_from_image(fs, chosencfg["ramdisk"], "ramdisk",
- fd_ramdisk, path_ramdisk, not_really)
+ fd_ramdisk, None if uid else path_ramdisk, not_really)
except:
- if not not_really:
- os.unlink(path_kernel)
+ if not uid and not not_really:
+ os.unlink(path_kernel)
raise
bootcfg["ramdisk"] = path_ramdisk
else:
initrd = None
- if not not_really:
+ if not uid and not not_really:
os.unlink(path_ramdisk)
args = None
--
2.42.0

250
xsa443-4.16-10.patch Normal file
View file

@ -0,0 +1,250 @@
From a5be7e8b054f586ad934e786232af29fdc6e3ead Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Mon, 25 Sep 2023 14:30:20 +0200
Subject: [PATCH 10/11] libxl: add support for running bootloader in restricted
mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Much like the device model depriv mode, add the same kind of support for the
bootloader. Such feature allows passing a UID as a parameter for the
bootloader to run as, together with the bootloader itself taking the necessary
actions to isolate.
Note that the user to run the bootloader as must have the right permissions to
access the guest disk image (in read mode only), and that the bootloader will
be run in non-interactive mode when restricted.
If enabled bootloader restrict mode will attempt to re-use the user(s) from the
QEMU depriv implementation if no user is provided on the configuration file or
the environment. See docs/features/qemu-deprivilege.pandoc for more
information about how to setup those users.
Bootloader restrict mode is not enabled by default as it requires certain
setup to be done first (setup of the user(s) to use in restrict mode).
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
---
docs/man/xl.1.pod.in | 33 +++++++++++
tools/libs/light/libxl_bootloader.c | 89 ++++++++++++++++++++++++++++-
tools/libs/light/libxl_dm.c | 8 +--
tools/libs/light/libxl_internal.h | 8 +++
4 files changed, 131 insertions(+), 7 deletions(-)
diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in
index 45e1430aeb74..96e6fb1c32a3 100644
--- a/docs/man/xl.1.pod.in
+++ b/docs/man/xl.1.pod.in
@@ -1976,6 +1976,39 @@ ignored:
=back
+=head1 ENVIRONMENT VARIABLES
+
+The following environment variables shall affect the execution of xl:
+
+=over 4
+
+=item LIBXL_BOOTLOADER_RESTRICT
+
+Attempt to restrict the bootloader after startup, to limit the
+consequences of security vulnerabilities due to parsing guest
+owned image files.
+
+See docs/features/qemu-deprivilege.pandoc for more information
+on how to setup the unprivileged users.
+
+Note that running the bootloader in restricted mode also implies using
+non-interactive mode, and the disk image must be readable by the
+restricted user.
+
+Having this variable set is equivalent to enabling the option, even if the
+value is 0.
+
+=item LIBXL_BOOTLOADER_USER
+
+When using bootloader_restrict, run the bootloader as this user. If
+not set the default QEMU restrict users will be used.
+
+NOTE: Each domain MUST have a SEPARATE username.
+
+See docs/features/qemu-deprivilege.pandoc for more information.
+
+=back
+
=head1 SEE ALSO
The following man pages:
diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c
index 1bc6e51827b9..d3a8a4a9ba59 100644
--- a/tools/libs/light/libxl_bootloader.c
+++ b/tools/libs/light/libxl_bootloader.c
@@ -14,6 +14,7 @@
#include "libxl_osdeps.h" /* must come before any other headers */
+#include <pwd.h>
#include <termios.h>
#ifdef HAVE_UTMP_H
#include <utmp.h>
@@ -42,8 +43,71 @@ static void bootloader_arg(libxl__bootloader_state *bl, const char *arg)
bl->args[bl->nargs++] = arg;
}
-static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
- const char *bootloader_path)
+static int bootloader_uid(libxl__gc *gc, domid_t guest_domid,
+ const char *user, uid_t *intended_uid)
+{
+ struct passwd *user_base, user_pwbuf;
+ int rc;
+
+ if (user) {
+ rc = userlookup_helper_getpwnam(gc, user, &user_pwbuf, &user_base);
+ if (rc) return rc;
+
+ if (!user_base) {
+ LOGD(ERROR, guest_domid, "Couldn't find user %s", user);
+ return ERROR_INVAL;
+ }
+
+ *intended_uid = user_base->pw_uid;
+ return 0;
+ }
+
+ /* Re-use QEMU user range for the bootloader. */
+ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_RANGE_BASE,
+ &user_pwbuf, &user_base);
+ if (rc) return rc;
+
+ if (user_base) {
+ struct passwd *user_clash, user_clash_pwbuf;
+ uid_t temp_uid = user_base->pw_uid + guest_domid;
+
+ rc = userlookup_helper_getpwuid(gc, temp_uid, &user_clash_pwbuf,
+ &user_clash);
+ if (rc) return rc;
+
+ if (user_clash) {
+ LOGD(ERROR, guest_domid,
+ "wanted to use uid %ld (%s + %d) but that is user %s !",
+ (long)temp_uid, LIBXL_QEMU_USER_RANGE_BASE,
+ guest_domid, user_clash->pw_name);
+ return ERROR_INVAL;
+ }
+
+ *intended_uid = temp_uid;
+ return 0;
+ }
+
+ rc = userlookup_helper_getpwnam(gc, LIBXL_QEMU_USER_SHARED, &user_pwbuf,
+ &user_base);
+ if (rc) return rc;
+
+ if (user_base) {
+ LOGD(WARN, guest_domid, "Could not find user %s, falling back to %s",
+ LIBXL_QEMU_USER_RANGE_BASE, LIBXL_QEMU_USER_SHARED);
+ *intended_uid = user_base->pw_uid;
+
+ return 0;
+ }
+
+ LOGD(ERROR, guest_domid,
+ "Could not find user %s or range base pseudo-user %s, cannot restrict",
+ LIBXL_QEMU_USER_SHARED, LIBXL_QEMU_USER_RANGE_BASE);
+
+ return ERROR_INVAL;
+}
+
+static int make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
+ const char *bootloader_path)
{
const libxl_domain_build_info *info = bl->info;
@@ -61,6 +125,23 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
ARG(GCSPRINTF("--ramdisk=%s", info->ramdisk));
if (info->cmdline && *info->cmdline != '\0')
ARG(GCSPRINTF("--args=%s", info->cmdline));
+ if (getenv("LIBXL_BOOTLOADER_RESTRICT") ||
+ getenv("LIBXL_BOOTLOADER_USER")) {
+ uid_t uid = -1;
+ int rc = bootloader_uid(gc, bl->domid, getenv("LIBXL_BOOTLOADER_USER"),
+ &uid);
+
+ if (rc) return rc;
+
+ assert(uid != -1);
+ if (!uid) {
+ LOGD(ERROR, bl->domid, "bootloader restrict UID is 0 (root)!");
+ return ERROR_INVAL;
+ }
+ LOGD(DEBUG, bl->domid, "using uid %ld", (long)uid);
+ ARG(GCSPRINTF("--runas=%ld", (long)uid));
+ ARG("--quiet");
+ }
ARG(GCSPRINTF("--output=%s", bl->outputpath));
ARG("--output-format=simple0");
@@ -79,6 +160,7 @@ static void make_bootloader_args(libxl__gc *gc, libxl__bootloader_state *bl,
/* Sentinel for execv */
ARG(NULL);
+ return 0;
#undef ARG
}
@@ -443,7 +525,8 @@ static void bootloader_disk_attached_cb(libxl__egc *egc,
bootloader = bltmp;
}
- make_bootloader_args(gc, bl, bootloader);
+ rc = make_bootloader_args(gc, bl, bootloader);
+ if (rc) goto out;
bl->openpty.ao = ao;
bl->openpty.callback = bootloader_gotptys;
diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c
index fc264a3a13a6..14b593110f7c 100644
--- a/tools/libs/light/libxl_dm.c
+++ b/tools/libs/light/libxl_dm.c
@@ -80,10 +80,10 @@ static int libxl__create_qemu_logfile(libxl__gc *gc, char *name)
* On error, return a libxl-style error code.
*/
#define DEFINE_USERLOOKUP_HELPER(NAME,SPEC_TYPE,STRUCTNAME,SYSCONF) \
- static int userlookup_helper_##NAME(libxl__gc *gc, \
- SPEC_TYPE spec, \
- struct STRUCTNAME *resultbuf, \
- struct STRUCTNAME **out) \
+ int userlookup_helper_##NAME(libxl__gc *gc, \
+ SPEC_TYPE spec, \
+ struct STRUCTNAME *resultbuf, \
+ struct STRUCTNAME **out) \
{ \
struct STRUCTNAME *resultp = NULL; \
char *buf = NULL; \
diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h
index cc27c72ecf30..8415d1feed16 100644
--- a/tools/libs/light/libxl_internal.h
+++ b/tools/libs/light/libxl_internal.h
@@ -4864,6 +4864,14 @@ struct libxl__cpu_policy {
struct xc_msr *msr;
};
+struct passwd;
+_hidden int userlookup_helper_getpwnam(libxl__gc*, const char *user,
+ struct passwd *res,
+ struct passwd **out);
+_hidden int userlookup_helper_getpwuid(libxl__gc*, uid_t uid,
+ struct passwd *res,
+ struct passwd **out);
+
#endif
/*
--
2.42.0

157
xsa443-4.16-11.patch Normal file
View file

@ -0,0 +1,157 @@
From 273cc7ecf0a66334f24f6f740bcd441b542b3323 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Thu, 28 Sep 2023 12:22:35 +0200
Subject: [PATCH 11/11] libxl: limit bootloader execution in restricted mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce a timeout for bootloader execution when running in restricted mode.
Allow overwriting the default time out with an environment provided value.
This is part of XSA-443 / CVE-2023-34325
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
---
docs/man/xl.1.pod.in | 8 ++++++
tools/libs/light/libxl_bootloader.c | 40 +++++++++++++++++++++++++++++
tools/libs/light/libxl_internal.h | 2 ++
3 files changed, 50 insertions(+)
diff --git a/docs/man/xl.1.pod.in b/docs/man/xl.1.pod.in
index 96e6fb1c32a3..8f056450a730 100644
--- a/docs/man/xl.1.pod.in
+++ b/docs/man/xl.1.pod.in
@@ -2007,6 +2007,14 @@ NOTE: Each domain MUST have a SEPARATE username.
See docs/features/qemu-deprivilege.pandoc for more information.
+=item LIBXL_BOOTLOADER_TIMEOUT
+
+Timeout in seconds for bootloader execution when running in restricted mode.
+Otherwise the build time default in LIBXL_BOOTLOADER_TIMEOUT will be used.
+
+If defined the value must be an unsigned integer between 0 and INT_MAX,
+otherwise behavior is undefined. Setting to 0 disables the timeout.
+
=back
=head1 SEE ALSO
diff --git a/tools/libs/light/libxl_bootloader.c b/tools/libs/light/libxl_bootloader.c
index d3a8a4a9ba59..a4beff42654c 100644
--- a/tools/libs/light/libxl_bootloader.c
+++ b/tools/libs/light/libxl_bootloader.c
@@ -30,6 +30,8 @@ static void bootloader_keystrokes_copyfail(libxl__egc *egc,
libxl__datacopier_state *dc, int rc, int onwrite, int errnoval);
static void bootloader_display_copyfail(libxl__egc *egc,
libxl__datacopier_state *dc, int rc, int onwrite, int errnoval);
+static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev,
+ const struct timeval *requested_abs, int rc);
static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc,
int rc);
static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
@@ -297,6 +299,7 @@ void libxl__bootloader_init(libxl__bootloader_state *bl)
bl->ptys[0].master = bl->ptys[0].slave = 0;
bl->ptys[1].master = bl->ptys[1].slave = 0;
libxl__ev_child_init(&bl->child);
+ libxl__ev_time_init(&bl->time);
libxl__domaindeathcheck_init(&bl->deathcheck);
bl->keystrokes.ao = bl->ao; libxl__datacopier_init(&bl->keystrokes);
bl->display.ao = bl->ao; libxl__datacopier_init(&bl->display);
@@ -314,6 +317,7 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl)
libxl__domaindeathcheck_stop(gc,&bl->deathcheck);
libxl__datacopier_kill(&bl->keystrokes);
libxl__datacopier_kill(&bl->display);
+ libxl__ev_time_deregister(gc, &bl->time);
for (i=0; i<2; i++) {
libxl__carefd_close(bl->ptys[i].master);
libxl__carefd_close(bl->ptys[i].slave);
@@ -375,6 +379,7 @@ static void bootloader_stop(libxl__egc *egc,
libxl__datacopier_kill(&bl->keystrokes);
libxl__datacopier_kill(&bl->display);
+ libxl__ev_time_deregister(gc, &bl->time);
if (libxl__ev_child_inuse(&bl->child)) {
r = kill(bl->child.pid, SIGTERM);
if (r) LOGED(WARN, bl->domid, "%sfailed to kill bootloader [%lu]",
@@ -637,6 +642,25 @@ static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
struct termios termattr;
+ if (getenv("LIBXL_BOOTLOADER_RESTRICT") ||
+ getenv("LIBXL_BOOTLOADER_USER")) {
+ const char *timeout_env = getenv("LIBXL_BOOTLOADER_TIMEOUT");
+ int timeout = timeout_env ? atoi(timeout_env)
+ : LIBXL_BOOTLOADER_TIMEOUT;
+
+ if (timeout) {
+ /* Set execution timeout */
+ rc = libxl__ev_time_register_rel(ao, &bl->time,
+ bootloader_timeout,
+ timeout * 1000);
+ if (rc) {
+ LOGED(ERROR, bl->domid,
+ "unable to register timeout for bootloader execution");
+ goto out;
+ }
+ }
+ }
+
pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished);
if (pid == -1) {
rc = ERROR_FAIL;
@@ -702,6 +726,21 @@ static void bootloader_display_copyfail(libxl__egc *egc,
libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, display);
bootloader_copyfail(egc, "bootloader output", bl, 1, rc,onwrite,errnoval);
}
+static void bootloader_timeout(libxl__egc *egc, libxl__ev_time *ev,
+ const struct timeval *requested_abs, int rc)
+{
+ libxl__bootloader_state *bl = CONTAINER_OF(ev, *bl, time);
+ STATE_AO_GC(bl->ao);
+
+ libxl__ev_time_deregister(gc, &bl->time);
+
+ assert(libxl__ev_child_inuse(&bl->child));
+ LOGD(ERROR, bl->domid, "killing bootloader because of timeout");
+
+ libxl__ev_child_kill_deregister(ao, &bl->child, SIGKILL);
+
+ bootloader_callback(egc, bl, rc);
+}
static void bootloader_domaindeath(libxl__egc *egc,
libxl__domaindeathcheck *dc,
@@ -718,6 +757,7 @@ static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
STATE_AO_GC(bl->ao);
int rc;
+ libxl__ev_time_deregister(gc, &bl->time);
libxl__datacopier_kill(&bl->keystrokes);
libxl__datacopier_kill(&bl->display);
diff --git a/tools/libs/light/libxl_internal.h b/tools/libs/light/libxl_internal.h
index 8415d1feed16..a9581289f462 100644
--- a/tools/libs/light/libxl_internal.h
+++ b/tools/libs/light/libxl_internal.h
@@ -103,6 +103,7 @@
#define LIBXL_QMP_CMD_TIMEOUT 10
#define LIBXL_STUBDOM_START_TIMEOUT 30
#define LIBXL_QEMU_BODGE_TIMEOUT 2
+#define LIBXL_BOOTLOADER_TIMEOUT 120
#define LIBXL_XENCONSOLE_LIMIT 1048576
#define LIBXL_XENCONSOLE_PROTOCOL "vt100"
#define LIBXL_MAXMEM_CONSTANT 1024
@@ -3738,6 +3739,7 @@ struct libxl__bootloader_state {
libxl__openpty_state openpty;
libxl__openpty_result ptys[2]; /* [0] is for bootloader */
libxl__ev_child child;
+ libxl__ev_time time;
libxl__domaindeathcheck deathcheck;
int nargs, argsspace;
const char **args;
--
2.42.0

93
xsa444-4.16-1.patch Normal file
View file

@ -0,0 +1,93 @@
From: Andrew Cooper <andrew.cooper3@citrix.com>
Subject: x86/svm: Fix asymmetry with AMD DR MASK context switching
The handling of MSR_DR{0..3}_MASK is asymmetric between PV and HVM guests.
HVM guests context switch in based on the guest view of DBEXT, whereas PV
guest switch in base on the host capability. Both guest types leave the
context dirty for the next vCPU.
This leads to the following issue:
* PV or HVM guest has debugging active (%dr7 + mask)
* Switch-out deactivates %dr7 but leaves other state stale in hardware
* Another HVM guest with masks unavailable has debugging active
* Switch in loads %dr7 but leaves the mask MSRs alone
Now, the second guest's vCPU is operating in the context of the prior vCPU's
mask MSR, while the environment the vCPU can see says there are no mask MSRs.
As a stopgap, adjust the HVM path to switch in the masks based on host
capabilities rather than guest visibility (i.e. like the PV path). Adjustment
of the intercepts still needs to be dependent on the guest visibility of
DBEXT.
This is part of XSA-444 / CVE-2023-34327
Fixes: c097f54912d3 ("x86/SVM: support data breakpoint extension registers")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index a019d196e071..ba4069f9100a 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -185,6 +185,10 @@ static void svm_save_dr(struct vcpu *v)
v->arch.hvm.flag_dr_dirty = 0;
vmcb_set_dr_intercepts(vmcb, ~0u);
+ /*
+ * The guest can only have changed the mask MSRs if we previous dropped
+ * intercepts. Re-read them from hardware.
+ */
if ( v->domain->arch.cpuid->extd.dbext )
{
svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_RW);
@@ -216,17 +220,25 @@ static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v)
ASSERT(v == current);
- if ( v->domain->arch.cpuid->extd.dbext )
+ /*
+ * Both the PV and HVM paths leave stale DR_MASK values in hardware on
+ * context-switch-out. If we're activating %dr7 for the guest, we must
+ * sync the DR_MASKs too, whether or not the guest can see them.
+ */
+ if ( boot_cpu_has(X86_FEATURE_DBEXT) )
{
- svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE);
- svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE);
- svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE);
- svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE);
-
wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, v->arch.msrs->dr_mask[0]);
wrmsrl(MSR_AMD64_DR1_ADDRESS_MASK, v->arch.msrs->dr_mask[1]);
wrmsrl(MSR_AMD64_DR2_ADDRESS_MASK, v->arch.msrs->dr_mask[2]);
wrmsrl(MSR_AMD64_DR3_ADDRESS_MASK, v->arch.msrs->dr_mask[3]);
+
+ if ( v->domain->arch.cpuid->extd.dbext )
+ {
+ svm_intercept_msr(v, MSR_AMD64_DR0_ADDRESS_MASK, MSR_INTERCEPT_NONE);
+ svm_intercept_msr(v, MSR_AMD64_DR1_ADDRESS_MASK, MSR_INTERCEPT_NONE);
+ svm_intercept_msr(v, MSR_AMD64_DR2_ADDRESS_MASK, MSR_INTERCEPT_NONE);
+ svm_intercept_msr(v, MSR_AMD64_DR3_ADDRESS_MASK, MSR_INTERCEPT_NONE);
+ }
}
write_debugreg(0, v->arch.dr[0]);
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index f7992ff230b5..a142a63dd869 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -2314,6 +2314,11 @@ void activate_debugregs(const struct vcpu *curr)
if ( curr->arch.dr7 & DR7_ACTIVE_MASK )
write_debugreg(7, curr->arch.dr7);
+ /*
+ * Both the PV and HVM paths leave stale DR_MASK values in hardware on
+ * context-switch-out. If we're activating %dr7 for the guest, we must
+ * sync the DR_MASKs too, whether or not the guest can see them.
+ */
if ( boot_cpu_has(X86_FEATURE_DBEXT) )
{
wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, curr->arch.msrs->dr_mask[0]);

72
xsa444-4.16-2.patch Normal file
View file

@ -0,0 +1,72 @@
From: Andrew Cooper <andrew.cooper3@citrix.com>
Subject: x86/pv: Correct the auditing of guest breakpoint addresses
The use of access_ok() is buggy, because it permits access to the compat
translation area. 64bit PV guests don't use the XLAT area, but on AMD
hardware, the DBEXT feature allows a breakpoint to match up to a 4G aligned
region, allowing the breakpoint to reach outside of the XLAT area.
Prior to c/s cda16c1bb223 ("x86: mirror compat argument translation area for
32-bit PV"), the live GDT was within 4G of the XLAT area.
All together, this allowed a malicious 64bit PV guest on AMD hardware to place
a breakpoint over the live GDT, and trigger a #DB livelock (CVE-2015-8104).
Introduce breakpoint_addr_ok() and explain why __addr_ok() happens to be an
appropriate check in this case.
For Xen 4.14 and later, this is a latent bug because the XLAT area has moved
to be on its own with nothing interesting adjacent. For Xen 4.13 and older on
AMD hardware, this fixes a PV-trigger-able DoS.
This is part of XSA-444 / CVE-2023-34328.
Fixes: 65e355490817 ("x86/PV: support data breakpoint extension registers")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
diff --git a/xen/arch/x86/pv/misc-hypercalls.c b/xen/arch/x86/pv/misc-hypercalls.c
index 5dade2472687..681c16108fd1 100644
--- a/xen/arch/x86/pv/misc-hypercalls.c
+++ b/xen/arch/x86/pv/misc-hypercalls.c
@@ -68,7 +68,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
switch ( reg )
{
case 0 ... 3:
- if ( !access_ok(value, sizeof(long)) )
+ if ( !breakpoint_addr_ok(value) )
return -EPERM;
v->arch.dr[reg] = value;
diff --git a/xen/include/asm-x86/debugreg.h b/xen/include/asm-x86/debugreg.h
index c57914efc6e8..cc298265244b 100644
--- a/xen/include/asm-x86/debugreg.h
+++ b/xen/include/asm-x86/debugreg.h
@@ -77,6 +77,26 @@
asm volatile ( "mov %%db" #reg ",%0" : "=r" (__val) ); \
__val; \
})
+
+/*
+ * Architecturally, %dr{0..3} can have any arbitrary value. However, Xen
+ * can't allow the guest to breakpoint the Xen address range, so we limit the
+ * guest to the lower canonical half, or above the Xen range in the higher
+ * canonical half.
+ *
+ * Breakpoint lengths are specified to mask the low order address bits,
+ * meaning all breakpoints are naturally aligned. With %dr7, the widest
+ * breakpoint is 8 bytes. With DBEXT, the widest breakpoint is 4G. Both of
+ * the Xen boundaries have >4G alignment.
+ *
+ * In principle we should account for HYPERVISOR_COMPAT_VIRT_START(d), but
+ * 64bit Xen has never enforced this for compat guests, and there's no problem
+ * (to Xen) if the guest breakpoints it's alias of the M2P. Skipping this
+ * aspect simplifies the logic, and causes us not to reject a migrating guest
+ * which operated fine on prior versions of Xen.
+ */
+#define breakpoint_addr_ok(a) __addr_ok(a)
+
long set_debugreg(struct vcpu *, unsigned int reg, unsigned long value);
void activate_debugregs(const struct vcpu *);

65
xsa445-4.16.patch Normal file
View file

@ -0,0 +1,65 @@
From 88fa5b0db062a8f2ccac4ba05ef75768b2b03e5a Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Wed, 11 Oct 2023 13:14:21 +0200
Subject: [PATCH] iommu/amd-vi: use correct level for quarantine domain page
tables
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The current setup of the quarantine page tables assumes that the quarantine
domain (dom_io) has been initialized with an address width of
DEFAULT_DOMAIN_ADDRESS_WIDTH (48).
However dom_io being a PV domain gets the AMD-Vi IOMMU page tables levels based
on the maximum (hot pluggable) RAM address, and hence on systems with no RAM
above the 512GB mark only 3 page-table levels are configured in the IOMMU.
On systems without RAM above the 512GB boundary amd_iommu_quarantine_init()
will setup page tables for the scratch page with 4 levels, while the IOMMU will
be configured to use 3 levels only. The page destined to be used as level 1,
and to contain a directory of PTEs ends up being the address in a PTE itself,
and thus level 1 page becomes the leaf page. Without the level mismatch it's
level 0 page that should be the leaf page instead.
The level 1 page won't be used as such, and hence it's not possible to use it
to gain access to other memory on the system. However that page is not cleared
in amd_iommu_quarantine_init() as part of re-initialization of the device
quarantine page tables, and hence data on the level 1 page can be leaked
between device usages.
Fix this by making sure the paging levels setup by amd_iommu_quarantine_init()
match the number configured on the IOMMUs.
Note that IVMD regions are not affected by this issue, as those areas are
mapped taking the configured paging levels into account.
This is XSA-445 / CVE-2023-46835
Fixes: ea38867831da ('x86 / iommu: set up a scratch page in the quarantine domain')
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
xen/drivers/passthrough/amd/iommu_map.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/xen/drivers/passthrough/amd/iommu_map.c b/xen/drivers/passthrough/amd/iommu_map.c
index cf6f01b633e4..1b414a413b89 100644
--- a/xen/drivers/passthrough/amd/iommu_map.c
+++ b/xen/drivers/passthrough/amd/iommu_map.c
@@ -654,9 +654,7 @@ static int fill_qpt(union amd_iommu_pte *this, unsigned int level,
int amd_iommu_quarantine_init(struct pci_dev *pdev, bool scratch_page)
{
struct domain_iommu *hd = dom_iommu(dom_io);
- unsigned long end_gfn =
- 1ul << (DEFAULT_DOMAIN_ADDRESS_WIDTH - PAGE_SHIFT);
- unsigned int level = amd_iommu_get_paging_mode(end_gfn);
+ unsigned int level = hd->arch.amd.paging_mode;
unsigned int req_id = get_dma_requestor_id(pdev->seg, pdev->sbdf.bdf);
const struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg);
int rc;
base-commit: 29efce0f8f10e381417a61f2f9988b40d4f6bcf0
--
2.30.2

115
xsa446.patch Normal file
View file

@ -0,0 +1,115 @@
From 80d5aada598c3a800a350003d5d582931545e13c Mon Sep 17 00:00:00 2001
From: Andrew Cooper <andrew.cooper3@citrix.com>
Date: Thu, 26 Oct 2023 14:37:38 +0100
Subject: [PATCH] x86/spec-ctrl: Remove conditional IRQs-on-ness for INT
$0x80/0x82 paths
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Before speculation defences, some paths in Xen could genuinely get away with
being IRQs-on at entry. But XPTI invalidated this property on most paths, and
attempting to maintain it on the remaining paths was a mistake.
Fast forward, and DO_SPEC_CTRL_COND_IBPB (protection for AMD BTC/SRSO) is not
IRQ-safe, running with IRQs enabled in some cases. The other actions taken on
these paths happen to be IRQ-safe.
Make entry_int82() and int80_direct_trap() unconditionally Interrupt Gates
rather than Trap Gates. Remove the conditional re-adjustment of
int80_direct_trap() in smp_prepare_cpus(), and have entry_int82() explicitly
enable interrupts when safe to do so.
In smp_prepare_cpus(), with the conditional re-adjustment removed, the
clearing of pv_cr3 is the only remaining action gated on XPTI, and it is out
of place anyway, repeating work already done by smp_prepare_boot_cpu(). Drop
the entire if() condition to avoid leaving an incorrect vestigial remnant.
Also drop comments which make incorrect statements about when its safe to
enable interrupts.
This is XSA-446 / CVE-2023-46836
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
---
xen/arch/x86/pv/traps.c | 4 ++--
xen/arch/x86/smpboot.c | 14 --------------
xen/arch/x86/x86_64/compat/entry.S | 2 ++
xen/arch/x86/x86_64/entry.S | 1 -
4 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/xen/arch/x86/pv/traps.c b/xen/arch/x86/pv/traps.c
index 74f333da7e1c..240d1a2db7a3 100644
--- a/xen/arch/x86/pv/traps.c
+++ b/xen/arch/x86/pv/traps.c
@@ -139,11 +139,11 @@ void __init pv_trap_init(void)
#ifdef CONFIG_PV32
/* The 32-on-64 hypercall vector is only accessible from ring 1. */
_set_gate(idt_table + HYPERCALL_VECTOR,
- SYS_DESC_trap_gate, 1, entry_int82);
+ SYS_DESC_irq_gate, 1, entry_int82);
#endif
/* Fast trap for int80 (faster than taking the #GP-fixup path). */
- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_trap_gate, 3,
+ _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3,
&int80_direct_trap);
open_softirq(NMI_SOFTIRQ, nmi_softirq);
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 3a1a659082c6..4c54ecbc91d7 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -1158,20 +1158,6 @@ void __init smp_prepare_cpus(void)
stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1));
- if ( opt_xpti_hwdom || opt_xpti_domu )
- {
- get_cpu_info()->pv_cr3 = 0;
-
-#ifdef CONFIG_PV
- /*
- * All entry points which may need to switch page tables have to start
- * with interrupts off. Re-write what pv_trap_init() has put there.
- */
- _set_gate(idt_table + LEGACY_SYSCALL_VECTOR, SYS_DESC_irq_gate, 3,
- &int80_direct_trap);
-#endif
- }
-
set_nr_sockets();
socket_cpumask = xzalloc_array(cpumask_t *, nr_sockets);
diff --git a/xen/arch/x86/x86_64/compat/entry.S b/xen/arch/x86/x86_64/compat/entry.S
index bd5abd8040bd..fcc3a721f147 100644
--- a/xen/arch/x86/x86_64/compat/entry.S
+++ b/xen/arch/x86/x86_64/compat/entry.S
@@ -21,6 +21,8 @@ ENTRY(entry_int82)
SPEC_CTRL_ENTRY_FROM_PV /* Req: %rsp=regs/cpuinfo, %rdx=0, Clob: acd */
/* WARNING! `ret`, `call *`, `jmp *` not safe before this point. */
+ sti
+
CR4_PV32_RESTORE
GET_CURRENT(bx)
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index 5ca74f5f62b2..9a7b129aa7e4 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -327,7 +327,6 @@ ENTRY(sysenter_entry)
#ifdef CONFIG_XEN_SHSTK
ALTERNATIVE "", "setssbsy", X86_FEATURE_XEN_SHSTK
#endif
- /* sti could live here when we don't switch page tables below. */
pushq $FLAT_USER_SS
pushq $0
pushfq
base-commit: 7befef87cc9b1bb8ca15d866ce1ecd9165ccb58c
prerequisite-patch-id: 142a87c707411d49e136c3fb76f1b14963ec6dc8
--
2.30.2

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,

View file

@ -1,194 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_memory_mapping without acquiring domctl lock
With dedicated locking added, the domctl lock isn't required here anymore.
Move the re-purposed dedicated XSM check as early as possible.
Minimal "modernization": Switch "add" to bool and use %pd in log messages.
This is part of XSA-492.
Fixes: fda49f9b3fbb ("Add build option to allow more hypercalls from stubdoms")
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
@@ -376,6 +376,66 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
copyback = true;
goto domctl_out_unlock_domonly;
+ case XEN_DOMCTL_memory_mapping:
+ {
+ unsigned long gfn = op->u.memory_mapping.first_gfn;
+ unsigned long mfn = op->u.memory_mapping.first_mfn;
+ unsigned long nr_mfns = op->u.memory_mapping.nr_mfns;
+ unsigned long mfn_end = mfn + nr_mfns - 1;
+ bool add = op->u.memory_mapping.add_mapping;
+
+ ret = -EINVAL;
+ if ( mfn_end < mfn || /* Wrap? */
+ ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) ||
+ (gfn + nr_mfns - 1) < gfn ) /* Wrap? */
+ goto domctl_out_unlock_domonly;
+
+ ret = xsm_iomem_mapping(XSM_DM_PRIV, d, mfn, mfn_end, add);
+ if ( ret || !paging_mode_translate(d) )
+ goto domctl_out_unlock_domonly;
+
+#ifndef CONFIG_X86 /* XXX ARM!? */
+ ret = -E2BIG;
+ /* Must break hypercall up as this could take a while. */
+ if ( nr_mfns > 64 )
+ goto domctl_out_unlock_domonly;
+#endif
+
+ iocaps_double_lock(d, false);
+
+ ret = -EPERM;
+ if ( !iomem_access_permitted(current->domain, mfn, mfn_end) ||
+ !iomem_access_permitted(d, mfn, mfn_end) )
+ /* Nothing. */;
+ else if ( add )
+ {
+ printk(XENLOG_G_DEBUG
+ "memory_map:add: %pd gfn=%lx mfn=%lx nr=%lx\n",
+ d, gfn, mfn, nr_mfns);
+
+ ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn));
+ if ( ret < 0 )
+ printk(XENLOG_G_WARNING
+ "memory_map:fail: %pd gfn=%lx mfn=%lx nr=%lx ret:%ld\n",
+ d, gfn, mfn, nr_mfns, ret);
+ }
+ else
+ {
+ printk(XENLOG_G_DEBUG
+ "memory_map:remove: %pd gfn=%lx mfn=%lx nr=%lx\n",
+ d, gfn, mfn, nr_mfns);
+
+ ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn));
+ if ( ret < 0 && is_hardware_domain(current->domain) )
+ printk(XENLOG_ERR
+ "memory_map: error %ld removing %pd access to [%lx,%lx]\n",
+ ret, d, mfn, mfn_end);
+ }
+
+ iocaps_double_unlock(d, false);
+ goto domctl_out_unlock_domonly;
+ }
+
default:
/* Everything else handled further down. */
break;
@@ -736,64 +796,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
break;
}
- case XEN_DOMCTL_memory_mapping:
- {
- unsigned long gfn = op->u.memory_mapping.first_gfn;
- unsigned long mfn = op->u.memory_mapping.first_mfn;
- unsigned long nr_mfns = op->u.memory_mapping.nr_mfns;
- unsigned long mfn_end = mfn + nr_mfns - 1;
- int add = op->u.memory_mapping.add_mapping;
-
- ret = -EINVAL;
- if ( mfn_end < mfn || /* wrap? */
- ((mfn | mfn_end) >> (paddr_bits - PAGE_SHIFT)) ||
- (gfn + nr_mfns - 1) < gfn ) /* wrap? */
- break;
-
-#ifndef CONFIG_X86 /* XXX ARM!? */
- ret = -E2BIG;
- /* Must break hypercall up as this could take a while. */
- if ( nr_mfns > 64 )
- 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) ||
- (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",
- d->domain_id, gfn, mfn, nr_mfns);
-
- ret = map_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn));
- if ( ret < 0 )
- printk(XENLOG_G_WARNING
- "memory_map:fail: dom%d gfn=%lx mfn=%lx nr=%lx ret:%ld\n",
- d->domain_id, gfn, mfn, nr_mfns, ret);
- }
- else
- {
- printk(XENLOG_G_DEBUG
- "memory_map:remove: dom%d gfn=%lx mfn=%lx nr=%lx\n",
- d->domain_id, gfn, mfn, nr_mfns);
-
- ret = unmap_mmio_regions(d, _gfn(gfn), nr_mfns, _mfn(mfn));
- if ( ret < 0 && is_hardware_domain(current->domain) )
- printk(XENLOG_ERR
- "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;
- }
-
case XEN_DOMCTL_settimeoffset:
domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds);
break;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -168,13 +168,13 @@ static XSM_INLINE int cf_check xsm_domct
switch ( cmd )
{
case XEN_DOMCTL_ioport_mapping:
- case XEN_DOMCTL_memory_mapping:
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:
+ case XEN_DOMCTL_memory_mapping:
ASSERT_UNREACHABLE();
return -EILSEQ;
@@ -576,7 +576,7 @@ static XSM_INLINE int cf_check xsm_iomem
static XSM_INLINE int cf_check xsm_iomem_mapping(
XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_DM_PRIV);
return xsm_default_action(action, current->domain, d);
}
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -685,6 +685,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:
+ case XEN_DOMCTL_memory_mapping:
ASSERT_UNREACHABLE();
return -EILSEQ;
@@ -692,7 +693,6 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_scheduler_op:
case XEN_DOMCTL_irq_permission:
case XEN_DOMCTL_iomem_permission:
- case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_set_target:
case XEN_DOMCTL_vm_event_op:

View file

@ -1,97 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_ioport_mapping without acquiring domctl lock
With dedicated locking added, the domctl lock isn't required here anymore.
As the handling is in arch-specific code (x86 only), almost no code is
being moved, but a 2nd (extensible to other sub-ops) invocation of
arch_do_domctl() is being added. Move just the re-purposed dedicated XSM
check as early as possible.
In flask_domctl() don't put #ifdef around the moved case label.
This is part of XSA-492.
Fixes: fda49f9b3fbb ("Add build option to allow more hypercalls from stubdoms")
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/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -663,12 +663,15 @@ long arch_do_domctl(
break;
}
+ ret = xsm_ioport_mapping(XSM_DM_PRIV, d, fmp, fmp + np - 1, add);
+ if ( ret )
+ break;
+
hvm = &d->arch.hvm;
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;
+ if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) )
+ ret = -EPERM;
else if ( add )
{
printk(XENLOG_G_INFO
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -436,6 +436,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
goto domctl_out_unlock_domonly;
}
+ case XEN_DOMCTL_ioport_mapping:
+ ret = arch_do_domctl(op, d, u_domctl);
+ goto domctl_out_unlock_domonly;
+
default:
/* Everything else handled further down. */
break;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -167,13 +167,13 @@ static XSM_INLINE int cf_check xsm_domct
XSM_ASSERT_ACTION(XSM_OTHER);
switch ( cmd )
{
- case XEN_DOMCTL_ioport_mapping:
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:
+ case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_memory_mapping:
ASSERT_UNREACHABLE();
return -EILSEQ;
@@ -772,7 +772,7 @@ static XSM_INLINE int cf_check xsm_iopor
static XSM_INLINE int cf_check xsm_ioport_mapping(
XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_DM_PRIV);
return xsm_default_action(action, current->domain, d);
}
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -685,6 +685,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:
+ case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_memory_mapping:
ASSERT_UNREACHABLE();
return -EILSEQ;
@@ -703,7 +704,6 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks (arch/x86/domctl.c) */
case XEN_DOMCTL_shadow_op:
case XEN_DOMCTL_ioport_permission:
- case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_gsi_permission:
#endif
#ifdef CONFIG_HAS_PASSTHROUGH

View file

@ -1,128 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_{,un}bind_pt_irq without acquiring domctl lock
With dedicated locking added, the domctl lock isn't required here anymore.
(It also already isn't used when pt_irq_{create,destroy}_bind() are
invoked for PVH Dom0.) As the handling is in arch-specific code, no code
is being moved, but the 2nd (extensible to other sub-ops like the ones
here) invocation of arch_do_domctl() is being re-used.
This is part of XSA-492.
Fixes: fda49f9b3fbb ("Add build option to allow more hypercalls from stubdoms")
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>
Acked-by: Julien Grall <julien@xen.org>
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -104,7 +104,7 @@ long arch_do_domctl(struct xen_domctl *d
if ( rc )
return rc;
- rc = xsm_bind_pt_irq(XSM_HOOK, d, bind);
+ rc = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind);
if ( rc )
return rc;
@@ -140,7 +140,7 @@ long arch_do_domctl(struct xen_domctl *d
if ( irq != virq )
return -EINVAL;
- rc = xsm_unbind_pt_irq(XSM_HOOK, d, bind);
+ rc = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind);
if ( rc )
return rc;
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -575,7 +575,7 @@ long arch_do_domctl(
if ( !is_hvm_domain(d) )
break;
- ret = xsm_bind_pt_irq(XSM_HOOK, d, bind);
+ ret = xsm_bind_pt_irq(XSM_DM_PRIV, d, bind);
if ( ret )
break;
@@ -613,7 +613,7 @@ long arch_do_domctl(
if ( !is_hvm_domain(d) )
break;
- ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind);
+ ret = xsm_unbind_pt_irq(XSM_DM_PRIV, d, bind);
if ( ret )
break;
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -437,6 +437,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
}
case XEN_DOMCTL_ioport_mapping:
+ case XEN_DOMCTL_bind_pt_irq:
+ case XEN_DOMCTL_unbind_pt_irq:
ret = arch_do_domctl(op, d, u_domctl);
goto domctl_out_unlock_domonly;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -168,13 +168,11 @@ static XSM_INLINE int cf_check xsm_domct
switch ( cmd )
{
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:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_memory_mapping:
+ case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
return -EILSEQ;
@@ -541,14 +539,14 @@ static XSM_INLINE int cf_check xsm_unmap
static XSM_INLINE int cf_check xsm_bind_pt_irq(
XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_DM_PRIV);
return xsm_default_action(action, current->domain, d);
}
static XSM_INLINE int cf_check xsm_unbind_pt_irq(
XSM_DEFAULT_ARG struct domain *d, struct xen_domctl_bind_pt_irq *bind)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_DM_PRIV);
return xsm_default_action(action, current->domain, d);
}
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -683,10 +683,12 @@ static int cf_check flask_domctl(struct
return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL);
/* These have individual XSM hooks and don't make it here. */
+ case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
case XEN_DOMCTL_get_domain_state:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_memory_mapping:
+ case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
return -EILSEQ;
@@ -697,9 +699,6 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_set_target:
case XEN_DOMCTL_vm_event_op:
- /* These have individual XSM hooks (arch/../domctl.c) */
- case XEN_DOMCTL_bind_pt_irq:
- case XEN_DOMCTL_unbind_pt_irq:
#ifdef CONFIG_X86
/* These have individual XSM hooks (arch/x86/domctl.c) */
case XEN_DOMCTL_shadow_op:

View file

@ -1,172 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_io{mem,port}_permission without acquiring domctl lock
With dedicated locking added, the domctl lock isn't required here anymore.
As the I/O port handling is in arch-specific code (x86 only), no code is
being moved, but the 2nd invocation of arch_do_domctl() is re-used. Move
the re-purposed dedicated XSM checks as early as possible.
This is part of XSA-492.
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/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -233,12 +233,17 @@ long arch_do_domctl(
unsigned int np = domctl->u.ioport_permission.nr_ports;
int allow = domctl->u.ioport_permission.allow_access;
+ ret = -EINVAL;
+ if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS )
+ break;
+
+ ret = xsm_ioport_permission(XSM_PRIV, d, fp, fp + np - 1, allow);
+ if ( ret )
+ break;
+
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) ||
- xsm_ioport_permission(XSM_HOOK, d, fp, fp + np - 1, allow) )
+ if ( !ioports_access_permitted(currd, fp, fp + np - 1) )
ret = -EPERM;
else if ( allow )
ret = ioports_permit_access(d, fp, fp + np - 1);
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -376,6 +376,34 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
copyback = true;
goto domctl_out_unlock_domonly;
+ case XEN_DOMCTL_iomem_permission:
+ {
+ unsigned long mfn = op->u.iomem_permission.first_mfn;
+ unsigned long nr_mfns = op->u.iomem_permission.nr_mfns;
+ bool allow = op->u.iomem_permission.allow_access;
+
+ ret = -EINVAL;
+ if ( (mfn + nr_mfns - 1) < mfn ) /* Wrap? */
+ goto domctl_out_unlock_domonly;
+
+ ret = xsm_iomem_permission(XSM_PRIV, d, mfn, mfn + nr_mfns - 1, allow);
+ if ( ret )
+ goto domctl_out_unlock_domonly;
+
+ iocaps_double_lock(d, true);
+
+ if ( !iomem_access_permitted(current->domain,
+ mfn, mfn + nr_mfns - 1) )
+ ret = -EPERM;
+ else if ( allow )
+ 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);
+ goto domctl_out_unlock_domonly;
+ }
+
case XEN_DOMCTL_memory_mapping:
{
unsigned long gfn = op->u.memory_mapping.first_gfn;
@@ -436,6 +464,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
goto domctl_out_unlock_domonly;
}
+ case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_unbind_pt_irq:
@@ -777,31 +806,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
}
#endif
- case XEN_DOMCTL_iomem_permission:
- {
- unsigned long mfn = op->u.iomem_permission.first_mfn;
- unsigned long nr_mfns = op->u.iomem_permission.nr_mfns;
- int allow = op->u.iomem_permission.allow_access;
-
- ret = -EINVAL;
- 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) )
- ret = -EPERM;
- else if ( allow )
- 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;
- }
-
case XEN_DOMCTL_settimeoffset:
domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds);
break;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -170,7 +170,9 @@ static XSM_INLINE int cf_check xsm_domct
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
case XEN_DOMCTL_get_domain_state:
+ case XEN_DOMCTL_iomem_permission:
case XEN_DOMCTL_ioport_mapping:
+ case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
@@ -567,7 +569,7 @@ static XSM_INLINE int cf_check xsm_irq_p
static XSM_INLINE int cf_check xsm_iomem_permission(
XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, d);
}
@@ -763,7 +765,7 @@ static XSM_INLINE int cf_check xsm_priv_
static XSM_INLINE int cf_check xsm_ioport_permission(
XSM_DEFAULT_ARG struct domain *d, uint32_t s, uint32_t e, uint8_t allow)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, d);
}
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -686,7 +686,9 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
case XEN_DOMCTL_get_domain_state:
+ case XEN_DOMCTL_iomem_permission:
case XEN_DOMCTL_ioport_mapping:
+ case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
@@ -695,14 +697,12 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks (common/domctl.c) */
case XEN_DOMCTL_scheduler_op:
case XEN_DOMCTL_irq_permission:
- case XEN_DOMCTL_iomem_permission:
case XEN_DOMCTL_set_target:
case XEN_DOMCTL_vm_event_op:
#ifdef CONFIG_X86
/* These have individual XSM hooks (arch/x86/domctl.c) */
case XEN_DOMCTL_shadow_op:
- case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_gsi_permission:
#endif
#ifdef CONFIG_HAS_PASSTHROUGH

View file

@ -1,163 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_{irq,gsi}_permission without acquiring domctl lock
With dedicated locking added, the domctl lock isn't required here anymore.
As the GSI handling is in arch-specific code (x86 only), no code is being
moved there; the 2nd invocation of arch_do_domctl() is re-used. Move the
re-purposed (XSM_HOOK -> XSM_PRIV, as xsm_domctl() is now bypassed)
dedicated XSM checks as early as possible.
This is part of XSA-492.
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/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -272,10 +272,13 @@ long arch_do_domctl(
break;
}
+ ret = xsm_irq_permission(XSM_PRIV, d, irq, flags);
+ if ( ret )
+ break;
+
iocaps_double_lock(d, true);
- if ( !irq_access_permitted(currd, irq) ||
- xsm_irq_permission(XSM_HOOK, d, irq, flags) )
+ if ( !irq_access_permitted(currd, irq) )
ret = -EPERM;
else if ( flags )
ret = irq_permit_access(d, irq);
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -464,8 +464,41 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
goto domctl_out_unlock_domonly;
}
+#ifdef CONFIG_HAS_PIRQ
+ case XEN_DOMCTL_irq_permission:
+ {
+ unsigned int pirq = op->u.irq_permission.pirq, irq;
+ bool allow = op->u.irq_permission.allow_access;
+
+ ret = -EINVAL;
+ if ( pirq >= current->domain->nr_pirqs )
+ goto domctl_out_unlock_domonly;
+
+ irq = domain_pirq_to_irq(current->domain, pirq);
+
+ ret = -EPERM;
+ if ( irq )
+ ret = xsm_irq_permission(XSM_PRIV, d, irq, allow);
+ if ( ret )
+ goto domctl_out_unlock_domonly;
+
+ iocaps_double_lock(d, true);
+
+ if ( !irq_access_permitted(current->domain, irq) )
+ ret = -EPERM;
+ else if ( allow )
+ ret = irq_permit_access(d, irq);
+ else
+ ret = irq_deny_access(d, irq);
+
+ iocaps_double_unlock(d, true);
+ goto domctl_out_unlock_domonly;
+ }
+#endif
+
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_ioport_mapping:
+ case XEN_DOMCTL_gsi_permission:
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_unbind_pt_irq:
ret = arch_do_domctl(op, d, u_domctl);
@@ -779,33 +812,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
}
break;
-#ifdef CONFIG_HAS_PIRQ
- case XEN_DOMCTL_irq_permission:
- {
- unsigned int pirq = op->u.irq_permission.pirq, irq;
- int allow = op->u.irq_permission.allow_access;
-
- if ( pirq >= current->domain->nr_pirqs )
- {
- 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;
- else if ( allow )
- ret = irq_permit_access(d, irq);
- else
- ret = irq_deny_access(d, irq);
-
- iocaps_double_unlock(d, true);
- break;
- }
-#endif
-
case XEN_DOMCTL_settimeoffset:
domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds);
break;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -170,9 +170,11 @@ static XSM_INLINE int cf_check xsm_domct
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
case XEN_DOMCTL_get_domain_state:
+ case XEN_DOMCTL_gsi_permission:
case XEN_DOMCTL_iomem_permission:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_ioport_permission:
+ case XEN_DOMCTL_irq_permission:
case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
@@ -562,7 +564,7 @@ static XSM_INLINE int cf_check xsm_unmap
static XSM_INLINE int cf_check xsm_irq_permission(
XSM_DEFAULT_ARG struct domain *d, int pirq, uint8_t allow)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, d);
}
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -686,9 +686,11 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
case XEN_DOMCTL_get_domain_state:
+ case XEN_DOMCTL_gsi_permission:
case XEN_DOMCTL_iomem_permission:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_ioport_permission:
+ case XEN_DOMCTL_irq_permission:
case XEN_DOMCTL_memory_mapping:
case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
@@ -696,14 +698,12 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks (common/domctl.c) */
case XEN_DOMCTL_scheduler_op:
- case XEN_DOMCTL_irq_permission:
case XEN_DOMCTL_set_target:
case XEN_DOMCTL_vm_event_op:
#ifdef CONFIG_X86
/* These have individual XSM hooks (arch/x86/domctl.c) */
case XEN_DOMCTL_shadow_op:
- case XEN_DOMCTL_gsi_permission:
#endif
#ifdef CONFIG_HAS_PASSTHROUGH
/*

View file

@ -1,179 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl/XSM: drop vm_event_control hook
Integrate the checking with xsm_domctl(). Care needs to be taken with the
GET_VERSION sub-op, which may be invoked with DOMID_INVALID, and which has
been (and continues to be) bypassing XSM checking.
Since the latter two parameters were unused, monitor_domctl() invoking the
hook was actually redundant with the earlier xsm_domctl() (as can be seen
nicely from the hunks changing xsm/flask/hooks.c).
As a positive side effect, permissions are then checked at the same early
point with and without Flask.
While folding XEN_DOMCTL_monitor_op and XEN_DOMCTL_vm_event_op in
flask_domctl(), also fold in XEN_DOMCTL_set_access_required.
This is part of XSA-492.
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
@@ -496,6 +496,23 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
}
#endif
+ case XEN_DOMCTL_vm_event_op:
+ if ( op->u.vm_event_op.op == XEN_VM_EVENT_GET_VERSION )
+ {
+ /* No XSM check (and potentially d == NULL) here. */
+ ret = vm_event_domctl(d, &op->u.vm_event_op);
+ if ( !ret )
+ copyback = true;
+ goto domctl_out_unlock_domonly;
+ }
+ if ( !d )
+ {
+ ret = -ESRCH;
+ goto domctl_out_unlock_domonly;
+ }
+ /* Other sub-ops handled further down. */
+ break;
+
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_gsi_permission:
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -30,16 +30,11 @@
int monitor_domctl(struct domain *d, struct xen_domctl_monitor_op *mop)
{
- int rc;
bool requested_status = false;
if ( unlikely(current->domain == d) ) /* no domain_pause() */
return -EPERM;
- rc = xsm_vm_event_control(XSM_PRIV, d, mop->op, mop->event);
- if ( unlikely(rc) )
- return rc;
-
switch ( mop->op )
{
case XEN_DOMCTL_MONITOR_OP_ENABLE:
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -603,11 +603,10 @@ int vm_event_domctl(struct domain *d, st
/* All other subops need to target a real domain. */
if ( unlikely(d == NULL) )
- return -ESRCH;
-
- rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op);
- if ( rc )
- return rc;
+ {
+ ASSERT_UNREACHABLE();
+ return -EILSEQ;
+ }
if ( unlikely(d == current->domain) ) /* no domain_pause() */
{
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -652,13 +652,6 @@ static XSM_INLINE int cf_check xsm_hvm_a
}
}
-static XSM_INLINE int cf_check xsm_vm_event_control(
- XSM_DEFAULT_ARG struct domain *d, int mode, int op)
-{
- XSM_ASSERT_ACTION(XSM_PRIV);
- return xsm_default_action(action, current->domain, d);
-}
-
#ifdef CONFIG_VM_EVENT
static XSM_INLINE int cf_check xsm_mem_access(XSM_DEFAULT_ARG struct domain *d)
{
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -157,8 +157,6 @@ struct xsm_ops {
int (*hvm_altp2mhvm_op)(struct domain *d, uint64_t mode, uint32_t op);
int (*get_vnumainfo)(struct domain *d);
- int (*vm_event_control)(struct domain *d, int mode, int op);
-
#ifdef CONFIG_VM_EVENT
int (*mem_access)(struct domain *d);
#endif
@@ -657,12 +655,6 @@ static inline int xsm_get_vnumainfo(xsm_
return alternative_call(xsm_ops.get_vnumainfo, d);
}
-static inline int xsm_vm_event_control(
- xsm_default_t def, struct domain *d, int mode, int op)
-{
- return alternative_call(xsm_ops.vm_event_control, d, mode, op);
-}
-
#ifdef CONFIG_VM_EVENT
static inline int xsm_mem_access(xsm_default_t def, struct domain *d)
{
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -116,8 +116,6 @@ static const struct xsm_ops __initconst_
.remove_from_physmap = xsm_remove_from_physmap,
.map_gmfn_foreign = xsm_map_gmfn_foreign,
- .vm_event_control = xsm_vm_event_control,
-
#ifdef CONFIG_VM_EVENT
.mem_access = xsm_mem_access,
#endif
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -699,7 +699,6 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks (common/domctl.c) */
case XEN_DOMCTL_scheduler_op:
case XEN_DOMCTL_set_target:
- case XEN_DOMCTL_vm_event_op:
#ifdef CONFIG_X86
/* These have individual XSM hooks (arch/x86/domctl.c) */
@@ -793,9 +792,8 @@ static int cf_check flask_domctl(struct
return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__TRIGGER);
case XEN_DOMCTL_set_access_required:
- return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT);
-
case XEN_DOMCTL_monitor_op:
+ case XEN_DOMCTL_vm_event_op:
return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT);
case XEN_DOMCTL_debug_op:
@@ -1368,11 +1366,6 @@ static int cf_check flask_hvm_altp2mhvm_
return current_has_perm(d, SECCLASS_HVM, HVM__ALTP2MHVM_OP);
}
-static int cf_check flask_vm_event_control(struct domain *d, int mode, int op)
-{
- return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VM_EVENT);
-}
-
#ifdef CONFIG_VM_EVENT
static int cf_check flask_mem_access(struct domain *d)
{
@@ -1971,8 +1964,6 @@ static const struct xsm_ops __initconst_
.do_xsm_op = do_flask_op,
.get_vnumainfo = flask_get_vnumainfo,
- .vm_event_control = flask_vm_event_control,
-
#ifdef CONFIG_VM_EVENT
.mem_access = flask_mem_access,
#endif

View file

@ -1,108 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl/XSM: pass full struct xen_domctl to xsm_domctl()
Subsequently some sub-ops will want to inspect their sub-sub-ops. Plus
this way we don't need to pass SSIDref separately anymore for
domain_create.
This is part of XSA-492.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -735,7 +735,7 @@ long do_paging_domctl_cont(
if ( d == NULL )
return -ESRCH;
- ret = xsm_domctl(XSM_OTHER, d, op.cmd, 0 /* SSIDref not applicable */);
+ ret = xsm_domctl(XSM_OTHER, d, &op);
if ( !ret )
{
if ( domctl_lock_acquire() )
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -526,9 +526,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
break;
}
- ret = xsm_domctl(XSM_OTHER, d, op->cmd,
- /* SSIDRef only applicable for cmd == createdomain */
- op->u.createdomain.ssidref);
+ ret = xsm_domctl(XSM_OTHER, d, op);
if ( ret )
goto domctl_out_unlock_domonly;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -162,10 +162,10 @@ static XSM_INLINE int cf_check xsm_set_t
}
static XSM_INLINE int cf_check xsm_domctl(
- XSM_DEFAULT_ARG struct domain *d, unsigned int cmd, uint32_t ssidref)
+ XSM_DEFAULT_ARG struct domain *d, struct xen_domctl *op)
{
XSM_ASSERT_ACTION(XSM_OTHER);
- switch ( cmd )
+ switch ( op->cmd )
{
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -61,7 +61,7 @@ struct xsm_ops {
int (*sysctl_scheduler_op)(int op);
#endif
int (*set_target)(struct domain *d, struct domain *e);
- int (*domctl)(struct domain *d, unsigned int cmd, uint32_t ssidref);
+ int (*domctl)(struct domain *d, struct xen_domctl *op);
int (*sysctl)(int cmd);
int (*readconsole)(uint32_t clear);
@@ -260,9 +260,9 @@ static inline int xsm_set_target(
}
static inline int xsm_domctl(xsm_default_t def, struct domain *d,
- unsigned int cmd, uint32_t ssidref)
+ struct xen_domctl *op)
{
- return alternative_call(xsm_ops.domctl, d, cmd, ssidref);
+ return alternative_call(xsm_ops.domctl, d, op);
}
static inline int xsm_sysctl(xsm_default_t def, int cmd)
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -667,10 +667,9 @@ static int cf_check flask_set_target(str
return rc;
}
-static int cf_check flask_domctl(struct domain *d, unsigned int cmd,
- uint32_t ssidref)
+static int cf_check flask_domctl(struct domain *d, struct xen_domctl *op)
{
- switch ( cmd )
+ switch ( op->cmd )
{
case XEN_DOMCTL_createdomain:
/*
@@ -680,7 +679,8 @@ static int cf_check flask_domctl(struct
* Note that d is NULL because we haven't even allocated memory for it
* this early in XEN_DOMCTL_createdomain.
*/
- return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL);
+ return avc_current_has_perm(op->u.createdomain.ssidref, SECCLASS_DOMAIN,
+ DOMAIN__CREATE, NULL);
/* These have individual XSM hooks and don't make it here. */
case XEN_DOMCTL_bind_pt_irq:
@@ -855,7 +855,7 @@ static int cf_check flask_domctl(struct
return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__SET_LLC_COLORS);
default:
- return avc_unknown_permission("domctl", cmd);
+ return avc_unknown_permission("domctl", op->cmd);
}
}

View file

@ -1,112 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl/XSM: drop scheduler_op hook
Integrate the checking with xsm_domctl(), now that it has the full op
struct passed. As a positive side effect, permissions are then checked at
the same early point with and without Flask.
This is part of XSA-492.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -2074,10 +2074,6 @@ long sched_adjust(struct domain *d, stru
{
long ret;
- ret = xsm_domctl_scheduler_op(XSM_HOOK, d, op->cmd);
- if ( ret )
- return ret;
-
if ( op->sched_id != dom_scheduler(d)->sched_id )
return -EINVAL;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -141,13 +141,6 @@ static XSM_INLINE int cf_check xsm_getdo
return xsm_default_action(action, current->domain, d);
}
-static XSM_INLINE int cf_check xsm_domctl_scheduler_op(
- XSM_DEFAULT_ARG struct domain *d, int cmd)
-{
- XSM_ASSERT_ACTION(XSM_HOOK);
- return xsm_default_action(action, current->domain, d);
-}
-
static XSM_INLINE int cf_check xsm_sysctl_scheduler_op(XSM_DEFAULT_ARG int cmd)
{
XSM_ASSERT_ACTION(XSM_HOOK);
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -56,7 +56,6 @@ struct xsm_ops {
struct xen_domctl_getdomaininfo *info);
int (*domain_create)(struct domain *d, uint32_t ssidref);
int (*getdomaininfo)(struct domain *d);
- int (*domctl_scheduler_op)(struct domain *d, int op);
#ifdef CONFIG_SYSCTL
int (*sysctl_scheduler_op)(int op);
#endif
@@ -240,12 +239,6 @@ static inline int xsm_get_domain_state(x
return alternative_call(xsm_ops.get_domain_state, d);
}
-static inline int xsm_domctl_scheduler_op(
- xsm_default_t def, struct domain *d, int cmd)
-{
- return alternative_call(xsm_ops.domctl_scheduler_op, d, cmd);
-}
-
#ifdef CONFIG_SYSCTL
static inline int xsm_sysctl_scheduler_op(xsm_default_t def, int cmd)
{
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -18,7 +18,6 @@ static const struct xsm_ops __initconst_
.security_domaininfo = xsm_security_domaininfo,
.domain_create = xsm_domain_create,
.getdomaininfo = xsm_getdomaininfo,
- .domctl_scheduler_op = xsm_domctl_scheduler_op,
#ifdef CONFIG_SYSCTL
.sysctl_scheduler_op = xsm_sysctl_scheduler_op,
#endif
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -609,7 +609,7 @@ static int cf_check flask_getdomaininfo(
return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO);
}
-static int cf_check flask_domctl_scheduler_op(struct domain *d, int op)
+static int flask_domctl_scheduler_op(struct domain *d, int op)
{
switch ( op )
{
@@ -697,7 +697,6 @@ static int cf_check flask_domctl(struct
return -EILSEQ;
/* These have individual XSM hooks (common/domctl.c) */
- case XEN_DOMCTL_scheduler_op:
case XEN_DOMCTL_set_target:
#ifdef CONFIG_X86
@@ -745,6 +744,9 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_setdomainhandle:
return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE);
+ case XEN_DOMCTL_scheduler_op:
+ return flask_domctl_scheduler_op(d, op->u.scheduler_op.cmd);
+
case XEN_DOMCTL_set_ext_vcpucontext:
case XEN_DOMCTL_set_vcpu_msrs:
case XEN_DOMCTL_setvcpucontext:
@@ -1884,7 +1886,6 @@ static const struct xsm_ops __initconst_
.security_domaininfo = flask_security_domaininfo,
.domain_create = flask_domain_create,
.getdomaininfo = flask_getdomaininfo,
- .domctl_scheduler_op = flask_domctl_scheduler_op,
#ifdef CONFIG_SYSCTL
.sysctl_scheduler_op = flask_sysctl_scheduler_op,
#endif

View file

@ -1,124 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl/XSM: drop shadow_control_op hook
Integrate the checking with xsm_domctl(), now that it has the full op
struct passed. As a positive side effect, permissions are then checked at
the same early point with and without Flask.
This is part of XSA-492.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -677,10 +677,6 @@ int paging_domctl(struct domain *d, stru
return -EBUSY;
}
- rc = xsm_shadow_control(XSM_HOOK, d, sc->op);
- if ( rc )
- return rc;
-
/* Code to handle log-dirty. Note that some log dirty operations
* piggy-back on shadow operations. For example, when
* XEN_DOMCTL_SHADOW_OP_OFF is called, it first checks whether log dirty
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -682,13 +682,6 @@ static XSM_INLINE int cf_check xsm_do_mc
return xsm_default_action(action, current->domain, NULL);
}
-static XSM_INLINE int cf_check xsm_shadow_control(
- XSM_DEFAULT_ARG struct domain *d, uint32_t op)
-{
- XSM_ASSERT_ACTION(XSM_HOOK);
- return xsm_default_action(action, current->domain, d);
-}
-
static XSM_INLINE int cf_check xsm_mem_sharing_op(
XSM_DEFAULT_ARG struct domain *d, struct domain *cd, int op)
{
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -172,7 +172,6 @@ struct xsm_ops {
#ifdef CONFIG_X86
int (*do_mca)(void);
- int (*shadow_control)(struct domain *d, uint32_t op);
int (*mem_sharing_op)(struct domain *d, struct domain *cd, int op);
int (*apic)(struct domain *d, int cmd);
int (*machine_memory_map)(void);
@@ -680,12 +679,6 @@ static inline int xsm_do_mca(xsm_default
return alternative_call(xsm_ops.do_mca);
}
-static inline int xsm_shadow_control(
- xsm_default_t def, struct domain *d, uint32_t op)
-{
- return alternative_call(xsm_ops.shadow_control, d, op);
-}
-
static inline int xsm_mem_sharing_op(
xsm_default_t def, struct domain *d, struct domain *cd, int op)
{
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -130,7 +130,6 @@ static const struct xsm_ops __initconst_
.platform_op = xsm_platform_op,
#ifdef CONFIG_X86
.do_mca = xsm_do_mca,
- .shadow_control = xsm_shadow_control,
.mem_sharing_op = xsm_mem_sharing_op,
.apic = xsm_apic,
.machine_memory_map = xsm_machine_memory_map,
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -40,6 +40,7 @@
#ifdef CONFIG_X86
#include <asm/pv/shim.h>
+static int flask_shadow_control(struct domain *d, unsigned int op);
#else
#define pv_shim false
#endif
@@ -699,10 +700,6 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks (common/domctl.c) */
case XEN_DOMCTL_set_target:
-#ifdef CONFIG_X86
- /* These have individual XSM hooks (arch/x86/domctl.c) */
- case XEN_DOMCTL_shadow_op:
-#endif
#ifdef CONFIG_HAS_PASSTHROUGH
/*
* These have individual XSM hooks
@@ -787,6 +784,11 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_get_address_size:
return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__GETADDRSIZE);
+#ifdef CONFIG_X86
+ case XEN_DOMCTL_shadow_op:
+ return flask_shadow_control(d, op->u.shadow_op.op);
+#endif
+
case XEN_DOMCTL_mem_sharing_op:
return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING);
@@ -1603,7 +1605,7 @@ static int cf_check flask_do_mca(void)
return domain_has_xen(current->domain, XEN__MCA_OP);
}
-static int cf_check flask_shadow_control(struct domain *d, uint32_t op)
+static int flask_shadow_control(struct domain *d, unsigned int op)
{
uint32_t perm;
@@ -1999,7 +2001,6 @@ static const struct xsm_ops __initconst_
.platform_op = flask_platform_op,
#ifdef CONFIG_X86
.do_mca = flask_do_mca,
- .shadow_control = flask_shadow_control,
.mem_sharing_op = flask_mem_sharing_op,
.apic = flask_apic,
.machine_memory_map = flask_machine_memory_map,

View file

@ -1,94 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_get_device_group without acquiring domctl lock
iommu_get_device_group() 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.
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
@@ -513,6 +513,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
/* Other sub-ops handled further down. */
break;
+ case XEN_DOMCTL_get_device_group:
+ ret = iommu_do_domctl(op, d, u_domctl);
+ goto domctl_out_unlock_domonly;
+
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_ioport_mapping:
case XEN_DOMCTL_gsi_permission:
@@ -918,7 +922,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
case XEN_DOMCTL_assign_device:
case XEN_DOMCTL_test_assign_device:
case XEN_DOMCTL_deassign_device:
- case XEN_DOMCTL_get_device_group:
ret = iommu_do_domctl(op, d, u_domctl);
break;
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1620,7 +1620,7 @@ static int iommu_get_device_group(
if ( (pdev->seg != seg) || ((b == bus) && (df == devfn)) )
continue;
- if ( xsm_get_device_group(XSM_HOOK, (seg << 16) | (b << 8) | df) )
+ if ( xsm_get_device_group(XSM_PRIV, (seg << 16) | (b << 8) | df) )
continue;
sdev_id = iommu_call(ops, get_device_group_id, seg, b, df);
@@ -1690,7 +1690,7 @@ int iommu_do_pci_domctl(
u32 max_sdevs;
XEN_GUEST_HANDLE_64(uint32) sdevs;
- ret = xsm_get_device_group(XSM_HOOK, domctl->u.get_device_group.machine_sbdf);
+ ret = xsm_get_device_group(XSM_PRIV, domctl->u.get_device_group.machine_sbdf);
if ( ret )
break;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -162,6 +162,7 @@ static XSM_INLINE int cf_check xsm_domct
{
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
+ case XEN_DOMCTL_get_device_group:
case XEN_DOMCTL_get_domain_state:
case XEN_DOMCTL_gsi_permission:
case XEN_DOMCTL_iomem_permission:
@@ -401,7 +402,7 @@ static XSM_INLINE int cf_check xsm_get_v
static XSM_INLINE int cf_check xsm_get_device_group(
XSM_DEFAULT_ARG uint32_t machine_bdf)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, NULL);
}
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -686,6 +686,7 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks and don't make it here. */
case XEN_DOMCTL_bind_pt_irq:
case XEN_DOMCTL_getdomaininfo:
+ case XEN_DOMCTL_get_device_group:
case XEN_DOMCTL_get_domain_state:
case XEN_DOMCTL_gsi_permission:
case XEN_DOMCTL_iomem_permission:
@@ -705,7 +706,6 @@ static int cf_check flask_domctl(struct
* These have individual XSM hooks
* (drivers/passthrough/{pci,device_tree.c)
*/
- case XEN_DOMCTL_get_device_group:
case XEN_DOMCTL_test_assign_device:
case XEN_DOMCTL_assign_device:
case XEN_DOMCTL_deassign_device:

View file

@ -1,378 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl/XSM: drop {,de}assign_{,dt}device hooks
Integrate the checking with xsm_domctl(). As a positive side effect,
permissions are then checked at the same early point with and without
Flask. As the DT device path needs fetching earlier (but must not be
double fetched), cache it in a private field of the public interface
struct.
This is part of XSA-492.
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
@@ -325,6 +325,10 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
case XEN_DOMCTL_deassign_device:
if ( op->domain == DOMID_IO )
{
+#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY
+ if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT )
+ op->u.assign_device.u.dt.dev = NULL;
+#endif
d = dom_io;
break;
}
@@ -332,6 +336,11 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
return -ESRCH;
fallthrough;
case XEN_DOMCTL_test_assign_device:
+#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY
+ if ( op->u.assign_device.dev == XEN_DOMCTL_DEV_DT )
+ op->u.assign_device.u.dt.dev = NULL;
+ fallthrough;
+#endif
case XEN_DOMCTL_vm_event_op:
if ( op->domain == DOMID_INVALID )
{
--- a/xen/drivers/passthrough/device_tree.c
+++ b/xen/drivers/passthrough/device_tree.c
@@ -340,15 +340,15 @@ int iommu_do_dt_domctl(struct xen_domctl
if ( (d && d->is_dying) || domctl->u.assign_device.flags )
break;
- ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
- domctl->u.assign_device.u.dt.size,
- &dev);
- if ( ret )
- break;
-
- ret = xsm_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
- if ( ret )
- break;
+ dev = domctl->u.assign_device.u.dt.dev;
+ if ( !dev )
+ {
+ ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
+ domctl->u.assign_device.u.dt.size,
+ &dev);
+ if ( ret )
+ break;
+ }
if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
{
@@ -396,15 +396,15 @@ int iommu_do_dt_domctl(struct xen_domctl
if ( domctl->u.assign_device.flags )
break;
- ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
- domctl->u.assign_device.u.dt.size,
- &dev);
- if ( ret )
- break;
-
- ret = xsm_deassign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
- if ( ret )
- break;
+ dev = domctl->u.assign_device.u.dt.dev;
+ if ( !dev )
+ {
+ ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
+ domctl->u.assign_device.u.dt.size,
+ &dev);
+ if ( ret )
+ break;
+ }
if ( d == dom_io )
{
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1740,10 +1740,6 @@ int iommu_do_pci_domctl(
machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
- ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf);
- if ( ret )
- break;
-
seg = machine_sbdf >> 16;
bus = PCI_BUS(machine_sbdf);
devfn = PCI_DEVFN(machine_sbdf);
@@ -1785,10 +1781,6 @@ int iommu_do_pci_domctl(
machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
- ret = xsm_deassign_device(XSM_HOOK, d, machine_sbdf);
- if ( ret )
- break;
-
seg = machine_sbdf >> 16;
bus = PCI_BUS(machine_sbdf);
devfn = PCI_DEVFN(machine_sbdf);
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -575,7 +575,10 @@ struct xen_domctl_assign_device {
} pci;
struct {
uint32_t size; /* Length of the path */
- XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */
+ XEN_GUEST_HANDLE_64(char) path; /* Path to the device tree node */
+#ifdef __XEN__
+ struct dt_device_node *dev; /* Resolved device node of the above */
+#endif
} dt;
} u;
};
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -405,40 +405,8 @@ static XSM_INLINE int cf_check xsm_get_d
XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, NULL);
}
-
-static XSM_INLINE int cf_check xsm_assign_device(
- XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf)
-{
- XSM_ASSERT_ACTION(XSM_HOOK);
- return xsm_default_action(action, current->domain, d);
-}
-
-static XSM_INLINE int cf_check xsm_deassign_device(
- XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf)
-{
- XSM_ASSERT_ACTION(XSM_HOOK);
- return xsm_default_action(action, current->domain, d);
-}
-
#endif /* HAS_PASSTHROUGH && HAS_PCI */
-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY)
-static XSM_INLINE int cf_check xsm_assign_dtdevice(
- XSM_DEFAULT_ARG struct domain *d, const char *dtpath)
-{
- XSM_ASSERT_ACTION(XSM_HOOK);
- return xsm_default_action(action, current->domain, d);
-}
-
-static XSM_INLINE int cf_check xsm_deassign_dtdevice(
- XSM_DEFAULT_ARG struct domain *d, const char *dtpath)
-{
- XSM_ASSERT_ACTION(XSM_HOOK);
- return xsm_default_action(action, current->domain, d);
-}
-
-#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE_DISCOVERY */
-
static XSM_INLINE int cf_check xsm_resource_plug_core(XSM_DEFAULT_VOID)
{
XSM_ASSERT_ACTION(XSM_HOOK);
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -124,13 +124,6 @@ struct xsm_ops {
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
int (*get_device_group)(uint32_t machine_bdf);
- int (*assign_device)(struct domain *d, uint32_t machine_bdf);
- int (*deassign_device)(struct domain *d, uint32_t machine_bdf);
-#endif
-
-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY)
- int (*assign_dtdevice)(struct domain *d, const char *dtpath);
- int (*deassign_dtdevice)(struct domain *d, const char *dtpath);
#endif
int (*resource_plug_core)(void);
@@ -533,35 +526,8 @@ static inline int xsm_get_device_group(x
{
return alternative_call(xsm_ops.get_device_group, machine_bdf);
}
-
-static inline int xsm_assign_device(
- xsm_default_t def, struct domain *d, uint32_t machine_bdf)
-{
- return alternative_call(xsm_ops.assign_device, d, machine_bdf);
-}
-
-static inline int xsm_deassign_device(
- xsm_default_t def, struct domain *d, uint32_t machine_bdf)
-{
- return alternative_call(xsm_ops.deassign_device, d, machine_bdf);
-}
#endif /* HAS_PASSTHROUGH && HAS_PCI) */
-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY)
-static inline int xsm_assign_dtdevice(
- xsm_default_t def, struct domain *d, const char *dtpath)
-{
- return alternative_call(xsm_ops.assign_dtdevice, d, dtpath);
-}
-
-static inline int xsm_deassign_dtdevice(
- xsm_default_t def, struct domain *d, const char *dtpath)
-{
- return alternative_call(xsm_ops.deassign_dtdevice, d, dtpath);
-}
-
-#endif /* HAS_PASSTHROUGH && HAS_DEVICE_TREE_DISCOVERY */
-
static inline int xsm_resource_plug_pci(xsm_default_t def, uint32_t machine_bdf)
{
return alternative_call(xsm_ops.resource_plug_pci, machine_bdf);
--- a/xen/xsm/dummy.c
+++ b/xen/xsm/dummy.c
@@ -81,13 +81,6 @@ static const struct xsm_ops __initconst_
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
.get_device_group = xsm_get_device_group,
- .assign_device = xsm_assign_device,
- .deassign_device = xsm_deassign_device,
-#endif
-
-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY)
- .assign_dtdevice = xsm_assign_dtdevice,
- .deassign_dtdevice = xsm_deassign_dtdevice,
#endif
.resource_plug_core = xsm_resource_plug_core,
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -45,6 +45,17 @@ static int flask_shadow_control(struct d
#define pv_shim false
#endif
+#ifdef CONFIG_HAS_PASSTHROUGH
+#ifdef CONFIG_HAS_PCI
+static int flask_assign_device(struct domain *d, unsigned int machine_bdf);
+static int flask_deassign_device(struct domain *d, unsigned int machine_bdf);
+#endif
+#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY
+static int flask_assign_dtdevice(struct domain *d, const char *dtpath);
+static int flask_deassign_dtdevice(struct domain *d, const char *dtpath);
+#endif
+#endif /* CONFIG_HAS_PASSTHROUGH */
+
static uint32_t domain_sid(const struct domain *dom)
{
struct domain_security_struct *dsec = dom->ssid;
@@ -700,16 +711,6 @@ static int cf_check flask_domctl(struct
/* These have individual XSM hooks (common/domctl.c) */
case XEN_DOMCTL_set_target:
-
-#ifdef CONFIG_HAS_PASSTHROUGH
- /*
- * These have individual XSM hooks
- * (drivers/passthrough/{pci,device_tree.c)
- */
- case XEN_DOMCTL_test_assign_device:
- case XEN_DOMCTL_assign_device:
- case XEN_DOMCTL_deassign_device:
-#endif
return 0;
case XEN_DOMCTL_destroydomain:
@@ -789,6 +790,49 @@ static int cf_check flask_domctl(struct
return flask_shadow_control(d, op->u.shadow_op.op);
#endif
+#ifdef CONFIG_HAS_PASSTHROUGH
+
+ case XEN_DOMCTL_test_assign_device:
+ case XEN_DOMCTL_assign_device:
+ case XEN_DOMCTL_deassign_device:
+ switch ( op->u.assign_device.dev )
+ {
+#ifdef CONFIG_HAS_PCI
+ case XEN_DOMCTL_DEV_PCI:
+ return op->cmd != XEN_DOMCTL_deassign_device
+ ? flask_assign_device(
+ d, op->u.assign_device.u.pci.machine_sbdf)
+ : flask_deassign_device(
+ d, op->u.assign_device.u.pci.machine_sbdf);
+#endif
+
+#ifdef CONFIG_HAS_DEVICE_TREE_DISCOVERY
+ case XEN_DOMCTL_DEV_DT:
+ {
+ struct dt_device_node *dev;
+ int ret = dt_find_node_by_gpath(op->u.assign_device.u.dt.path,
+ op->u.assign_device.u.dt.size,
+ &dev);
+
+ if ( ret )
+ return ret;
+
+ op->u.assign_device.u.dt.dev = dev;
+
+ return op->cmd != XEN_DOMCTL_deassign_device
+ ? flask_assign_dtdevice(d, dt_node_full_name(dev))
+ : flask_deassign_dtdevice(d, dt_node_full_name(dev));
+ }
+#endif
+
+ default:
+ /* Unknown type. */
+ break;
+ }
+ return avc_unknown_permission("assign_device", op->cmd);
+
+#endif /* CONFIG_HAS_PASSTHROUGH */
+
case XEN_DOMCTL_mem_sharing_op:
return current_has_perm(d, SECCLASS_HVM, HVM__MEM_SHARING);
@@ -1416,7 +1460,7 @@ static int flask_test_assign_device(uint
return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL);
}
-static int cf_check flask_assign_device(struct domain *d, uint32_t machine_bdf)
+static int flask_assign_device(struct domain *d, uint32_t machine_bdf)
{
uint32_t dsid, rsid;
int rc = -EPERM;
@@ -1446,7 +1490,7 @@ static int cf_check flask_assign_device(
return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
-static int cf_check flask_deassign_device(
+static int flask_deassign_device(
struct domain *d, uint32_t machine_bdf)
{
uint32_t rsid;
@@ -1478,7 +1522,7 @@ static int flask_test_assign_dtdevice(co
NULL);
}
-static int cf_check flask_assign_dtdevice(struct domain *d, const char *dtpath)
+static int flask_assign_dtdevice(struct domain *d, const char *dtpath)
{
uint32_t dsid, rsid;
int rc = -EPERM;
@@ -1508,7 +1552,7 @@ static int cf_check flask_assign_dtdevic
return avc_has_perm(dsid, rsid, SECCLASS_RESOURCE, dperm, &ad);
}
-static int cf_check flask_deassign_dtdevice(
+static int flask_deassign_dtdevice(
struct domain *d, const char *dtpath)
{
uint32_t rsid;
@@ -1989,13 +2033,6 @@ static const struct xsm_ops __initconst_
#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
.get_device_group = flask_get_device_group,
- .assign_device = flask_assign_device,
- .deassign_device = flask_deassign_device,
-#endif
-
-#if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE_DISCOVERY)
- .assign_dtdevice = flask_assign_dtdevice,
- .deassign_dtdevice = flask_deassign_dtdevice,
#endif
.platform_op = flask_platform_op,

View file

@ -1,123 +0,0 @@
From: Jan Beulich <jbeulich@suse.com>
Subject: domctl: handle XEN_DOMCTL_set_target without acquiring domctl lock
The only locking required here is that between checking d->target and
setting it. To avoid the need for an explicit lock, use cmpxchgptr() to
update d->target.
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.
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
@@ -505,6 +505,30 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
}
#endif
+ case XEN_DOMCTL_set_target:
+ {
+ struct domain *e = get_domain_by_id(op->u.set_target.target);
+
+ ret = -ESRCH;
+ if ( !e )
+ goto domctl_out_unlock_domonly;
+
+ if ( d == e )
+ ret = -EINVAL;
+ else if ( !is_hvm_domain(e) )
+ ret = -EOPNOTSUPP;
+ else
+ ret = xsm_set_target(XSM_PRIV, d, e);
+
+ /* Hold reference on @e until we destroy @d. */
+ if ( !ret && cmpxchgptr(&d->target, NULL, e) )
+ ret = -EINVAL;
+
+ if ( ret )
+ put_domain(e);
+ goto domctl_out_unlock_domonly;
+ }
+
case XEN_DOMCTL_vm_event_op:
if ( op->u.vm_event_op.op == XEN_VM_EVENT_GET_VERSION )
{
@@ -844,36 +868,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
domain_set_time_offset(d, op->u.settimeoffset.time_offset_seconds);
break;
- case XEN_DOMCTL_set_target:
- {
- struct domain *e;
-
- ret = -ESRCH;
- e = get_domain_by_id(op->u.set_target.target);
- if ( e == NULL )
- break;
-
- ret = -EINVAL;
- if ( (d == e) || (d->target != NULL) )
- {
- put_domain(e);
- break;
- }
-
- ret = -EOPNOTSUPP;
- if ( is_hvm_domain(e) )
- ret = xsm_set_target(XSM_HOOK, d, e);
- if ( ret )
- {
- put_domain(e);
- break;
- }
-
- /* Hold reference on @e until we destroy @d. */
- d->target = e;
- break;
- }
-
case XEN_DOMCTL_subscribe:
d->suspend_evtchn = op->u.subscribe.port;
break;
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -150,7 +150,7 @@ static XSM_INLINE int cf_check xsm_sysct
static XSM_INLINE int cf_check xsm_set_target(
XSM_DEFAULT_ARG struct domain *d, struct domain *e)
{
- XSM_ASSERT_ACTION(XSM_HOOK);
+ XSM_ASSERT_ACTION(XSM_PRIV);
return xsm_default_action(action, current->domain, NULL);
}
@@ -170,6 +170,7 @@ static XSM_INLINE int cf_check xsm_domct
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_irq_permission:
case XEN_DOMCTL_memory_mapping:
+ case XEN_DOMCTL_set_target:
case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
return -EILSEQ;
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -705,14 +705,11 @@ static int cf_check flask_domctl(struct
case XEN_DOMCTL_ioport_permission:
case XEN_DOMCTL_irq_permission:
case XEN_DOMCTL_memory_mapping:
+ case XEN_DOMCTL_set_target:
case XEN_DOMCTL_unbind_pt_irq:
ASSERT_UNREACHABLE();
return -EILSEQ;
- /* These have individual XSM hooks (common/domctl.c) */
- case XEN_DOMCTL_set_target:
- return 0;
-
case XEN_DOMCTL_destroydomain:
return current_has_perm(d, SECCLASS_DOMAIN, DOMAIN__DESTROY);

View file

@ -1,311 +0,0 @@
From 2e21b5301765de353c06081eee953255bf327176 Mon Sep 17 00:00:00 2001
From: Michal Orzel <michal.orzel@amd.com>
Date: Tue, 14 Apr 2026 10:11:24 +0200
Subject: xen/arm64: flushtlb: Optimize ARM64_WORKAROUND_REPEAT_TLBI
The ARM64_WORKAROUND_REPEAT_TLBI workaround is used to mitigate several
errata where broadcast TLBI;DSB sequences don't provide all the
architecturally required synchronization. The workaround performs more
work than necessary, and can have significant overhead. This patch
optimizes the workaround, as explained below.
1. All relevant errata only affect the ordering and/or completion of
memory accesses which have been translated by an invalidated TLB
entry. The actual invalidation of TLB entries is unaffected.
2. The existing workaround is applied to both broadcast and local TLB
invalidation, whereas for all relevant errata it is only necessary to
apply a workaround for broadcast invalidation.
3. The existing workaround replaces every TLBI with a TLBI;DSB;TLBI
sequence, whereas for all relevant errata it is only necessary to
execute a single additional TLBI;DSB sequence after any number of
TLBIs are completed by a DSB.
For example, for a sequence of batched TLBIs:
TLBI <op1>[, <arg1>]
TLBI <op2>[, <arg2>]
TLBI <op3>[, <arg3>]
DSB ISH
... the existing workaround will expand this to:
TLBI <op1>[, <arg1>]
DSB ISH // additional
TLBI <op1>[, <arg1>] // additional
TLBI <op2>[, <arg2>]
DSB ISH // additional
TLBI <op2>[, <arg2>] // additional
TLBI <op3>[, <arg3>]
DSB ISH // additional
TLBI <op3>[, <arg3>] // additional
DSB ISH
... whereas it is sufficient to have:
TLBI <op1>[, <arg1>]
TLBI <op2>[, <arg2>]
TLBI <op3>[, <arg3>]
DSB ISH
TLBI <opX>[, <argX>] // additional
DSB ISH // additional
Using a single additional TLBI and DSB at the end of the sequence can
have significantly lower overhead as each DSB which completes a TLBI
must synchronize with other PEs in the system, with potential
performance effects both locally and system-wide.
4. The existing workaround repeats each specific TLBI operation, whereas
for all relevant errata it is sufficient for the additional TLBI to
use *any* operation which will be broadcast, regardless of which
translation regime or stage of translation the operation applies to.
For example, for a single TLBI:
TLBI ALLE2IS
DSB ISH
... the existing workaround will expand this to:
TLBI ALLE2IS
DSB ISH
TLBI ALLE2IS // additional
DSB ISH // additional
... whereas it is sufficient to have:
TLBI ALLE2IS
DSB ISH
TLBI VALE1IS, XZR // additional
DSB ISH // additional
As the additional TLBI doesn't have to match a specific earlier TLBI,
the additional TLBI can be implemented in separate code, with no
memory of the earlier TLBIs. The additional TLBI can also use a
cheaper TLBI operation.
5. The existing workaround is applied to both Stage-1 and Stage-2 TLB
invalidation, whereas for all relevant errata it is only necessary to
apply a workaround for Stage-1 invalidation.
Architecturally, TLBI operations which invalidate only Stage-2
information (e.g. IPAS2E1IS) are not required to invalidate TLB
entries which combine information from Stage-1 and Stage-2
translation table entries, and consequently may not complete memory
accesses translated by those combined entries. In these cases,
completion of memory accesses is only guaranteed after subsequent
invalidation of Stage-1 information (e.g. VMALLE1IS).
Rework the workaround logic as follows:
- add TLB_HELPER_LOCAL() to be used for local TLB ops without a
workaround,
- modify TLB_HELPER() workaround to use tlbi vale2is, xzr as a second
TLBI,
- drop TLB_HELPER_VA(). It's used only by __flush_xen_tlb_one_local
which is local and does not need workaround and by
__flush_xen_tlb_one. In the latter case, since it's used in a loop,
we don't need a workaround in the middle. Add __tlb_repeat_sync with
a workaround to be used at the end after DSB and before final ISB,
- TLBI VALE2IS passing XZR is used as an additional TLBI. While there is
an identity mapping there, it's used very rarely. The performance
impact is therefore negligible. If things change in the future, we
can revisit the decision.
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
(cherry picked from commit 7c502d7591519135765b8041cbd1c70e56e5a0b9)
diff --git a/xen/arch/arm/include/asm/arm32/flushtlb.h b/xen/arch/arm/include/asm/arm32/flushtlb.h
index 61c25a318998..5483be08fbbe 100644
--- a/xen/arch/arm/include/asm/arm32/flushtlb.h
+++ b/xen/arch/arm/include/asm/arm32/flushtlb.h
@@ -57,6 +57,9 @@ static inline void __flush_xen_tlb_one(vaddr_t va)
asm volatile(STORE_CP32(0, TLBIMVAHIS) : : "r" (va) : "memory");
}
+/* Only for ARM64_WORKAROUND_REPEAT_TLBI */
+static inline void __tlb_repeat_sync(void) {}
+
#endif /* __ASM_ARM_ARM32_FLUSHTLB_H__ */
/*
* Local variables:
diff --git a/xen/arch/arm/include/asm/arm64/flushtlb.h b/xen/arch/arm/include/asm/arm64/flushtlb.h
index 3b99c11b50d1..1606b26bf28a 100644
--- a/xen/arch/arm/include/asm/arm64/flushtlb.h
+++ b/xen/arch/arm/include/asm/arm64/flushtlb.h
@@ -12,9 +12,14 @@
* ARM64_WORKAROUND_REPEAT_TLBI:
* Modification of the translation table for a virtual address might lead to
* read-after-read ordering violation.
- * The workaround repeats TLBI+DSB ISH operation for all the TLB flush
- * operations. While this is strictly not necessary, we don't want to
- * take any risk.
+ * The workaround repeats TLBI+DSB ISH operation for broadcast TLB flush
+ * operations. The workaround is not needed for local operations.
+ *
+ * It is sufficient for the additional TLBI to use *any* operation which will
+ * be broadcast, regardless of which translation regime or stage of translation
+ * the operation applies to. TLBI VALE2IS is used passing XZR. While there is
+ * an identity mapping there, it's only used during suspend/resume, CPU on/off,
+ * so the impact (performance if any) is negligible.
*
* For Xen page-tables the ISB will discard any instructions fetched
* from the old mappings.
@@ -26,69 +31,90 @@
* Note that for local TLB flush, using non-shareable (nsh) is sufficient
* (see D5-4929 in ARM DDI 0487H.a). Although, the memory barrier in
* for the workaround is left as inner-shareable to match with Linux
- * v6.1-rc8.
+ * v6.19.
*/
-#define TLB_HELPER(name, tlbop, sh) \
+#define TLB_HELPER_LOCAL(name, tlbop) \
static inline void name(void) \
{ \
asm_inline volatile ( \
- "dsb " # sh "st;" \
+ "dsb nshst;" \
"tlbi " # tlbop ";" \
- ALTERNATIVE( \
- "nop; nop;", \
- "dsb ish;" \
- "tlbi " # tlbop ";", \
- ARM64_WORKAROUND_REPEAT_TLBI, \
- CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \
- "dsb " # sh ";" \
+ "dsb nsh;" \
"isb;" \
: : : "memory"); \
}
-/*
- * FLush TLB by VA. This will likely be used in a loop, so the caller
- * is responsible to use the appropriate memory barriers before/after
- * the sequence.
- *
- * See above about the ARM64_WORKAROUND_REPEAT_TLBI sequence.
- */
-#define TLB_HELPER_VA(name, tlbop) \
-static inline void name(vaddr_t va) \
-{ \
- asm_inline volatile ( \
- "tlbi " # tlbop ", %0;" \
- ALTERNATIVE( \
- "nop; nop;", \
- "dsb ish;" \
- "tlbi " # tlbop ", %0;", \
- ARM64_WORKAROUND_REPEAT_TLBI, \
- CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \
- : : "r" (va >> PAGE_SHIFT) : "memory"); \
+#define TLB_HELPER(name, tlbop) \
+static inline void name(void) \
+{ \
+ asm_inline volatile ( \
+ "dsb ishst;" \
+ "tlbi " # tlbop ";" \
+ ALTERNATIVE( \
+ "nop; nop;", \
+ "dsb ish;" \
+ "tlbi vale2is, xzr;", \
+ ARM64_WORKAROUND_REPEAT_TLBI, \
+ CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \
+ "dsb ish;" \
+ "isb;" \
+ : : : "memory"); \
}
/* Flush local TLBs, current VMID only. */
-TLB_HELPER(flush_guest_tlb_local, vmalls12e1, nsh)
+TLB_HELPER_LOCAL(flush_guest_tlb_local, vmalls12e1)
/* Flush innershareable TLBs, current VMID only */
-TLB_HELPER(flush_guest_tlb, vmalls12e1is, ish)
+TLB_HELPER(flush_guest_tlb, vmalls12e1is)
/* Flush local TLBs, all VMIDs, non-hypervisor mode */
-TLB_HELPER(flush_all_guests_tlb_local, alle1, nsh)
+TLB_HELPER_LOCAL(flush_all_guests_tlb_local, alle1)
/* Flush innershareable TLBs, all VMIDs, non-hypervisor mode */
-TLB_HELPER(flush_all_guests_tlb, alle1is, ish)
+TLB_HELPER(flush_all_guests_tlb, alle1is)
/* Flush all hypervisor mappings from the TLB of the local processor. */
-TLB_HELPER(flush_xen_tlb_local, alle2, nsh)
+TLB_HELPER_LOCAL(flush_xen_tlb_local, alle2)
+
+#undef TLB_HELPER_LOCAL
+#undef TLB_HELPER
+
+/*
+ * FLush TLB by VA. This will likely be used in a loop, so the caller
+ * is responsible to use the appropriate memory barriers before/after
+ * the sequence.
+ */
/* Flush TLB of local processor for address va. */
-TLB_HELPER_VA(__flush_xen_tlb_one_local, vae2)
+static inline void __flush_xen_tlb_one_local(vaddr_t va)
+{
+ asm_inline volatile (
+ "tlbi vae2, %0" : : "r" (va >> PAGE_SHIFT) : "memory");
+}
/* Flush TLB of all processors in the inner-shareable domain for address va. */
-TLB_HELPER_VA(__flush_xen_tlb_one, vae2is)
+static inline void __flush_xen_tlb_one(vaddr_t va)
+{
+ asm_inline volatile (
+ "tlbi vae2is, %0" : : "r" (va >> PAGE_SHIFT) : "memory");
+}
-#undef TLB_HELPER
-#undef TLB_HELPER_VA
+/*
+ * ARM64_WORKAROUND_REPEAT_TLBI:
+ * For all relevant erratas it is only necessary to execute a single
+ * additional TLBI;DSB sequence after any number of TLBIs are completed by DSB.
+ */
+static inline void __tlb_repeat_sync(void)
+{
+ asm_inline volatile (
+ ALTERNATIVE(
+ "nop; nop;",
+ "tlbi vale2is, xzr;"
+ "dsb ish;",
+ ARM64_WORKAROUND_REPEAT_TLBI,
+ CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)
+ : : : "memory");
+}
#endif /* __ASM_ARM_ARM64_FLUSHTLB_H__ */
/*
diff --git a/xen/arch/arm/include/asm/flushtlb.h b/xen/arch/arm/include/asm/flushtlb.h
index e45fb6d97b02..c292c3c00d29 100644
--- a/xen/arch/arm/include/asm/flushtlb.h
+++ b/xen/arch/arm/include/asm/flushtlb.h
@@ -65,6 +65,7 @@ static inline void flush_xen_tlb_range_va(vaddr_t va,
va += PAGE_SIZE;
}
dsb(ish); /* Ensure the TLB invalidation has completed */
+ __tlb_repeat_sync();
isb();
}
diff --git a/xen/arch/arm/include/asm/mmu/layout.h b/xen/arch/arm/include/asm/mmu/layout.h
index 19c0ec63a59a..feafc14ebfda 100644
--- a/xen/arch/arm/include/asm/mmu/layout.h
+++ b/xen/arch/arm/include/asm/mmu/layout.h
@@ -23,6 +23,10 @@
*
* Reserved to identity map Xen
*
+ * Note: As part of ARM64_WORKAROUND_REPEAT_TLBI, VA 0 is used for an extra
+ * TLBI operation given its rare use (only identity mapping) and thus
+ * negligible performance impact.
+ *
* 0x00000a0000000000 - 0x00000a7fffffffff (512GB, L0 slot [20])
* (Relative offsets)
* 0 - 2M Unmapped

View file

@ -1,71 +0,0 @@
From 7e70b87512c966248b1e8453d9ac54c643c06f44 Mon Sep 17 00:00:00 2001
From: Michal Orzel <michal.orzel@amd.com>
Date: Fri, 22 May 2026 09:35:55 +0200
Subject: xen/arm: Sync missing definitions for Arm CPUs with Linux
Synchronize with Linux kernel 7.0 definitions for the following CPUs:
- Cortex-A76AE,
- Cortex-A78AE,
- Cortex-X1C,
- Cortex-X3,
- Neoverse-V2,
- Cortex-X4,
- Neoverse-V3AE,
- Neoverse-V3,
- Cortex-X925.
These will be used for errata detection in subsequent patches.
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Julien Grall <julien@xen.org>
diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h
index ec23fd098b63..907778683b08 100644
--- a/xen/arch/arm/include/asm/processor.h
+++ b/xen/arch/arm/include/asm/processor.h
@@ -89,13 +89,22 @@
#define ARM_CPU_PART_CORTEX_A76 0xD0B
#define ARM_CPU_PART_NEOVERSE_N1 0xD0C
#define ARM_CPU_PART_CORTEX_A77 0xD0D
+#define ARM_CPU_PART_CORTEX_A76AE 0xD0E
#define ARM_CPU_PART_NEOVERSE_V1 0xD40
#define ARM_CPU_PART_CORTEX_A78 0xD41
+#define ARM_CPU_PART_CORTEX_A78AE 0xD42
#define ARM_CPU_PART_CORTEX_X1 0xD44
#define ARM_CPU_PART_CORTEX_A710 0xD47
#define ARM_CPU_PART_CORTEX_X2 0xD48
#define ARM_CPU_PART_NEOVERSE_N2 0xD49
#define ARM_CPU_PART_CORTEX_A78C 0xD4B
+#define ARM_CPU_PART_CORTEX_X1C 0xD4C
+#define ARM_CPU_PART_CORTEX_X3 0xD4E
+#define ARM_CPU_PART_NEOVERSE_V2 0xD4F
+#define ARM_CPU_PART_CORTEX_X4 0xD82
+#define ARM_CPU_PART_NEOVERSE_V3AE 0xD83
+#define ARM_CPU_PART_NEOVERSE_V3 0xD84
+#define ARM_CPU_PART_CORTEX_X925 0xD85
#define MIDR_CORTEX_A12 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A12)
#define MIDR_CORTEX_A17 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A17)
@@ -110,13 +119,22 @@
#define MIDR_CORTEX_A76 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
#define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
#define MIDR_CORTEX_A77 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
+#define MIDR_CORTEX_A76AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76AE)
#define MIDR_NEOVERSE_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
#define MIDR_CORTEX_A78 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
+#define MIDR_CORTEX_A78AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78AE)
#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
#define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
+#define MIDR_CORTEX_X1C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1C)
+#define MIDR_CORTEX_X3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X3)
+#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2)
+#define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4)
+#define MIDR_NEOVERSE_V3AE MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3AE)
+#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
+#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
/* MPIDR Multiprocessor Affinity Register */
#define _MPIDR_UP (30)

Some files were not shown because too many files have changed in this diff Show more