Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5813d5853a | ||
|
|
8b84ab579c | ||
|
|
a65ac23041 | ||
|
|
046e9e564a | ||
|
|
5b38fd1c96 | ||
|
|
8f43f4c45b | ||
|
|
4a3496d719 | ||
|
|
01f64a0113 | ||
|
|
85b6cafcb8 | ||
|
|
0b14ad1009 | ||
|
|
06e1d41034 | ||
|
|
158b3ce973 |
103 changed files with 5391 additions and 5148 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -6,5 +6,4 @@ lwip-1.3.0.tar.gz
|
|||
pciutils-2.2.9.tar.bz2
|
||||
zlib-1.2.3.tar.gz
|
||||
polarssl-1.1.4-gpl.tgz
|
||||
/mini-os-4.21.0.tar.xz
|
||||
/xen-4.21.1.tar.xz
|
||||
/xen-4.16.5.tar.gz
|
||||
|
|
|
|||
11
CVE-2014-0150.patch
Normal file
11
CVE-2014-0150.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- xen-4.4.1/tools/qemu-xen-traditional/hw/virtio-net.c.orig 2014-07-02 15:54:37.000000000 +0100
|
||||
+++ xen-4.4.1/tools/qemu-xen-traditional/hw/virtio-net.c 2014-11-18 20:50:13.593122915 +0000
|
||||
@@ -192,7 +192,7 @@
|
||||
return VIRTIO_NET_ERR;
|
||||
|
||||
if (mac_data.entries) {
|
||||
- if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
+ if (n->mac_table.in_use <= MAC_TABLE_ENTRIES - mac_data.entries) {
|
||||
memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
|
||||
elem->out_sg[2].iov_base + sizeof(mac_data),
|
||||
mac_data.entries * ETH_ALEN);
|
||||
11
qemu.trad.CVE-2015-5278.patch
Normal file
11
qemu.trad.CVE-2015-5278.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c.orig 2015-09-26 17:27:49.494334726 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c 2015-09-26 17:31:53.107474932 +0100
|
||||
@@ -331,7 +331,7 @@
|
||||
if (index <= s->stop)
|
||||
avail = s->stop - index;
|
||||
else
|
||||
- avail = 0;
|
||||
+ break;
|
||||
len = size;
|
||||
if (len > avail)
|
||||
len = avail;
|
||||
48
qemu.trad.CVE-2015-5279.patch
Normal file
48
qemu.trad.CVE-2015-5279.patch
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/ne2000.c 2015-09-26 17:27:49.494334726 +0100
|
||||
@@ -304,6 +304,9 @@
|
||||
}
|
||||
|
||||
index = s->curpag << 8;
|
||||
+ if (index >= NE2000_PMEM_END) {
|
||||
+ index = s->start;
|
||||
+ }
|
||||
/* 4 bytes for header */
|
||||
total_len = size + 4;
|
||||
/* address for next packet (4 bytes for CRC) */
|
||||
@@ -387,15 +390,21 @@
|
||||
offset = addr | (page << 4);
|
||||
switch(offset) {
|
||||
case EN0_STARTPG:
|
||||
- s->start = val << 8;
|
||||
+ if (val << 8 <= NE2000_PMEM_END) {
|
||||
+ s->start = val << 8;
|
||||
+ }
|
||||
s->tainted = 1;
|
||||
break;
|
||||
case EN0_STOPPG:
|
||||
- s->stop = val << 8;
|
||||
+ if (val << 8 <= NE2000_PMEM_END) {
|
||||
+ s->stop = val << 8;
|
||||
+ }
|
||||
s->tainted = 1;
|
||||
break;
|
||||
case EN0_BOUNDARY:
|
||||
- s->boundary = val;
|
||||
+ if (val << 8 < NE2000_PMEM_END) {
|
||||
+ s->boundary = val;
|
||||
+ }
|
||||
break;
|
||||
case EN0_IMR:
|
||||
s->imr = val;
|
||||
@@ -436,7 +445,9 @@
|
||||
s->phys[offset - EN1_PHYS] = val;
|
||||
break;
|
||||
case EN1_CURPAG:
|
||||
- s->curpag = val;
|
||||
+ if (val << 8 < NE2000_PMEM_END) {
|
||||
+ s->curpag = val;
|
||||
+ }
|
||||
s->tainted = 1;
|
||||
break;
|
||||
case EN1_MULT ... EN1_MULT + 7:
|
||||
12
qemu.trad.CVE-2015-6815.patch
Normal file
12
qemu.trad.CVE-2015-6815.patch
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/e1000.c.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/e1000.c 2015-09-26 17:16:36.406544380 +0100
|
||||
@@ -461,7 +461,8 @@
|
||||
memmove(tp->data, tp->header, hdr);
|
||||
tp->size = hdr;
|
||||
}
|
||||
- } while (split_size -= bytes);
|
||||
+ split_size -= bytes;
|
||||
+ } while (bytes && split_size);
|
||||
} else if (!tp->tse && tp->cptse) {
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentaion Error\n");
|
||||
63
qemu.trad.CVE-2015-7295.patch
Normal file
63
qemu.trad.CVE-2015-7295.patch
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.c.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.c 2015-10-10 16:57:01.806370020 +0100
|
||||
@@ -268,8 +268,8 @@
|
||||
return vring_avail_idx(vq) == vq->last_avail_idx;
|
||||
}
|
||||
|
||||
-void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
- unsigned int len, unsigned int idx)
|
||||
+static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len)
|
||||
{
|
||||
unsigned int offset;
|
||||
int i;
|
||||
@@ -302,7 +302,19 @@
|
||||
|
||||
offset += size;
|
||||
}
|
||||
+}
|
||||
|
||||
+void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len)
|
||||
+{
|
||||
+ vq->last_avail_idx--;
|
||||
+ virtqueue_unmap_sg(vq, elem, len);
|
||||
+}
|
||||
+
|
||||
+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len, unsigned int idx)
|
||||
+{
|
||||
+ virtqueue_unmap_sg(vq, elem, len);
|
||||
idx = (idx + vring_used_idx(vq)) % vq->vring.num;
|
||||
|
||||
/* Get a pointer to the next entry in the used ring. */
|
||||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.h.orig 2015-06-09 16:32:24.000000000 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio.h 2015-10-10 16:57:53.146216039 +0100
|
||||
@@ -105,6 +105,8 @@
|
||||
void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len);
|
||||
void virtqueue_flush(VirtQueue *vq, unsigned int count);
|
||||
+void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
+ unsigned int len);
|
||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
--- xen-4.5.1/tools/qemu-xen-traditional/hw/virtio-net.c.orig 2015-10-10 16:10:05.071786348 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/hw/virtio-net.c 2015-10-10 19:05:34.510029916 +0100
|
||||
@@ -424,11 +424,15 @@
|
||||
len = iov_fill(sg, elem.in_num,
|
||||
buf + offset, size - offset);
|
||||
total += len;
|
||||
+ offset += len;
|
||||
+ if (!n->mergeable_rx_bufs && offset < size) {
|
||||
+ virtqueue_discard(n->rx_vq, &elem, total);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
/* signal other side */
|
||||
virtqueue_fill(n->rx_vq, &elem, total, i++);
|
||||
|
||||
- offset += len;
|
||||
}
|
||||
|
||||
if (mhdr)
|
||||
37
qemu.trad.CVE-2015-7512.patch
Normal file
37
qemu.trad.CVE-2015-7512.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
From 8b98a2f07175d46c3f7217639bd5e03f2ec56343 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Wang <jasowang@redhat.com>
|
||||
Date: Mon, 30 Nov 2015 15:00:06 +0800
|
||||
Subject: [PATCH] pcnet: fix rx buffer overflow(CVE-2015-7512)
|
||||
|
||||
Backends could provide a packet whose length is greater than buffer
|
||||
size. Check for this and truncate the packet to avoid rx buffer
|
||||
overflow in this case.
|
||||
|
||||
Cc: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Cc: qemu-stable@nongnu.org
|
||||
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/pcnet.c | 6 ++++++
|
||||
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/pcnet.c b/tools/qemu-xen-traditional/hw/pcnet.c
|
||||
index 309c40b..1f4a3db 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/pcnet.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/pcnet.c
|
||||
@@ -1064,6 +1064,12 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
int pktcount = 0;
|
||||
|
||||
if (!s->looptest) {
|
||||
+ if (size > 4092) {
|
||||
+#ifdef PCNET_DEBUG_RMD
|
||||
+ fprintf(stderr, "pcnet: truncates rx packet.\n");
|
||||
+#endif
|
||||
+ size = 4092;
|
||||
+ }
|
||||
memcpy(src, buf, size);
|
||||
/* no need to compute the CRC */
|
||||
src[size] = 0;
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
38
qemu.trad.CVE-2015-8345.patch
Normal file
38
qemu.trad.CVE-2015-8345.patch
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
From 00837731d254908a841d69298a4f9f077babaf24 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Weil <sw@weilnetz.de>
|
||||
Date: Fri, 20 Nov 2015 08:42:33 +0100
|
||||
Subject: [PATCH] eepro100: Prevent two endless loops
|
||||
|
||||
http://lists.nongnu.org/archive/html/qemu-devel/2015-11/msg04592.html
|
||||
shows an example how an endless loop in function action_command can
|
||||
be achieved.
|
||||
|
||||
During my code review, I noticed a 2nd case which can result in an
|
||||
endless loop.
|
||||
|
||||
Reported-by: Qinghao Tang <luodalongde@gmail.com>
|
||||
Signed-off-by: Stefan Weil <sw@weilnetz.de>
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/eepro100.c | 16 ++++++++++++++++
|
||||
1 files changed, 16 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/eepro100.c b/tools/qemu-xen-traditional/hw/eepro100.c
|
||||
index 60333b7..685a478 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/eepro100.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/eepro100.c
|
||||
@@ -774,6 +774,11 @@ static void tx_command(EEPRO100State *s)
|
||||
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
||||
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
||||
//~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
||||
+ if (tx_buffer_size == 0) {
|
||||
+ /* Prevent an endless loop. */
|
||||
+ logout("loop in %s:%u\n", __FILE__, __LINE__);
|
||||
+ break;
|
||||
+ }
|
||||
tbd_address += 8;
|
||||
logout
|
||||
("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
44
qemu.trad.CVE-2015-8504.patch
Normal file
44
qemu.trad.CVE-2015-8504.patch
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
From 4c65fed8bdf96780735dbdb92a8bd0d6b6526cc3 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 3 Dec 2015 18:54:17 +0530
|
||||
Subject: [PATCH] ui: vnc: avoid floating point exception
|
||||
|
||||
While sending 'SetPixelFormat' messages to a VNC server,
|
||||
the client could set the 'red-max', 'green-max' and 'blue-max'
|
||||
values to be zero. This leads to a floating point exception in
|
||||
write_png_palette while doing frame buffer updates.
|
||||
|
||||
Reported-by: Lian Yihan <lianyihan@360.cn>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
---
|
||||
tools/qemu-xen-traditional/vnc.c | 6 +++---
|
||||
1 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/vnc.c b/tools/qemu-xen-traditional/vnc.c
|
||||
index 7538405..cbe4d33 100644
|
||||
--- a/tools/qemu-xen-traditional/vnc.c
|
||||
+++ b/tools/qemu-xen-traditional/vnc.c
|
||||
@@ -2198,15 +2198,15 @@ static void set_pixel_format(VncState *vs,
|
||||
}
|
||||
|
||||
vs->clientds = vs->serverds;
|
||||
- vs->clientds.pf.rmax = red_max;
|
||||
+ vs->clientds.pf.rmax = red_max ? red_max : 0xFF;
|
||||
count_bits(vs->clientds.pf.rbits, red_max);
|
||||
vs->clientds.pf.rshift = red_shift;
|
||||
vs->clientds.pf.rmask = red_max << red_shift;
|
||||
- vs->clientds.pf.gmax = green_max;
|
||||
+ vs->clientds.pf.gmax = green_max ? green_max : 0xFF;
|
||||
count_bits(vs->clientds.pf.gbits, green_max);
|
||||
vs->clientds.pf.gshift = green_shift;
|
||||
vs->clientds.pf.gmask = green_max << green_shift;
|
||||
- vs->clientds.pf.bmax = blue_max;
|
||||
+ vs->clientds.pf.bmax = blue_max ? blue_max : 0xFF;
|
||||
count_bits(vs->clientds.pf.bbits, blue_max);
|
||||
vs->clientds.pf.bshift = blue_shift;
|
||||
vs->clientds.pf.bmask = blue_max << blue_shift;
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
30
qemu.trad.CVE-2016-1714.patch
Normal file
30
qemu.trad.CVE-2016-1714.patch
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
--- xen-4.6.1/tools/qemu-xen-traditional/hw/fw_cfg.c.orig 2016-01-04 15:35:42.000000000 +0000
|
||||
+++ xen-4.6.1/tools/qemu-xen-traditional/hw/fw_cfg.c 2016-03-06 16:42:33.464296362 +0000
|
||||
@@ -54,11 +54,15 @@
|
||||
static void fw_cfg_write(FWCfgState *s, uint8_t value)
|
||||
{
|
||||
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
||||
- FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
+ FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
|
||||
+ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
|
||||
FW_CFG_DPRINTF("write %d\n", value);
|
||||
|
||||
- if (s->cur_entry & FW_CFG_WRITE_CHANNEL && s->cur_offset < e->len) {
|
||||
+ if (s->cur_entry & FW_CFG_WRITE_CHANNEL
|
||||
+ && e != NULL
|
||||
+ && e->callback
|
||||
+ && s->cur_offset < e->len) {
|
||||
e->data[s->cur_offset++] = value;
|
||||
if (s->cur_offset == e->len) {
|
||||
e->callback(e->callback_opaque, e->data);
|
||||
@@ -88,7 +92,8 @@
|
||||
static uint8_t fw_cfg_read(FWCfgState *s)
|
||||
{
|
||||
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
|
||||
- FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
+ FWCfgEntry *e = (s->cur_entry == FW_CFG_INVALID) ? NULL :
|
||||
+ &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
|
||||
uint8_t ret;
|
||||
|
||||
if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
|
||||
104
qemu.trad.CVE-2016-1981.patch
Normal file
104
qemu.trad.CVE-2016-1981.patch
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: Laszlo Ersek
|
||||
*Subject*: [Qemu-devel] [PATCH] e1000: eliminate infinite loops on
|
||||
out-of-bounds transfer start
|
||||
*Date*: Tue, 19 Jan 2016 14:17:20 +0100
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
The start_xmit() and e1000_receive_iov() functions implement DMA transfers
|
||||
iterating over a set of descriptors that the guest's e1000 driver
|
||||
prepares:
|
||||
|
||||
- the TDLEN and RDLEN registers store the total size of the descriptor
|
||||
area,
|
||||
|
||||
- while the TDH and RDH registers store the offset (in whole tx / rx
|
||||
descriptors) into the area where the transfer is supposed to start.
|
||||
|
||||
Each time a descriptor is processed, the TDH and RDH register is bumped
|
||||
(as appropriate for the transfer direction).
|
||||
|
||||
QEMU already contains logic to deal with bogus transfers submitted by the
|
||||
guest:
|
||||
|
||||
- Normally, the transmit case wants to increase TDH from its initial value
|
||||
to TDT. (TDT is allowed to be numerically smaller than the initial TDH
|
||||
value; wrapping at or above TDLEN bytes to zero is normal.) The failsafe
|
||||
that QEMU currently has here is a check against reaching the original
|
||||
TDH value again -- a complete wraparound, which should never happen.
|
||||
|
||||
- In the receive case RDH is increased from its initial value until
|
||||
"total_size" bytes have been received; preferably in a single step, or
|
||||
in "s->rxbuf_size" byte steps, if the latter is smaller. However, null
|
||||
RX descriptors are skipped without receiving data, while RDH is
|
||||
incremented just the same. QEMU tries to prevent an infinite loop
|
||||
(processing only null RX descriptors) by detecting whether RDH assumes
|
||||
its original value during the loop. (Again, wrapping from RDLEN to 0 is
|
||||
normal.)
|
||||
|
||||
What both directions miss is that the guest could program TDLEN and RDLEN
|
||||
so low, and the initial TDH and RDH so high, that these registers will
|
||||
immediately be truncated to zero, and then never reassume their initial
|
||||
values in the loop -- a full wraparound will never occur.
|
||||
|
||||
The condition that expresses this is:
|
||||
|
||||
xdh_start >= s->mac_reg[XDLEN] / sizeof(desc)
|
||||
|
||||
i.e., TDH or RDH start out after the last whole rx or tx descriptor that
|
||||
fits into the TDLEN or RDLEN sized area.
|
||||
|
||||
This condition could be checked before we enter the loops, but
|
||||
pci_dma_read() / pci_dma_write() knows how to fill in buffers safely for
|
||||
bogus DMA addresses, so we just extend the existing failsafes with the
|
||||
above condition.
|
||||
|
||||
Cc: "Michael S. Tsirkin" <address@hidden>
|
||||
Cc: Petr Matousek <address@hidden>
|
||||
Cc: Stefano Stabellini <address@hidden>
|
||||
Cc: Prasad Pandit <address@hidden>
|
||||
Cc: Michael Roth <address@hidden>
|
||||
Cc: Jason Wang <address@hidden>
|
||||
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044
|
||||
Signed-off-by: Laszlo Ersek <address@hidden>
|
||||
Reviewed-by: Jason Wang <address@hidden>
|
||||
---
|
||||
|
||||
Notes:
|
||||
Regarding the public posting: we made an honest effort to vet this
|
||||
vulnerability, and the impact seems low -- no host side reads/writes,
|
||||
"just" a DoS (infinite loop). We decided the patch could be posted
|
||||
publicly, for the usual review process. Jason and Prasad checked the
|
||||
patch in the internal discussion already, but comments, improvements
|
||||
etc. are clearly welcome. The CVE request is underway. Thanks.
|
||||
|
||||
hw/net/e1000.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
|
||||
index bec06e9..34d0823 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/e1000.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/e1000.c
|
||||
@@ -908,7 +908,8 @@ start_xmit(E1000State *s)
|
||||
* bogus values to TDT/TDLEN.
|
||||
* there's nothing too intelligent we could do about this.
|
||||
*/
|
||||
- if (s->mac_reg[TDH] == tdh_start) {
|
||||
+ if (s->mac_reg[TDH] == tdh_start ||
|
||||
+ tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
|
||||
DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
|
||||
tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
|
||||
break;
|
||||
@@ -1165,7 +1166,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
s->mac_reg[RDH] = 0;
|
||||
s->check_rxov = 1;
|
||||
/* see comment in start_xmit; same here */
|
||||
- if (s->mac_reg[RDH] == rdh_start) {
|
||||
+ if (s->mac_reg[RDH] == rdh_start ||
|
||||
+ rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
|
||||
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
|
||||
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
|
||||
set_ics(s, 0, E1000_ICS_RXO);
|
||||
--
|
||||
1.8.3.1
|
||||
56
qemu.trad.CVE-2016-2538.patch
Normal file
56
qemu.trad.CVE-2016-2538.patch
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
When processing remote NDIS control message packets,
|
||||
the USB Net device emulator uses a fixed length(4096) data buffer.
|
||||
The incoming informationBufferOffset & Length combination could
|
||||
overflow and cross that range. Check control message buffer
|
||||
offsets and length to avoid it.
|
||||
|
||||
Reported-by: Qinghao Tang <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/usb/dev-network.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
Update as per review
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg03475.html
|
||||
|
||||
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
|
||||
index 8a4ff49..180adce 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/usb-net.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/usb-net.c
|
||||
@@ -915,8 +915,9 @@ static int rndis_query_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
- if (bufoffs + buflen > length)
|
||||
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
+ }
|
||||
|
||||
infobuflen = ndis_query(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen, infobuf,
|
||||
@@ -961,8 +962,9 @@ static int rndis_set_response(USBNetState *s,
|
||||
|
||||
bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8;
|
||||
buflen = le32_to_cpu(buf->InformationBufferLength);
|
||||
- if (bufoffs + buflen > length)
|
||||
+ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) {
|
||||
return USB_RET_STALL;
|
||||
+ }
|
||||
|
||||
ret = ndis_set(s, le32_to_cpu(buf->OID),
|
||||
bufoffs + (uint8_t *) buf, buflen);
|
||||
@@ -1212,8 +1214,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p)
|
||||
if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) {
|
||||
uint32_t offs = 8 + le32_to_cpu(msg->DataOffset);
|
||||
uint32_t size = le32_to_cpu(msg->DataLength);
|
||||
- if (offs + size <= len)
|
||||
+ if (offs < len && size < len && offs + size <= len) {
|
||||
qemu_send_packet(s->vc, s->out_buf + offs, size);
|
||||
+ }
|
||||
}
|
||||
s->out_ptr -= len;
|
||||
memmove(s->out_buf, &s->out_buf[len], s->out_ptr);
|
||||
--
|
||||
2.5.0
|
||||
34
qemu.trad.CVE-2016-2841.patch
Normal file
34
qemu.trad.CVE-2016-2841.patch
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152)
|
||||
bytes to process network packets. Registers PSTART & PSTOP
|
||||
define ring buffer size & location. Setting these registers
|
||||
to invalid values could lead to infinite loop or OOB r/w
|
||||
access issues. Add check to avoid it.
|
||||
|
||||
Reported-by: Yang Hongke <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/net/ne2000.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
Update per review:
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg05522.html
|
||||
|
||||
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
|
||||
index b032212..ced4666 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/ne2000.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/ne2000.c
|
||||
@@ -154,6 +154,10 @@ static int ne2000_buffer_full(NE2000State *s)
|
||||
{
|
||||
int avail, index, boundary;
|
||||
|
||||
+ if (s->stop <= s->start) {
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
index = s->curpag << 8;
|
||||
boundary = s->boundary << 8;
|
||||
if (index < boundary)
|
||||
--
|
||||
2.5.0
|
||||
45
qemu.trad.CVE-2016-2857.patch
Normal file
45
qemu.trad.CVE-2016-2857.patch
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
While computing IP checksum, 'net_checksum_calculate' reads
|
||||
payload length from the packet. It could exceed the given 'data'
|
||||
buffer size. Add a check to avoid it.
|
||||
|
||||
Reported-by: Liu Ling <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
net/checksum.c | 10 ++++++++--
|
||||
1 file changed, 8 insertions(+), 2 deletions(-)
|
||||
|
||||
Update as per review:
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg06121.html
|
||||
|
||||
diff --git a/net/checksum.c b/net/checksum.c
|
||||
index 14c0855..0942437 100644
|
||||
--- a/tools/qemu-xen-traditional/net-checksum.c
|
||||
+++ b/tools/qemu-xen-traditional/net-checksum.c
|
||||
@@ -59,6 +59,11 @@ void net_checksum_calculate(uint8_t *data, int length)
|
||||
int hlen, plen, proto, csum_offset;
|
||||
uint16_t csum;
|
||||
|
||||
+ /* Ensure data has complete L2 & L3 headers. */
|
||||
+ if (length < 14 + 20) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if ((data[14] & 0xf0) != 0x40)
|
||||
return; /* not IPv4 */
|
||||
hlen = (data[14] & 0x0f) * 4;
|
||||
@@ -76,8 +81,9 @@ void net_checksum_calculate(uint8_t *data, int length)
|
||||
return;
|
||||
}
|
||||
|
||||
- if (plen < csum_offset+2)
|
||||
- return;
|
||||
+ if (plen < csum_offset + 2 || 14 + hlen + plen > length) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
data[14+hlen+csum_offset] = 0;
|
||||
data[14+hlen+csum_offset+1] = 0;
|
||||
--
|
||||
2.5.0
|
||||
46
qemu.trad.CVE-2016-4001.patch
Normal file
46
qemu.trad.CVE-2016-4001.patch
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
From 3a15cc0e1ee7168db0782133d2607a6bfa422d66 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Fri, 8 Apr 2016 11:33:48 +0530
|
||||
Subject: [PATCH] net: stellaris_enet: check packet length against receive buffer
|
||||
|
||||
When receiving packets over Stellaris ethernet controller, it
|
||||
uses receive buffer of size 2048 bytes. In case the controller
|
||||
accepts large(MTU) packets, it could lead to memory corruption.
|
||||
Add check to avoid it.
|
||||
|
||||
Reported-by: Oleksandr Bazhaniuk <oleksandr.bazhaniuk@intel.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-id: 1460095428-22698-1-git-send-email-ppandit@redhat.com
|
||||
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/stellaris_enet.c | 12 +++++++++++-
|
||||
1 files changed, 11 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/stellaris_enet.c b/tools/qemu-xen-traditional/hw/stellaris_enet.c
|
||||
index 84cf60b..6880894 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/stellaris_enet.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/stellaris_enet.c
|
||||
@@ -236,8 +236,18 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
|
||||
n = s->next_packet + s->np;
|
||||
if (n >= 31)
|
||||
n -= 31;
|
||||
- s->np++;
|
||||
|
||||
+ if (size >= sizeof(s->rx[n].data) - 6) {
|
||||
+ /* If the packet won't fit into the
|
||||
+ * emulated 2K RAM, this is reported
|
||||
+ * as a FIFO overrun error.
|
||||
+ */
|
||||
+ s->ris |= SE_INT_FOV;
|
||||
+ stellaris_enet_update(s);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ s->np++;
|
||||
s->rx[n].len = size + 6;
|
||||
p = s->rx[n].data;
|
||||
*(p++) = (size + 6);
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
31
qemu.trad.CVE-2016-4002.patch
Normal file
31
qemu.trad.CVE-2016-4002.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
When receiving packets over MIPSnet network device, it uses
|
||||
receive buffer of size 1514 bytes. In case the controller
|
||||
accepts large(MTU) packets, it could lead to memory corruption.
|
||||
Add check to avoid it.
|
||||
|
||||
Reported by: Oleksandr Bazhaniuk <address@hidden>
|
||||
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
tools/qemu-xen-traditional/hw/mipsnet.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/mipsnet.c b/tools/qemu-xen-traditional/hw/mipsnet.c
|
||||
index f261011..e134b31 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/mipsnet.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/mipsnet.c
|
||||
@@ -82,6 +82,9 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
if (!mipsnet_can_receive(opaque))
|
||||
return;
|
||||
|
||||
+ if (size >= sizeof(s->rx_buffer)) {
|
||||
+ return;
|
||||
+ }
|
||||
s->busy = 1;
|
||||
|
||||
/* Just accept everything. */
|
||||
--
|
||||
2.5.5
|
||||
|
||||
44
qemu.trad.CVE-2016-4439.patch
Normal file
44
qemu.trad.CVE-2016-4439.patch
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: P J P
|
||||
*Subject*: [Qemu-devel] [PATCH 1/2] scsi: check command buffer length
|
||||
before write(CVE-2016-4439)
|
||||
*Date*: Thu, 19 May 2016 16:09:30 +0530
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte
|
||||
FIFO buffer. It is used to handle command and data transfer. While
|
||||
writing to this command buffer 's->cmdbuf[TI_BUFSZ=16]', a check
|
||||
was missing to validate input length. Add check to avoid OOB write
|
||||
access.
|
||||
|
||||
Fixes CVE-2016-4439
|
||||
Reported-by: Li Qiang <address@hidden>
|
||||
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/scsi/esp.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index 8961be2..01497e6 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -448,7 +448,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
|
||||
break;
|
||||
case ESP_FIFO:
|
||||
if (s->do_cmd) {
|
||||
- s->cmdbuf[s->cmdlen++] = val & 0xff;
|
||||
+ if (s->cmdlen < TI_BUFSZ) {
|
||||
+ s->cmdbuf[s->cmdlen++] = val & 0xff;
|
||||
+ } else {
|
||||
+ ESP_ERROR("fifo overrun\n");
|
||||
+ }
|
||||
} else if (s->ti_size == TI_BUFSZ - 1) {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
} else {
|
||||
--
|
||||
2.5.5
|
||||
|
||||
68
qemu.trad.CVE-2016-4441.patch
Normal file
68
qemu.trad.CVE-2016-4441.patch
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: P J P
|
||||
*Subject*: [Qemu-devel] [PATCH 2/2] scsi: check dma length before
|
||||
reading scsi command(CVE-2016-4441)
|
||||
*Date*: Thu, 19 May 2016 16:09:31 +0530
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte
|
||||
FIFO buffer. It is used to handle command and data transfer.
|
||||
Routine get_cmd() uses DMA to read scsi commands into this buffer.
|
||||
Add check to validate DMA length against buffer size to avoid any
|
||||
overrun.
|
||||
|
||||
Fixes CVE-2016-4441
|
||||
Reported-by: Li Qiang <address@hidden>
|
||||
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/scsi/esp.c | 11 +++++++----
|
||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index 01497e6..591c817 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -82,7 +82,7 @@ void esp_request_cancelled(SCSIRequest *req)
|
||||
}
|
||||
}
|
||||
|
||||
-static uint32_t get_cmd(ESPState *s, uint8_t *buf)
|
||||
+static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
|
||||
{
|
||||
uint32_t dmalen;
|
||||
int target;
|
||||
@@ -92,6 +92,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
|
||||
target = s->wregs[ESP_WBUSID] & BUSID_DID;
|
||||
if (s->dma) {
|
||||
dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
|
||||
+ if (dmalen > buflen) {
|
||||
+ return 0;
|
||||
+ }
|
||||
s->dma_memory_read(s->dma_opaque, buf, dmalen);
|
||||
} else {
|
||||
dmalen = s->ti_size;
|
||||
@@ -166,7 +169,7 @@ static void handle_satn(ESPState *s)
|
||||
uint8_t buf[32];
|
||||
int len;
|
||||
|
||||
- len = get_cmd(s, buf);
|
||||
+ len = get_cmd(s, buf, sizeof(buf));
|
||||
if (len)
|
||||
do_cmd(s, buf);
|
||||
}
|
||||
@@ -192,7 +195,7 @@ static void handle_satn_stop(ESPState *s)
|
||||
|
||||
static void handle_satn_stop(ESPState *s)
|
||||
{
|
||||
- s->cmdlen = get_cmd(s, s->cmdbuf);
|
||||
+ s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
|
||||
if (s->cmdlen) {
|
||||
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
|
||||
s->do_cmd = 1;
|
||||
--
|
||||
2.5.5
|
||||
|
||||
65
qemu.trad.CVE-2016-5238.patch
Normal file
65
qemu.trad.CVE-2016-5238.patch
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: Paolo Bonzini
|
||||
*Subject*: Re: [Qemu-devel] [PATCH] scsi: check buffer length before
|
||||
reading scsi command
|
||||
*Date*: Wed, 1 Jun 2016 15:10:16 +0200
|
||||
*User-agent*: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
|
||||
Thunderbird/45.1.0
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
On 31/05/2016 19:53, P J P wrote:
|
||||
>/ From: Prasad J Pandit <address@hidden>/
|
||||
>/ /
|
||||
>/ The 53C9X Fast SCSI Controller(FSC) comes with an internal 16-byte/
|
||||
>/ FIFO buffer. It is used to handle command and data transfer./
|
||||
>/ Routine get_cmd() in non-DMA mode, uses 'ti_size' to read scsi/
|
||||
>/ command into a buffer. Add check to validate command length against/
|
||||
>/ buffer size to avoid any overrun./
|
||||
>/ /
|
||||
>/ Reported-by: Li Qiang <address@hidden>/
|
||||
>/ Signed-off-by: Prasad J Pandit <address@hidden>/
|
||||
>/ ---/
|
||||
>/ hw/scsi/esp.c | 3 +++/
|
||||
>/ 1 file changed, 3 insertions(+)/
|
||||
>/ /
|
||||
>/ diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c/
|
||||
>/ index 60c1b28..953027a 100644/
|
||||
>/ --- a/tools/qemu-xen-traditional/hw/esp.c/
|
||||
>/ +++ b/tools/qemu-xen-traditional/hw/esp.c/
|
||||
>/ @@ -98,6 +98,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t /
|
||||
>/ buflen)/
|
||||
>/ s->dma_memory_read(s->dma_opaque, buf, dmalen);/
|
||||
>/ } else {/
|
||||
>/ dmalen = s->ti_size;/
|
||||
>/ + if (dmalen > TI_BUFSZ) {/
|
||||
>/ + return 0;/
|
||||
>/ + }/
|
||||
>/ memcpy(buf, s->ti_buf, dmalen);/
|
||||
>/ buf[0] = buf[2] >> 5;/
|
||||
>/ }/
|
||||
>/ /
|
||||
|
||||
In theory this shouldn't happen, but I agree that it is better to be
|
||||
defensive. I'm queuing this patch.
|
||||
|
||||
At least the following patch is needed to ensure that ti_size always
|
||||
matches ti_rptr/ti_wptr (Hervé, what do you think about it? should I
|
||||
resubmit it formally?). Also, things are more complicated than
|
||||
necessary due to ti_size being used for both DMA and FIFO transfers.
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index c2f6f8f..6407844 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -222,7 +222,7 @@ static void write_response(ESPState *s)
|
||||
} else {
|
||||
s->ti_size = 2;
|
||||
s->ti_rptr = 0;
|
||||
- s->ti_wptr = 0;
|
||||
+ s->ti_wptr = 2;
|
||||
s->rregs[ESP_RFLAGS] = 2;
|
||||
}
|
||||
esp_raise_irq(s);
|
||||
|
||||
76
qemu.trad.CVE-2016-5338.patch
Normal file
76
qemu.trad.CVE-2016-5338.patch
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
------------------------------------------------------------------------
|
||||
*From*: P J P
|
||||
*Subject*: [Qemu-devel] [PATCH v3] scsi: esp: check TI buffer index
|
||||
before read/write
|
||||
*Date*: Mon, 6 Jun 2016 22:04:43 +0530
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
The 53C9X Fast SCSI Controller(FSC) comes with internal 16-byte
|
||||
FIFO buffers. One is used to handle commands and other is for
|
||||
information transfer. Three control variables 'ti_rptr',
|
||||
'ti_wptr' and 'ti_size' are used to control r/w access to the
|
||||
information transfer buffer ti_buf[TI_BUFSZ=16]. In that,
|
||||
|
||||
'ti_rptr' is used as read index, where read occurs.
|
||||
'ti_wptr' is a write index, where write would occur.
|
||||
'ti_size' indicates total bytes to be read from the buffer.
|
||||
|
||||
While reading/writing to this buffer, index could exceed its
|
||||
size. Add check to avoid OOB r/w access.
|
||||
|
||||
Reported-by: Huawei PSIRT <address@hidden>
|
||||
Reported-by: Li Qiang <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/scsi/esp.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
Update as per:
|
||||
-> https://lists.gnu.org/archive/html/qemu-devel/2016-06/msg01326.html
|
||||
|
||||
diff --git a/tools/qemu-xen-traditional/hw/esp.c b/tools/qemu-xen-traditional/hw/esp.c
|
||||
index c2f6f8f..4b94bbc 100644
|
||||
--- a/tools/qemu-xen-traditional/hw/esp.c
|
||||
+++ b/tools/qemu-xen-traditional/hw/esp.c
|
||||
@@ -403,18 +403,17 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
|
||||
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
|
||||
switch (saddr) {
|
||||
case ESP_FIFO:
|
||||
- if (s->ti_size > 0) {
|
||||
+ if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
|
||||
+ /* Data out. */
|
||||
+ ESP_ERROR("PIO data read not implemented\n");
|
||||
+ s->rregs[ESP_FIFO] = 0;
|
||||
+ esp_raise_irq(s);
|
||||
+ } else if (s->ti_rptr < s->ti_wptr) {
|
||||
s->ti_size--;
|
||||
- if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
|
||||
- /* Data out. */
|
||||
- ESP_ERROR("PIO data read not implemented\n");
|
||||
- s->rregs[ESP_FIFO] = 0;
|
||||
- } else {
|
||||
- s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
|
||||
- }
|
||||
+ s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
|
||||
esp_raise_irq(s);
|
||||
}
|
||||
- if (s->ti_size == 0) {
|
||||
+ if (s->ti_rptr == s->ti_wptr) {
|
||||
s->ti_rptr = 0;
|
||||
s->ti_wptr = 0;
|
||||
}
|
||||
@@ -459,7 +457,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
|
||||
} else {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
}
|
||||
- } else if (s->ti_size == TI_BUFSZ - 1) {
|
||||
+ } else if (s->ti_wptr == TI_BUFSZ - 1) {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
} else {
|
||||
s->ti_size++;
|
||||
--
|
||||
2.5.5
|
||||
|
||||
81
qemu.trad.CVE-2016-6351.patch
Normal file
81
qemu.trad.CVE-2016-6351.patch
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
From 926cde5f3e4d2504ed161ed0cb771ac7cad6fd11 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Thu, 16 Jun 2016 00:22:35 +0200
|
||||
Subject: [PATCH] scsi: esp: make cmdbuf big enough for maximum CDB size
|
||||
|
||||
While doing DMA read into ESP command buffer 's->cmdbuf', it could
|
||||
write past the 's->cmdbuf' area, if it was transferring more than 16
|
||||
bytes. Increase the command buffer size to 32, which is maximum when
|
||||
's->do_cmd' is set, and add a check on 'len' to avoid OOB access.
|
||||
|
||||
Reported-by: Li Qiang <liqiang6-s@360.cn>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
hw/esp.c | 6 ++++--
|
||||
hw/esp.c | 3 ++-
|
||||
2 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/hw/esp.c b/hw/esp.c
|
||||
index 64680b3..baa0a2c 100644
|
||||
--- a/hw/esp.c
|
||||
+++ b/hw/esp.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "hw.h"
|
||||
#include "scsi-disk.h"
|
||||
#include "scsi.h"
|
||||
+#include <assert.h>
|
||||
|
||||
/* debug ESP card */
|
||||
//#define DEBUG_ESP
|
||||
@@ -248,6 +248,8 @@ static void esp_do_dma(ESPState *s)
|
||||
len = s->dma_left;
|
||||
if (s->do_cmd) {
|
||||
DPRINTF("command len %d + %d\n", s->cmdlen, len);
|
||||
+ assert (s->cmdlen <= sizeof(s->cmdbuf) &&
|
||||
+ len <= sizeof(s->cmdbuf) - s->cmdlen);
|
||||
s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
|
||||
s->ti_size = 0;
|
||||
s->cmdlen = 0;
|
||||
@@ -345,7 +347,7 @@ static void handle_ti(ESPState *s)
|
||||
s->dma_counter = dmalen;
|
||||
|
||||
if (s->do_cmd)
|
||||
- minlen = (dmalen < 32) ? dmalen : 32;
|
||||
+ minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
|
||||
else if (s->ti_size < 0)
|
||||
minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
|
||||
else
|
||||
@@ -449,7 +451,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
|
||||
break;
|
||||
case ESP_FIFO:
|
||||
if (s->do_cmd) {
|
||||
- if (s->cmdlen < TI_BUFSZ) {
|
||||
+ if (s->cmdlen < ESP_CMDBUF_SZ) {
|
||||
s->cmdbuf[s->cmdlen++] = val & 0xff;
|
||||
} else {
|
||||
ESP_ERROR("fifo overrun\n");
|
||||
diff --git a/hw/esp.c b/hw/esp.c
|
||||
index 6c79527..d2c4886 100644
|
||||
--- a/hw/esp.c
|
||||
+++ b/hw/esp.c
|
||||
@@ -14,6 +14,7 @@ void esp_init(hwaddr espaddr, int it_shift,
|
||||
|
||||
#define ESP_REGS 16
|
||||
#define TI_BUFSZ 16
|
||||
+#define ESP_CMDBUF_SZ 32
|
||||
|
||||
typedef struct ESPState ESPState;
|
||||
|
||||
@@ -31,7 +32,7 @@ struct ESPState {
|
||||
uint32_t dma;
|
||||
SCSIDevice *scsi_dev[ESP_MAX_DEVS];
|
||||
SCSIDevice *current_dev;
|
||||
- uint8_t cmdbuf[TI_BUFSZ];
|
||||
+ uint8_t cmdbuf[ESP_CMDBUF_SZ];
|
||||
uint32_t cmdlen;
|
||||
uint32_t do_cmd;
|
||||
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
37
qemu.trad.CVE-2016-8669.patch
Normal file
37
qemu.trad.CVE-2016-8669.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
From 3592fe0c919cf27a81d8e9f9b4f269553418bb01 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Wed, 12 Oct 2016 11:28:08 +0530
|
||||
Subject: [PATCH] char: serial: check divider value against baud base
|
||||
|
||||
16550A UART device uses an oscillator to generate frequencies
|
||||
(baud base), which decide communication speed. This speed could
|
||||
be changed by dividing it by a divider. If the divider is
|
||||
greater than the baud base, speed is set to zero, leading to a
|
||||
divide by zero error. Add check to avoid it.
|
||||
|
||||
Reported-by: Huawei PSIRT <psirt@huawei.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-Id: <1476251888-20238-1-git-send-email-ppandit@redhat.com>
|
||||
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||||
---
|
||||
hw/char/serial.c | 3 ++-
|
||||
1 files changed, 2 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/serial.c b/hw/serial.c
|
||||
index 3442f47..eec72b7 100644
|
||||
--- a/hw/serial.c
|
||||
+++ b/hw/serial.c
|
||||
@@ -153,8 +153,9 @@ static void serial_update_parameters(SerialState *s)
|
||||
int speed, parity, data_bits, stop_bits, frame_size;
|
||||
QEMUSerialSetParams ssp;
|
||||
|
||||
- if (s->divider == 0)
|
||||
+ if (s->divider == 0 || s->divider > s->baudbase) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
frame_size = 1;
|
||||
if (s->lcr & 0x08) {
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
29
qemu.trad.CVE-2016-8910.patch
Normal file
29
qemu.trad.CVE-2016-8910.patch
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
From: Prasad J Pandit <address@hidden>
|
||||
|
||||
RTL8139 ethernet controller in C+ mode supports multiple
|
||||
descriptor rings, each with maximum of 64 descriptors. While
|
||||
processing transmit descriptor ring in 'rtl8139_cplus_transmit',
|
||||
it does not limit the descriptor count and runs forever. Add
|
||||
check to avoid it.
|
||||
|
||||
Reported-by: Andrew Henderson <address@hidden>
|
||||
Signed-off-by: Prasad J Pandit <address@hidden>
|
||||
---
|
||||
hw/net/rtl8139.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
|
||||
index 3345bc6..f05e59c 100644
|
||||
--- a/hw/rtl8139.c
|
||||
+++ b/hw/rtl8139.c
|
||||
@@ -2350,7 +2350,7 @@ static void rtl8139_cplus_transmit(RTL8139State *s)
|
||||
{
|
||||
int txcount = 0;
|
||||
|
||||
- while (rtl8139_cplus_transmit_one(s))
|
||||
+ while (txcount < 64 && rtl8139_cplus_transmit_one(s))
|
||||
{
|
||||
++txcount;
|
||||
}
|
||||
--
|
||||
2.7.4
|
||||
34
qemu.trad.CVE-2016-9776.patch
Normal file
34
qemu.trad.CVE-2016-9776.patch
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
From 77d54985b85a0cb760330ec2bd92505e0a2a97a9 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Tue, 29 Nov 2016 00:38:39 +0530
|
||||
Subject: [PATCH] net: mcf: check receive buffer size register value
|
||||
|
||||
ColdFire Fast Ethernet Controller uses a receive buffer size
|
||||
register(EMRBR) to hold maximum size of all receive buffers.
|
||||
It is set by a user before any operation. If it was set to be
|
||||
zero, ColdFire emulator would go into an infinite loop while
|
||||
receiving data in mcf_fec_receive. Add check to avoid it.
|
||||
|
||||
Reported-by: Wjjzhang <wjjzhang@tencent.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Signed-off-by: Jason Wang <jasowang@redhat.com>
|
||||
---
|
||||
hw/net/mcf_fec.c | 2 +-
|
||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
|
||||
index dc61bac..4025eb3 100644
|
||||
--- a/hw/mcf_fec.c
|
||||
+++ b/hw/mcf_fec.c
|
||||
@@ -393,7 +393,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
||||
s->tx_descriptor = s->etdsr;
|
||||
break;
|
||||
case 0x188:
|
||||
- s->emrbr = value & 0x7f0;
|
||||
+ s->emrbr = value > 0 ? value & 0x7F0 : 0x7F0;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n",
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
51
qemu.trad.CVE-2017-6505.patch
Normal file
51
qemu.trad.CVE-2017-6505.patch
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
From 95ed56939eb2eaa4e2f349fe6dcd13ca4edfd8fb Mon Sep 17 00:00:00 2001
|
||||
From: Li Qiang <liqiang6-s@360.cn>
|
||||
Date: Tue, 7 Feb 2017 02:23:33 -0800
|
||||
Subject: [PATCH] usb: ohci: limit the number of link eds
|
||||
|
||||
The guest may builds an infinite loop with link eds. This patch
|
||||
limit the number of linked ed to avoid this.
|
||||
|
||||
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
|
||||
Message-id: 5899a02e.45ca240a.6c373.93c1@mx.google.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb-ohci.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
|
||||
index 2cba3e3..21c93e0 100644
|
||||
--- a/hw/usb-ohci.c
|
||||
+++ b/hw/usb-ohci.c
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#define OHCI_MAX_PORTS 15
|
||||
|
||||
+#define ED_LINK_LIMIT 4
|
||||
+
|
||||
static int64_t usb_frame_time;
|
||||
static int64_t usb_bit_time;
|
||||
|
||||
@@ -1184,7 +1186,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
||||
uint32_t next_ed;
|
||||
uint32_t cur;
|
||||
int active;
|
||||
-
|
||||
+ uint32_t link_cnt = 0;
|
||||
active = 0;
|
||||
|
||||
if (head == 0)
|
||||
@@ -1199,6 +1201,10 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
|
||||
|
||||
next_ed = ed.next & OHCI_DPTR_MASK;
|
||||
|
||||
+ if (++link_cnt > ED_LINK_LIMIT) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
|
||||
uint32_t addr;
|
||||
/* Cancel pending packets for ED that have been paused. */
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
51
qemu.trad.CVE-2017-7718.patch
Normal file
51
qemu.trad.CVE-2017-7718.patch
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
From 215902d7b6fb50c6fc216fc74f770858278ed904 Mon Sep 17 00:00:00 2001
|
||||
From: hangaohuai <hangaohuai@huawei.com>
|
||||
Date: Tue, 14 Mar 2017 14:39:19 +0800
|
||||
Subject: [PATCH] fix :cirrus_vga fix OOB read case qemu Segmentation fault
|
||||
|
||||
check the validity of parameters in cirrus_bitblt_rop_fwd_transp_xxx
|
||||
and cirrus_bitblt_rop_fwd_xxx to avoid the OOB read which causes qemu Segmentation fault.
|
||||
|
||||
After the fix, we will touch the assert in
|
||||
cirrus_invalidate_region:
|
||||
assert(off_cur_end >= off_cur);
|
||||
|
||||
Signed-off-by: fangying <fangying1@huawei.com>
|
||||
Signed-off-by: hangaohuai <hangaohuai@huawei.com>
|
||||
Message-id: 20170314063919.16200-1-hangaohuai@huawei.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/cirrus_vga_rop.h | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
|
||||
index 0925a00..b7447f8 100644
|
||||
--- a/hw/cirrus_vga_rop.h
|
||||
+++ b/hw/cirrus_vga_rop.h
|
||||
@@ -97,6 +97,11 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||
src = src_ - src_base;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
+
|
||||
+ if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x++) {
|
||||
p = *(dst_base + m(dst));
|
||||
@@ -143,6 +148,11 @@ glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||
src = src_ - src_base;
|
||||
dstpitch -= bltwidth;
|
||||
srcpitch -= bltwidth;
|
||||
+
|
||||
+ if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
for (y = 0; y < bltheight; y++) {
|
||||
for (x = 0; x < bltwidth; x+=2) {
|
||||
p1 = *(dst_base + m(dst));
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
38
qemu.trad.CVE-2017-8309.patch
Normal file
38
qemu.trad.CVE-2017-8309.patch
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
From 3268a845f41253fb55852a8429c32b50f36f349a Mon Sep 17 00:00:00 2001
|
||||
From: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Date: Fri, 28 Apr 2017 09:56:12 +0200
|
||||
Subject: [PATCH] audio: release capture buffers
|
||||
|
||||
AUD_add_capture() allocates two buffers which are never released.
|
||||
Add the missing calls to AUD_del_capture().
|
||||
|
||||
Impact: Allows vnc clients to exhaust host memory by repeatedly
|
||||
starting and stopping audio capture.
|
||||
|
||||
Fixes: CVE-2017-8309
|
||||
Cc: P J P <ppandit@redhat.com>
|
||||
Cc: Huawei PSIRT <PSIRT@huawei.com>
|
||||
Reported-by: "Jiangxin (hunter, SCC)" <jiangxin1@huawei.com>
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
Reviewed-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-id: 20170428075612.9997-1-kraxel@redhat.com
|
||||
---
|
||||
audio/audio.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/audio/audio.c b/audio/audio.c
|
||||
index c8898d8..beafed2 100644
|
||||
--- a/audio/audio.c
|
||||
+++ b/audio/audio.c
|
||||
@@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
|
||||
sw = sw1;
|
||||
}
|
||||
LIST_REMOVE (cap, entries);
|
||||
+ qemu_free (cap->hw.mix_buf);
|
||||
+ qemu_free (cap->buf);
|
||||
qemu_free (cap);
|
||||
}
|
||||
return;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
31
qemu.trad.CVE-2017-9330.patch
Normal file
31
qemu.trad.CVE-2017-9330.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
From 26f670a244982335cc08943fb1ec099a2c81e42d Mon Sep 17 00:00:00 2001
|
||||
From: Li Qiang <liqiang6-s@360.cn>
|
||||
Date: Tue, 7 Feb 2017 03:15:03 -0800
|
||||
Subject: [PATCH] usb: ohci: fix error return code in servicing iso td
|
||||
|
||||
It should return 1 if an error occurs when reading iso td.
|
||||
This will avoid an infinite loop issue in ohci_service_ed_list.
|
||||
|
||||
Signed-off-by: Li Qiang <liqiang6-s@360.cn>
|
||||
Message-id: 5899ac3e.1033240a.944d5.9a2d@mx.google.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/usb-ohci.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
|
||||
index c82a92f..2cba3e3 100644
|
||||
--- a/hw/usb-ohci.c
|
||||
+++ b/hw/usb-ohci.c
|
||||
@@ -725,7 +725,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
|
||||
|
||||
if (!ohci_read_iso_td(addr, &iso_td)) {
|
||||
printf("usb-ohci: ISO_TD read error at %x\n", addr);
|
||||
- return 0;
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
starting_frame = OHCI_BM(iso_td.flags, TD_SF);
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
76
qemu.trad.bug1399055.patch
Normal file
76
qemu.trad.bug1399055.patch
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
From 4299b90e9ba9ce5ca9024572804ba751aa1a7e70 Mon Sep 17 00:00:00 2001
|
||||
From: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Date: Tue, 18 Oct 2016 13:15:17 +0530
|
||||
Subject: [PATCH] display: cirrus: check vga bits per pixel(bpp) value
|
||||
|
||||
In Cirrus CLGD 54xx VGA Emulator, if cirrus graphics mode is VGA,
|
||||
'cirrus_get_bpp' returns zero(0), which could lead to a divide
|
||||
by zero error in while copying pixel data. The same could occur
|
||||
via blit pitch values. Add check to avoid it.
|
||||
|
||||
Reported-by: Huawei PSIRT <psirt@huawei.com>
|
||||
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
|
||||
Message-id: 1476776717-24807-1-git-send-email-ppandit@redhat.com
|
||||
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
|
||||
---
|
||||
hw/cirrus_vga.c | 14 ++++++++++----
|
||||
1 files changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
|
||||
index 3d712d5..bdb092e 100644
|
||||
--- a/hw/cirrus_vga.c
|
||||
+++ b/hw/cirrus_vga.c
|
||||
@@ -272,6 +272,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
|
||||
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
int32_t pitch, int32_t addr)
|
||||
{
|
||||
+ if (!pitch) {
|
||||
+ return true;
|
||||
+ }
|
||||
if (pitch < 0) {
|
||||
int64_t min = addr
|
||||
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||
@@ -715,7 +718,7 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||
s->cirrus_addr_mask));
|
||||
}
|
||||
|
||||
-static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
+static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
{
|
||||
int sx = 0, sy = 0;
|
||||
int dx = 0, dy = 0;
|
||||
@@ -729,6 +732,9 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
int width, height;
|
||||
|
||||
depth = s->get_bpp((VGAState *)s) / 8;
|
||||
+ if (!depth) {
|
||||
+ return 0;
|
||||
+ }
|
||||
s->get_resolution((VGAState *)s, &width, &height);
|
||||
|
||||
/* extra x, y */
|
||||
@@ -783,6 +789,8 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||
s->cirrus_blt_dstpitch, s->cirrus_blt_width,
|
||||
s->cirrus_blt_height);
|
||||
+
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
@@ -790,11 +798,9 @@ static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
if (blit_is_unsafe(s))
|
||||
return 0;
|
||||
|
||||
- cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
|
||||
+ return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
|
||||
s->cirrus_blt_srcaddr - s->start_addr,
|
||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||
-
|
||||
- return 1;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
--
|
||||
1.7.0.4
|
||||
|
||||
3
sources
3
sources
|
|
@ -4,5 +4,4 @@ SHA512 (newlib-1.16.0.tar.gz) = 40eb96bbc6736a16b6399e0cdb73e853d0d90b685c967e77
|
|||
SHA512 (zlib-1.2.3.tar.gz) = 021b958fcd0d346c4ba761bcf0cc40f3522de6186cf5a0a6ea34a70504ce9622b1c2626fce40675bc8282cf5f5ade18473656abc38050f72f5d6480507a2106e
|
||||
SHA512 (polarssl-1.1.4-gpl.tgz) = 88da614e4d3f4409c4fd3bb3e44c7587ba051e3fed4e33d526069a67e8180212e1ea22da984656f50e290049f60ddca65383e5983c0f8884f648d71f698303ad
|
||||
SHA512 (pciutils-2.2.9.tar.bz2) = 2b3d98d027e46d8c08037366dde6f0781ca03c610ef2b380984639e4ef39899ed8d8b8e4cd9c9dc54df101279b95879bd66bfd4d04ad07fef41e847ea7ae32b5
|
||||
SHA512 (mini-os-4.21.0.tar.xz) = 7543774d15da84476d93d04154990923c82209cb3fa125574c0383652c5a310957200f54b63b34502161f9c3afce4907e0060d9036f3eaf3a7cb6b1b3119b546
|
||||
SHA512 (xen-4.21.1.tar.xz) = 8dfe65255e202b3dacf9d0d7265636bc1f97627c11b08babc13a5b8e74c7c65e7e2c6a1513e28b3c713fe512edb6702a73b2bf667e2a8f2ce825b196a2cd5aab
|
||||
SHA512 (xen-4.16.5.tar.gz) = 2f370787b72b2cd9d81c0b5f138133e676d2b9c8c76e31e6439649d7145242a6b7be0d51a7ff4f4197a99e3f6b24ac50e63d2fa49368da440d3f555e70c4ebd3
|
||||
|
|
|
|||
|
|
@ -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
8
xen.drop.brctl.patch
Normal 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
|
||||
|
|
@ -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
11
xen.fedora.crypt.patch
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
--- xen-4.5.1/tools/qemu-xen-traditional/vnc.c.orig 2015-07-12 21:55:32.875504811 +0100
|
||||
+++ xen-4.5.1/tools/qemu-xen-traditional/vnc.c 2015-07-12 22:03:03.860005391 +0100
|
||||
@@ -2140,7 +2140,7 @@
|
||||
GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
|
||||
static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
|
||||
{
|
||||
- const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
|
||||
+ const char *priority = x509 ? "@SYSTEM" : "@SYSTEM:+ANON-DH";
|
||||
int rc;
|
||||
|
||||
rc = gnutls_priority_set_direct(s, priority, NULL);
|
||||
|
|
@ -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
10
xen.gcc10.fixes.patch
Normal 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)
|
||||
|
||||
|
|
@ -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
12
xen.gcc7.fix.patch
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
--- xen-4.8.0/extras/mini-os/Makefile.orig 2016-09-28 12:09:38.000000000 +0100
|
||||
+++ xen-4.8.0/extras/mini-os/Makefile 2017-02-15 21:15:19.340197960 +0000
|
||||
@@ -142,6 +142,9 @@
|
||||
APP_LDLIBS += -lz
|
||||
APP_LDLIBS += -lm
|
||||
LDLIBS += -lc
|
||||
+ifeq ($(MINIOS_TARGET_ARCH),x86_32)
|
||||
+LDLIBS += -L$(shell dirname `gcc -m32 -print-libgcc-file-name`) -lgcc
|
||||
+endif
|
||||
endif
|
||||
|
||||
ifneq ($(APP_OBJS)-$(lwip),-y)
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
From 90b20547b756a5cf9b0fec9fb0de5b361e8bf4c3 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Date: Fri, 10 Apr 2026 21:55:46 +0100
|
||||
Subject: [PATCH] x86/amd: Mitigate AMD-SN-7053 / FP-DSS
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This is XSA-488 / CVE-2025-54505
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
(cherry picked from commit 99912d346009fda1e7fb1510c9501fbab17e92a0)
|
||||
---
|
||||
xen/arch/x86/cpu/amd.c | 37 ++++++++++++++++++++++++++++
|
||||
xen/arch/x86/include/asm/msr-index.h | 1 +
|
||||
2 files changed, 38 insertions(+)
|
||||
|
||||
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
|
||||
index 8c55d233f3..1bb0766ebf 100644
|
||||
--- a/xen/arch/x86/cpu/amd.c
|
||||
+++ b/xen/arch/x86/cpu/amd.c
|
||||
@@ -1048,6 +1048,42 @@ void amd_init_de_cfg(const struct cpuinfo_x86 *c)
|
||||
wrmsrl(MSR_AMD64_DE_CFG, val | new);
|
||||
}
|
||||
|
||||
+static void amd_init_fp_cfg(const struct cpuinfo_x86 *c)
|
||||
+{
|
||||
+ uint64_t val, new = 0;
|
||||
+
|
||||
+ /* If virtualised, we won't have mutable access even if we can read it. */
|
||||
+ if ( cpu_has_hypervisor )
|
||||
+ return;
|
||||
+
|
||||
+ /*
|
||||
+ * On Zen1, mitigate SB-7053 / FP-DSS Floating Point Divider State
|
||||
+ * Sampling by setting bit 9 as instructed.
|
||||
+ */
|
||||
+ if ( c->family == 0x17 && is_zen1_uarch() )
|
||||
+ new |= 1 << 9;
|
||||
+
|
||||
+ /*
|
||||
+ * Avoid reading FP_CFG if we don't intend to change anything. The
|
||||
+ * register doesn't exist on all families.
|
||||
+ */
|
||||
+ if ( !new )
|
||||
+ return;
|
||||
+
|
||||
+ val = rdmsr(MSR_AMD64_FP_CFG);
|
||||
+
|
||||
+ if ( (val & new) == new )
|
||||
+ return;
|
||||
+
|
||||
+ /*
|
||||
+ * FP_CFG is a Core-scoped MSR, and this write is racy. However, both
|
||||
+ * threads calculate the new value from state which expected to be
|
||||
+ * consistent across CPUs and unrelated to the old value, so the result
|
||||
+ * should be consistent.
|
||||
+ */
|
||||
+ wrmsr(MSR_AMD64_FP_CFG, val | new);
|
||||
+}
|
||||
+
|
||||
void __init amd_init_lfence_dispatch(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
@@ -1120,6 +1156,7 @@ static void cf_check init_amd(struct cpuinfo_x86 *c)
|
||||
uint64_t value;
|
||||
|
||||
amd_init_de_cfg(c);
|
||||
+ amd_init_fp_cfg(c);
|
||||
|
||||
if (c == &boot_cpu_data)
|
||||
amd_init_lfence_dispatch(); /* Needs amd_init_de_cfg() */
|
||||
diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h
|
||||
index df52587c85..6c5b2569e1 100644
|
||||
--- a/xen/arch/x86/include/asm/msr-index.h
|
||||
+++ b/xen/arch/x86/include/asm/msr-index.h
|
||||
@@ -428,6 +428,7 @@
|
||||
#define MSR_AMD64_LS_CFG 0xc0011020U
|
||||
#define MSR_AMD64_IC_CFG 0xc0011021U
|
||||
#define MSR_AMD64_DC_CFG 0xc0011022U
|
||||
+#define MSR_AMD64_FP_CFG 0xc0011028U
|
||||
#define MSR_AMD64_DE_CFG 0xc0011029U
|
||||
#define AMD64_DE_CFG_LFENCE_SERIALISE (_AC(1, ULL) << 1)
|
||||
#define MSR_AMD64_EX_CFG 0xc001102cU
|
||||
--
|
||||
2.39.5
|
||||
|
||||
|
|
@ -1,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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
|
||||
145
xsa376.patch
Normal file
145
xsa376.patch
Normal 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
110
xsa437-4.16.patch
Normal 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
414
xsa438-4.16.patch
Normal 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)
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
239
xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch
Normal file
239
xsa439-0010-x86-spec-ctrl-Mitigate-the-Zen1-DIV-leakage.patch
Normal 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
58
xsa440-4.17.patch
Normal 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
185
xsa442-4.17.patch
Normal 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
70
xsa443-4.16-01.patch
Normal 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
32
xsa443-4.16-02.patch
Normal 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
137
xsa443-4.16-03.patch
Normal 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
60
xsa443-4.16-04.patch
Normal 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
59
xsa443-4.16-05.patch
Normal 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
65
xsa443-4.16-06.patch
Normal 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
105
xsa443-4.16-07.patch
Normal 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
126
xsa443-4.16-08.patch
Normal 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
307
xsa443-4.16-09.patch
Normal 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
250
xsa443-4.16-10.patch
Normal 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
157
xsa443-4.16-11.patch
Normal 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
93
xsa444-4.16-1.patch
Normal 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
72
xsa444-4.16-2.patch
Normal 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
65
xsa445-4.16.patch
Normal 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
115
xsa446.patch
Normal 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
|
||||
|
||||
30
xsa483.patch
30
xsa483.patch
|
|
@ -1,30 +0,0 @@
|
|||
From: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
Subject: tools/oxenstored: Reset quota when resetting permissions
|
||||
|
||||
The quota object contains both limits and the current node usage counts.
|
||||
|
||||
When a domain is torn down, the node data itself is cleaned up but the node
|
||||
usage counts are not. A later domain reusing the same domid can create fewer
|
||||
nodes before being deemed to be over quota.
|
||||
|
||||
Reset the count when the node permissions are cleaned up.
|
||||
|
||||
This is XSA-483 / CVE-2026-23556.
|
||||
|
||||
Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
|
||||
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
|
||||
index 9b8dd2812df0..aa9204ead3ec 100644
|
||||
--- a/tools/ocaml/xenstored/store.ml
|
||||
+++ b/tools/ocaml/xenstored/store.ml
|
||||
@@ -465,7 +465,8 @@ let reset_permissions store domid =
|
||||
if perms <> node.perms then
|
||||
Logging.debug "store|node" "Changed permissions for node %s" (Node.get_name node);
|
||||
Some { node with Node.perms }
|
||||
- ) store.root
|
||||
+ ) store.root;
|
||||
+ store.quota <- Quota.del store.quota domid
|
||||
|
||||
type ops = {
|
||||
store: t;
|
||||
89
xsa484.patch
89
xsa484.patch
|
|
@ -1,89 +0,0 @@
|
|||
From 3d0d19ad17f29c64dde4a7baf392da4fd58f3654 Mon Sep 17 00:00:00 2001
|
||||
From: Juergen Gross <jgross@suse.com>
|
||||
Date: Mon, 16 Mar 2026 15:06:11 +0100
|
||||
Subject: [PATCH] tools/xenstored: make conn_delete_all_transactions()
|
||||
idempotent
|
||||
|
||||
conn_delete_all_transactions() should be callable in any context,
|
||||
resetting ALL transaction related data.
|
||||
|
||||
This includes number of active transactions and the transaction
|
||||
pointer in struct connection.
|
||||
|
||||
So reset conn->trans to NULL in conn_delete_all_transactions() and
|
||||
do the cleanup for each transaction in destroy_transaction().
|
||||
|
||||
This avoids triggering the assert() in conn_delete_all_transactions()
|
||||
in case e.g. ignore_connection() was called while an operation inside
|
||||
a transaction was performed, or XS_RESET_WATCHES was called in a
|
||||
transaction.
|
||||
|
||||
This is XSA-484 / CVE-2026-23557.
|
||||
|
||||
Reported-by: Andrii Sultanov <andriy.sultanov@vates.tech>
|
||||
Fixes: 1f9d04fb021c ("xenstored: allow guest to shutdown all its watches/transactions")
|
||||
Signed-off-by: Juergen Gross <jgross@suse.com>
|
||||
---
|
||||
tools/xenstored/transaction.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/tools/xenstored/transaction.c b/tools/xenstored/transaction.c
|
||||
index 167cd597fd..0825c48859 100644
|
||||
--- a/tools/xenstored/transaction.c
|
||||
+++ b/tools/xenstored/transaction.c
|
||||
@@ -432,17 +432,23 @@ static int finalize_transaction(struct connection *conn,
|
||||
static int destroy_transaction(void *_transaction)
|
||||
{
|
||||
struct transaction *trans = _transaction;
|
||||
+ struct connection *conn = trans->conn;
|
||||
struct accessed_node *i;
|
||||
|
||||
wrl_ntransactions--;
|
||||
trace_destroy(trans, "transaction");
|
||||
while ((i = list_top(&trans->accessed, struct accessed_node, list))) {
|
||||
if (i->ta_node)
|
||||
- db_delete(trans->conn, i->trans_name, NULL);
|
||||
+ db_delete(conn, i->trans_name, NULL);
|
||||
list_del(&i->list);
|
||||
talloc_free(i);
|
||||
}
|
||||
|
||||
+ list_del(&trans->list);
|
||||
+ domain_transaction_dec(conn);
|
||||
+ if (list_empty(&conn->transaction_list))
|
||||
+ conn->ta_start_time = 0;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -523,10 +529,6 @@ int do_transaction_end(const void *ctx, struct connection *conn,
|
||||
return ENOENT;
|
||||
|
||||
conn->transaction = NULL;
|
||||
- list_del(&trans->list);
|
||||
- domain_transaction_dec(conn);
|
||||
- if (list_empty(&conn->transaction_list))
|
||||
- conn->ta_start_time = 0;
|
||||
|
||||
chk_quota = trans->node_created && domain_is_unprivileged(conn);
|
||||
|
||||
@@ -572,14 +574,10 @@ void conn_delete_all_transactions(struct connection *conn)
|
||||
struct transaction *trans;
|
||||
|
||||
while ((trans = list_top(&conn->transaction_list,
|
||||
- struct transaction, list))) {
|
||||
- list_del(&trans->list);
|
||||
+ struct transaction, list)))
|
||||
talloc_free(trans);
|
||||
- }
|
||||
-
|
||||
- assert(conn->transaction == NULL);
|
||||
|
||||
- conn->ta_start_time = 0;
|
||||
+ conn->transaction = NULL;
|
||||
}
|
||||
|
||||
int check_transactions(struct hashtable *hash)
|
||||
--
|
||||
2.53.0
|
||||
|
||||
181
xsa486.patch
181
xsa486.patch
|
|
@ -1,181 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: gnttab: split gnttab_map_frame()
|
||||
|
||||
If a domain tries to map status frames in parallel to switching grant
|
||||
table version from 2 to 1, the mapping operation may put in place P2M
|
||||
entries referencing MFNs which gnttab_unpopulate_status_frames() is in the
|
||||
process of freeing.
|
||||
|
||||
Ideally we would refcount pages when entered into P2M tables, but that's a
|
||||
significant change. Extend the grant-table-locked region instead in
|
||||
xenmem_add_to_physmap_one() (being the sole caller of gnttab_map_frame()),
|
||||
such that a race with gnttab_unpopulate_status_frames() is no longer
|
||||
possible.
|
||||
|
||||
This is XSA-486 / CVE-2026-23558.
|
||||
|
||||
Fixes: 5ce8fafa947c ("Dynamic grant-table sizing")
|
||||
Fixes: a98dc13703e0 ("Introduce a grant_entry_v2 structure")
|
||||
Reported-by: Rafal Wojtczuk <rafal.wojtczuk@7bulls.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/arm/mm.c
|
||||
+++ b/xen/arch/arm/mm.c
|
||||
@@ -174,12 +174,10 @@ int xenmem_add_to_physmap_one(
|
||||
switch ( space )
|
||||
{
|
||||
case XENMAPSPACE_grant_table:
|
||||
- rc = gnttab_map_frame(d, idx, gfn, &mfn);
|
||||
+ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
- /* Need to take care of the reference obtained in gnttab_map_frame(). */
|
||||
- page = mfn_to_page(mfn);
|
||||
t = p2m_ram_rw;
|
||||
|
||||
break;
|
||||
@@ -281,10 +279,23 @@ int xenmem_add_to_physmap_one(
|
||||
* to drop the reference we took earlier. In all other cases we need to
|
||||
* drop any reference we took earlier (perhaps indirectly).
|
||||
*/
|
||||
- if ( space == XENMAPSPACE_gmfn_foreign ? rc : page != NULL )
|
||||
+ switch ( space )
|
||||
{
|
||||
+ default:
|
||||
+ if ( page )
|
||||
+ put_page(page);
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_grant_table:
|
||||
+ gnttab_map_frame_end(d, mfn);
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_gmfn_foreign:
|
||||
+ if ( !rc )
|
||||
+ break;
|
||||
ASSERT(page != NULL);
|
||||
put_page(page);
|
||||
+ break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
--- a/xen/arch/x86/mm/p2m.c
|
||||
+++ b/xen/arch/x86/mm/p2m.c
|
||||
@@ -2009,11 +2009,9 @@ int xenmem_add_to_physmap_one(
|
||||
break;
|
||||
|
||||
case XENMAPSPACE_grant_table:
|
||||
- rc = gnttab_map_frame(d, idx, gfn, &mfn);
|
||||
+ rc = gnttab_map_frame_begin(d, idx, gfn, &mfn);
|
||||
if ( rc )
|
||||
return rc;
|
||||
- /* Need to take care of the reference obtained in gnttab_map_frame(). */
|
||||
- page = mfn_to_page(mfn);
|
||||
break;
|
||||
|
||||
case XENMAPSPACE_gmfn:
|
||||
@@ -2095,19 +2093,28 @@ int xenmem_add_to_physmap_one(
|
||||
put_gfn(d, gfn_x(gfn));
|
||||
|
||||
put_both:
|
||||
- /*
|
||||
- * In the XENMAPSPACE_gmfn case, we took a ref of the gfn at the top.
|
||||
- * We also may need to transfer ownership of the page reference to our
|
||||
- * caller.
|
||||
- */
|
||||
- if ( space == XENMAPSPACE_gmfn )
|
||||
+ switch ( space )
|
||||
{
|
||||
+ case XENMAPSPACE_gmfn:
|
||||
+ /*
|
||||
+ * We took a ref of the gfn at the top. We also may need to transfer
|
||||
+ * ownership of the page reference to our caller.
|
||||
+ */
|
||||
put_gfn(d, gmfn);
|
||||
if ( !rc && extra.ppage )
|
||||
{
|
||||
*extra.ppage = page;
|
||||
page = NULL;
|
||||
}
|
||||
+ break;
|
||||
+
|
||||
+ case XENMAPSPACE_grant_table:
|
||||
+ /*
|
||||
+ * We (gnttab_map_frame_begin()) acquired a lock and took a ref of the
|
||||
+ * page underlying the MFN at the top.
|
||||
+ */
|
||||
+ gnttab_map_frame_end(d, mfn);
|
||||
+ break;
|
||||
}
|
||||
|
||||
if ( page )
|
||||
--- a/xen/common/grant_table.c
|
||||
+++ b/xen/common/grant_table.c
|
||||
@@ -4250,7 +4250,8 @@ int gnttab_acquire_resource(
|
||||
return rc;
|
||||
}
|
||||
|
||||
-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn)
|
||||
+int gnttab_map_frame_begin(
|
||||
+ struct domain *d, unsigned long idx, gfn_t gfn, mfn_t *mfn)
|
||||
{
|
||||
int rc = 0;
|
||||
struct grant_table *gt = d->grant_table;
|
||||
@@ -4288,11 +4289,19 @@ int gnttab_map_frame(struct domain *d, u
|
||||
put_page(pg);
|
||||
}
|
||||
|
||||
- grant_write_unlock(gt);
|
||||
+ if ( rc )
|
||||
+ grant_write_unlock(d->grant_table);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
+void gnttab_map_frame_end(struct domain *d, mfn_t mfn)
|
||||
+{
|
||||
+ put_page(mfn_to_page(mfn));
|
||||
+
|
||||
+ grant_write_unlock(d->grant_table);
|
||||
+}
|
||||
+
|
||||
static void gnttab_usage_print(struct domain *rd)
|
||||
{
|
||||
int first = 1;
|
||||
--- a/xen/include/xen/grant_table.h
|
||||
+++ b/xen/include/xen/grant_table.h
|
||||
@@ -60,8 +60,13 @@ int gnttab_release_mappings(struct domai
|
||||
int mem_sharing_gref_to_gfn(struct grant_table *gt, grant_ref_t ref,
|
||||
gfn_t *gfn, uint16_t *status);
|
||||
|
||||
-int gnttab_map_frame(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
- mfn_t *mfn);
|
||||
+/*
|
||||
+ * These need to be used as a pair, as the first (in the success case) returns
|
||||
+ * with a lock and page reference held which the second needs to drop.
|
||||
+ */
|
||||
+int gnttab_map_frame_begin(struct domain *d, unsigned long idx, gfn_t gfn,
|
||||
+ mfn_t *mfn);
|
||||
+void gnttab_map_frame_end(struct domain *d, mfn_t mfn);
|
||||
|
||||
unsigned int gnttab_resource_max_frames(const struct domain *d, unsigned int id);
|
||||
|
||||
@@ -100,12 +105,14 @@ static inline int mem_sharing_gref_to_gf
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
-static inline int gnttab_map_frame(struct domain *d, unsigned long idx,
|
||||
- gfn_t gfn, mfn_t *mfn)
|
||||
+static inline int gnttab_map_frame_begin(struct domain *d, unsigned long idx,
|
||||
+ gfn_t gfn, mfn_t *mfn)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+static inline void gnttab_map_frame_end(struct domain *d, mfn_t mfn) {}
|
||||
+
|
||||
static inline unsigned int gnttab_resource_max_frames(
|
||||
const struct domain *d, unsigned int id)
|
||||
{
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
From: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Subject: x86/amd: Mitigate AMD-SN-7052
|
||||
|
||||
This is XSA-490 / CVE-2025-54518.
|
||||
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
|
||||
index 1bb0766ebf13..b5bf2b732e8f 100644
|
||||
--- a/xen/arch/x86/cpu/amd.c
|
||||
+++ b/xen/arch/x86/cpu/amd.c
|
||||
@@ -1116,11 +1116,25 @@ static void amd_check_bp_cfg(void)
|
||||
{
|
||||
uint64_t val, new = 0;
|
||||
|
||||
- /*
|
||||
- * AMD Erratum #1485. Set bit 5, as instructed.
|
||||
- */
|
||||
- if (!cpu_has_hypervisor && boot_cpu_data.x86 == 0x19 && is_zen4_uarch())
|
||||
- new |= (1 << 5);
|
||||
+ if (!cpu_has_hypervisor) {
|
||||
+ /*
|
||||
+ * AMD Erratum #1485. If SMT is enabled and STIBP disabled,
|
||||
+ * the CPU may fetch incorrect instruction bytes.
|
||||
+ *
|
||||
+ * Set bit 5, as instructed.
|
||||
+ */
|
||||
+ if (boot_cpu_data.x86 == 0x19 && is_zen4_uarch())
|
||||
+ new |= (1 << 5);
|
||||
+
|
||||
+ /*
|
||||
+ * AMD SB-7052. CPU OP Cache corruption, causing instructions
|
||||
+ * to be executed at a higher privilege.
|
||||
+ *
|
||||
+ * Set bit 33, as instructed.
|
||||
+ */
|
||||
+ if (boot_cpu_data.x86 == 0x17 && is_zen2_uarch())
|
||||
+ new |= (1UL << 33);
|
||||
+ }
|
||||
|
||||
/*
|
||||
* On hardware supporting SRSO_MSR_FIX, activate BP_SPEC_REDUCE by
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/HVM: add locking to I/O port translation list traversal
|
||||
|
||||
XEN_DOMCTL_ioport_mapping is usable by DM stubdoms, and hence we can't
|
||||
assume the list to be left unaltered while the guest (really: the
|
||||
hypervisor on behalf of the guest) is accessing it.
|
||||
|
||||
This is XSA-491 / CVE-2026-42487.
|
||||
|
||||
Fixes: 192c4dabc344 ("domctl and p2m changes for PCI passthru")
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/x86/domctl.c
|
||||
+++ b/xen/arch/x86/domctl.c
|
||||
@@ -663,6 +663,7 @@ long arch_do_domctl(
|
||||
"ioport_map:add: dom%d gport=%x mport=%x nr=%x\n",
|
||||
d->domain_id, fgp, fmp, np);
|
||||
|
||||
+ write_lock(&hvm->g2m_ioport_lock);
|
||||
list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list)
|
||||
if (g2m_ioport->mport == fmp )
|
||||
{
|
||||
@@ -684,11 +685,14 @@ long arch_do_domctl(
|
||||
g2m_ioport->np = np;
|
||||
list_add_tail(&g2m_ioport->list, &hvm->g2m_ioport_list);
|
||||
}
|
||||
+ write_unlock(&hvm->g2m_ioport_lock);
|
||||
if ( !ret )
|
||||
ret = ioports_permit_access(d, fmp, fmp + np - 1);
|
||||
if ( ret && !found && g2m_ioport )
|
||||
{
|
||||
+ write_lock(&hvm->g2m_ioport_lock);
|
||||
list_del(&g2m_ioport->list);
|
||||
+ write_unlock(&hvm->g2m_ioport_lock);
|
||||
xfree(g2m_ioport);
|
||||
}
|
||||
}
|
||||
@@ -697,6 +701,8 @@ long arch_do_domctl(
|
||||
printk(XENLOG_G_INFO
|
||||
"ioport_map:remove: dom%d gport=%x mport=%x nr=%x\n",
|
||||
d->domain_id, fgp, fmp, np);
|
||||
+
|
||||
+ write_lock(&hvm->g2m_ioport_lock);
|
||||
list_for_each_entry(g2m_ioport, &hvm->g2m_ioport_list, list)
|
||||
if ( g2m_ioport->mport == fmp )
|
||||
{
|
||||
@@ -704,6 +710,8 @@ long arch_do_domctl(
|
||||
xfree(g2m_ioport);
|
||||
break;
|
||||
}
|
||||
+ write_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
ret = ioports_deny_access(d, fmp, fmp + np - 1);
|
||||
if ( ret && is_hardware_domain(currd) )
|
||||
printk(XENLOG_ERR
|
||||
--- a/xen/arch/x86/hvm/emulate.c
|
||||
+++ b/xen/arch/x86/hvm/emulate.c
|
||||
@@ -160,7 +160,6 @@ void hvmemul_cancel(struct vcpu *v)
|
||||
hvio->mmio_insn_bytes = 0;
|
||||
hvio->mmio_access = (struct npfec){};
|
||||
hvio->mmio_retry = false;
|
||||
- hvio->g2m_ioport = NULL;
|
||||
|
||||
hvmemul_cache_disable(v);
|
||||
}
|
||||
--- a/xen/arch/x86/hvm/hvm.c
|
||||
+++ b/xen/arch/x86/hvm/hvm.c
|
||||
@@ -610,6 +610,7 @@ int hvm_domain_initialise(struct domain
|
||||
spin_lock_init(&d->arch.hvm.irq_lock);
|
||||
spin_lock_init(&d->arch.hvm.uc_lock);
|
||||
spin_lock_init(&d->arch.hvm.write_map.lock);
|
||||
+ rwlock_init(&d->arch.hvm.g2m_ioport_lock);
|
||||
rwlock_init(&d->arch.hvm.mmcfg_lock);
|
||||
INIT_LIST_HEAD(&d->arch.hvm.write_map.list);
|
||||
INIT_LIST_HEAD(&d->arch.hvm.g2m_ioport_list);
|
||||
--- a/xen/arch/x86/hvm/io.c
|
||||
+++ b/xen/arch/x86/hvm/io.c
|
||||
@@ -143,36 +143,56 @@ bool handle_pio(uint16_t port, unsigned
|
||||
return true;
|
||||
}
|
||||
|
||||
-static bool cf_check g2m_portio_accept(
|
||||
- const struct hvm_io_handler *handler, const ioreq_t *p)
|
||||
+/* NB: Returns with the lock held in the success case. */
|
||||
+static const struct g2m_ioport *g2m_portio_find_and_lock(struct hvm_domain *hvm,
|
||||
+ uint64_t addr,
|
||||
+ uint32_t size)
|
||||
{
|
||||
- struct vcpu *curr = current;
|
||||
- const struct hvm_domain *hvm = &curr->domain->arch.hvm;
|
||||
- struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io;
|
||||
- struct g2m_ioport *g2m_ioport;
|
||||
- unsigned int start, end;
|
||||
+ const struct g2m_ioport *g2m_ioport;
|
||||
+
|
||||
+ read_lock(&hvm->g2m_ioport_lock);
|
||||
|
||||
list_for_each_entry( g2m_ioport, &hvm->g2m_ioport_list, list )
|
||||
{
|
||||
- start = g2m_ioport->gport;
|
||||
- end = start + g2m_ioport->np;
|
||||
- if ( (p->addr >= start) && (p->addr + p->size <= end) )
|
||||
- {
|
||||
- hvio->g2m_ioport = g2m_ioport;
|
||||
- return 1;
|
||||
- }
|
||||
+ unsigned int start = g2m_ioport->gport;
|
||||
+
|
||||
+ if ( addr >= start && addr + size <= start + g2m_ioport->np )
|
||||
+ return g2m_ioport;
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static bool cf_check g2m_portio_accept(
|
||||
+ const struct hvm_io_handler *handler, const ioreq_t *p)
|
||||
+{
|
||||
+ struct hvm_domain *hvm = ¤t->domain->arch.hvm;
|
||||
+ const struct g2m_ioport *g2m_ioport =
|
||||
+ g2m_portio_find_and_lock(hvm, p->addr, p->size);
|
||||
+
|
||||
+ if ( !g2m_ioport )
|
||||
+ return false;
|
||||
+
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
+ return true;
|
||||
}
|
||||
|
||||
static int cf_check g2m_portio_read(
|
||||
const struct hvm_io_handler *handler, uint64_t addr, uint32_t size,
|
||||
uint64_t *data)
|
||||
{
|
||||
- struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io;
|
||||
- const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport;
|
||||
- unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport;
|
||||
+ struct hvm_domain *hvm = ¤t->domain->arch.hvm;
|
||||
+ const struct g2m_ioport *g2m_ioport =
|
||||
+ g2m_portio_find_and_lock(hvm, addr, size);
|
||||
+ unsigned int mport;
|
||||
+
|
||||
+ if ( !g2m_ioport )
|
||||
+ return X86EMUL_RETRY;
|
||||
+
|
||||
+ mport = addr - g2m_ioport->gport + g2m_ioport->mport;
|
||||
|
||||
switch ( size )
|
||||
{
|
||||
@@ -189,6 +209,8 @@ static int cf_check g2m_portio_read(
|
||||
BUG();
|
||||
}
|
||||
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
@@ -196,9 +218,15 @@ static int cf_check g2m_portio_write(
|
||||
const struct hvm_io_handler *handler, uint64_t addr, uint32_t size,
|
||||
uint64_t data)
|
||||
{
|
||||
- struct hvm_vcpu_io *hvio = ¤t->arch.hvm.hvm_io;
|
||||
- const struct g2m_ioport *g2m_ioport = hvio->g2m_ioport;
|
||||
- unsigned int mport = (addr - g2m_ioport->gport) + g2m_ioport->mport;
|
||||
+ struct hvm_domain *hvm = ¤t->domain->arch.hvm;
|
||||
+ const struct g2m_ioport *g2m_ioport =
|
||||
+ g2m_portio_find_and_lock(hvm, addr, size);
|
||||
+ unsigned int mport;
|
||||
+
|
||||
+ if ( !g2m_ioport )
|
||||
+ return X86EMUL_RETRY;
|
||||
+
|
||||
+ mport = addr - g2m_ioport->gport + g2m_ioport->mport;
|
||||
|
||||
switch ( size )
|
||||
{
|
||||
@@ -215,6 +243,8 @@ static int cf_check g2m_portio_write(
|
||||
BUG();
|
||||
}
|
||||
|
||||
+ read_unlock(&hvm->g2m_ioport_lock);
|
||||
+
|
||||
return X86EMUL_OKAY;
|
||||
}
|
||||
|
||||
--- a/xen/arch/x86/include/asm/hvm/domain.h
|
||||
+++ b/xen/arch/x86/include/asm/hvm/domain.h
|
||||
@@ -125,6 +125,7 @@ struct hvm_domain {
|
||||
|
||||
/* List of guest to machine IO ports mapping. */
|
||||
struct list_head g2m_ioport_list;
|
||||
+ rwlock_t g2m_ioport_lock;
|
||||
|
||||
/* List of MMCFG regions trapped by Xen. */
|
||||
struct list_head mmcfg_regions;
|
||||
--- a/xen/arch/x86/include/asm/hvm/vcpu.h
|
||||
+++ b/xen/arch/x86/include/asm/hvm/vcpu.h
|
||||
@@ -54,8 +54,6 @@ struct hvm_vcpu_io {
|
||||
unsigned long msix_unmask_address;
|
||||
unsigned long msix_snoop_address;
|
||||
unsigned long msix_snoop_gpa;
|
||||
-
|
||||
- const struct g2m_ioport *g2m_ioport;
|
||||
};
|
||||
|
||||
struct nestedvcpu {
|
||||
|
|
@ -1,264 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: sched: use sequence counter to enlighten vcpu_runstate_get()
|
||||
|
||||
Subsequently XEN_DOMCTL_getdomaininfo will want to invoke the function
|
||||
without holding a lock, thus allowing parallel execution of potentially
|
||||
many instances. As was learned from 228ab9992ffb ("domctl: improve
|
||||
locking during domain destruction"), reverted by d0887cc6b16e, such
|
||||
parallelism can result in severe lock contention on any (previously)
|
||||
inner lock. To avoid taking that risk replace the use of the scheduler
|
||||
lock in vcpu_runstate_get() by a newly introduced sequence counter.
|
||||
Convert the "no lock if current" property to "use a local counter
|
||||
instance", thus guaranteeing the loop to exit after the first iteration.
|
||||
|
||||
Skeleton and commentary of the seqcount implementation based on /
|
||||
derived from Linux 6.11-rc.
|
||||
|
||||
To have runstate_seq placed next to runstate in struct vcpu, without
|
||||
introducing a new obvious padding hole, yet while keeping the latter
|
||||
adjacent to runstate_guest{,_area} as well, move runstate down a little.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Requested-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Juergen Gross <jgross@suse.com>
|
||||
|
||||
--- a/xen/common/sched/core.c
|
||||
+++ b/xen/common/sched/core.c
|
||||
@@ -281,13 +281,18 @@ static inline void vcpu_runstate_change(
|
||||
}
|
||||
|
||||
delta = new_entry_time - v->runstate.state_entry_time;
|
||||
- if ( delta > 0 )
|
||||
+
|
||||
+ /* Serialization: ->schedule_lock (see ASSERT() above). */
|
||||
+ with_seq_write(&v->runstate_seq)
|
||||
{
|
||||
- v->runstate.time[v->runstate.state] += delta;
|
||||
- v->runstate.state_entry_time = new_entry_time;
|
||||
- }
|
||||
+ if ( delta > 0 )
|
||||
+ {
|
||||
+ v->runstate.time[v->runstate.state] += delta;
|
||||
+ v->runstate.state_entry_time = new_entry_time;
|
||||
+ }
|
||||
|
||||
- v->runstate.state = new_state;
|
||||
+ v->runstate.state = new_state;
|
||||
+ }
|
||||
}
|
||||
|
||||
void sched_guest_idle(void (*idle) (void), unsigned int cpu)
|
||||
@@ -307,30 +312,18 @@ void sched_guest_idle(void (*idle) (void
|
||||
void vcpu_runstate_get(const struct vcpu *v,
|
||||
struct vcpu_runstate_info *runstate)
|
||||
{
|
||||
- spinlock_t *lock;
|
||||
- s_time_t delta;
|
||||
- struct sched_unit *unit;
|
||||
+ struct seqcount seq = SEQCNT_ZERO();
|
||||
+ const struct seqcount *s = likely(v == current) ? &seq : &v->runstate_seq;
|
||||
|
||||
- rcu_read_lock(&sched_res_rculock);
|
||||
-
|
||||
- /*
|
||||
- * Be careful in case of an idle vcpu: the assignment to a unit might
|
||||
- * change even with the scheduling lock held, so be sure to use the
|
||||
- * correct unit for locking in order to avoid triggering an ASSERT() in
|
||||
- * the unlock function.
|
||||
- */
|
||||
- unit = is_idle_vcpu(v) ? get_sched_res(v->processor)->sched_unit_idle
|
||||
- : v->sched_unit;
|
||||
- lock = likely(v == current) ? NULL : unit_schedule_lock_irq(unit);
|
||||
- memcpy(runstate, &v->runstate, sizeof(*runstate));
|
||||
- delta = NOW() - runstate->state_entry_time;
|
||||
- if ( delta > 0 )
|
||||
- runstate->time[runstate->state] += delta;
|
||||
-
|
||||
- if ( unlikely(lock != NULL) )
|
||||
- unit_schedule_unlock_irq(lock, unit);
|
||||
+ until_seq_read(s)
|
||||
+ {
|
||||
+ s_time_t delta;
|
||||
|
||||
- rcu_read_unlock(&sched_res_rculock);
|
||||
+ *runstate = v->runstate;
|
||||
+ delta = NOW() - runstate->state_entry_time;
|
||||
+ if ( delta > 0 )
|
||||
+ runstate->time[runstate->state] += delta;
|
||||
+ }
|
||||
}
|
||||
|
||||
uint64_t get_cpu_idle_time(unsigned int cpu)
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xen/radix-tree.h>
|
||||
#include <xen/multicall.h>
|
||||
#include <xen/nospec.h>
|
||||
+#include <xen/seqcount.h>
|
||||
#include <xen/tasklet.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/smp.h>
|
||||
@@ -198,7 +199,6 @@ struct vcpu
|
||||
|
||||
struct sched_unit *sched_unit;
|
||||
|
||||
- struct vcpu_runstate_info runstate;
|
||||
#ifndef CONFIG_COMPAT
|
||||
# define runstate_guest(v) ((v)->runstate_guest)
|
||||
XEN_GUEST_HANDLE(vcpu_runstate_info_t) runstate_guest; /* guest address */
|
||||
@@ -210,6 +210,8 @@ struct vcpu
|
||||
} runstate_guest; /* guest address */
|
||||
#endif
|
||||
struct guest_area runstate_guest_area;
|
||||
+ struct vcpu_runstate_info runstate;
|
||||
+ struct seqcount runstate_seq;
|
||||
unsigned int new_state;
|
||||
|
||||
/* Has the FPU been initialised? */
|
||||
--- /dev/null
|
||||
+++ b/xen/include/xen/seqcount.h
|
||||
@@ -0,0 +1,139 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+#ifndef XEN_SEQCOUNT_H
|
||||
+#define XEN_SEQCOUNT_H
|
||||
+
|
||||
+#include <xen/lib.h>
|
||||
+#include <xen/nospec.h>
|
||||
+
|
||||
+#include <asm/atomic.h>
|
||||
+#include <asm/system.h>
|
||||
+
|
||||
+/*
|
||||
+ * Sequence counters (seqcount_t)
|
||||
+ *
|
||||
+ * This is the raw counting mechanism, without any writer protection.
|
||||
+ *
|
||||
+ * Write side critical sections must be serialized (and non-preemptible).
|
||||
+ *
|
||||
+ * If readers can be invoked from interrupt contexts, interrupts must also
|
||||
+ * be respectively disabled before entering the write section.
|
||||
+ *
|
||||
+ * This mechanism can't be used if the protected data contains pointers,
|
||||
+ * as the writer can invalidate a pointer that a reader is following.
|
||||
+ */
|
||||
+struct seqcount {
|
||||
+ unsigned int sequence;
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * SEQCNT_ZERO() - initializer for seqcount_t
|
||||
+ * @name: Name of the struct seqcount instance
|
||||
+ */
|
||||
+#define SEQCNT_ZERO() { .sequence = 0 }
|
||||
+
|
||||
+static inline unsigned int seqprop_sequence(const struct seqcount *s)
|
||||
+{
|
||||
+ return ACCESS_ONCE(s->sequence);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * read_seqcount_begin() - begin a seqcount read critical section
|
||||
+ * @s: Pointer to struct seqcount
|
||||
+ *
|
||||
+ * Return: count to be passed to read_seqcount_retry()
|
||||
+ */
|
||||
+static inline unsigned int _read_seqcount_begin(const struct seqcount *s)
|
||||
+{
|
||||
+ unsigned int seq;
|
||||
+
|
||||
+ while ((seq = seqprop_sequence(s)) & 1)
|
||||
+ cpu_relax();
|
||||
+
|
||||
+ smp_rmb();
|
||||
+
|
||||
+ return seq;
|
||||
+}
|
||||
+
|
||||
+static always_inline unsigned int read_seqcount_begin(const struct seqcount *s)
|
||||
+{
|
||||
+ unsigned int seq = _read_seqcount_begin(s);
|
||||
+
|
||||
+ block_lock_speculation();
|
||||
+
|
||||
+ return seq;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * read_seqcount_retry() - end a seqcount read critical section
|
||||
+ * @s: Pointer to struct seqcount
|
||||
+ * @start: count, from read_seqcount_begin()
|
||||
+ *
|
||||
+ * read_seqcount_retry closes the read critical section of given struct
|
||||
+ * seqcount. If the critical section was invalid, it must be ignored
|
||||
+ * (and typically retried).
|
||||
+ *
|
||||
+ * Return: true if a read section retry is required, else false
|
||||
+ */
|
||||
+static inline bool _read_seqcount_retry(const struct seqcount *s,
|
||||
+ unsigned int start)
|
||||
+{
|
||||
+ smp_rmb();
|
||||
+ return unlikely(seqprop_sequence(s) != start);
|
||||
+}
|
||||
+
|
||||
+static always_inline bool read_seqcount_retry(const struct seqcount *s,
|
||||
+ unsigned int start)
|
||||
+{
|
||||
+ return lock_evaluate_nospec(_read_seqcount_retry(s, start));
|
||||
+}
|
||||
+
|
||||
+/* Loops until a consistent count has been observed across the loop body. */
|
||||
+#define until_seq_read(seq) \
|
||||
+ for ( unsigned int retry_ = 1, count_; \
|
||||
+ retry_ && (count_ = read_seqcount_begin(seq), true); \
|
||||
+ retry_ = read_seqcount_retry(seq, count_) )
|
||||
+
|
||||
+/*
|
||||
+ * write_seqcount_begin() - start a struct seqcount write side critical section
|
||||
+ * @s: Pointer to struct seqcount
|
||||
+ *
|
||||
+ * Context: sequence counter write side sections must be serialized.
|
||||
+ * If readers can be invoked from interrupt context, interrupts must be
|
||||
+ * respectively disabled.
|
||||
+ */
|
||||
+static inline void write_seqcount_begin(struct seqcount *s)
|
||||
+{
|
||||
+ add_sized(&s->sequence, 1);
|
||||
+ smp_wmb();
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * write_seqcount_end() - end a struct seqcount write side critical section
|
||||
+ * @s: Pointer to seqcount
|
||||
+ */
|
||||
+static inline void write_seqcount_end(struct seqcount *s)
|
||||
+{
|
||||
+ smp_wmb();
|
||||
+ add_sized(&s->sequence, 1);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Not really a loop, but we need write_seqcount_{begin,end}() in the correct
|
||||
+ * position.
|
||||
+ */
|
||||
+#define with_seq_write(seq) \
|
||||
+ for ( bool once_ = true; \
|
||||
+ once_ && (write_seqcount_begin(seq), true); \
|
||||
+ (write_seqcount_end(seq), once_ = false) )
|
||||
+
|
||||
+#endif /* XEN_SEQCOUNT_H */
|
||||
+
|
||||
+/*
|
||||
+ * Local variables:
|
||||
+ * mode: C
|
||||
+ * c-file-style: "BSD"
|
||||
+ * c-basic-offset: 4
|
||||
+ * tab-width: 4
|
||||
+ * indent-tabs-mode: nil
|
||||
+ * End:
|
||||
+ */
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domctl: handle XEN_DOMCTL_getdomaininfo without acquiring domctl lock
|
||||
|
||||
getdomaininfo() is not called under consistently the same lock. Thus,
|
||||
with caller side locking irrelevant, it can as well be called with the
|
||||
domctl lock not held. (Callers not pausing the domain they want to
|
||||
retrieve information for already need to be aware that not all of the
|
||||
data returned can be relied on as being consistent; most data will also
|
||||
be stale by the time the caller gets to look at it.)
|
||||
|
||||
Move the handling not only ahead of acquiring the lock, but also ahead
|
||||
of the XSM check, leveraging that the sub-op has its own hook.
|
||||
|
||||
While moving, convert an assignment to an assertion: The domain in
|
||||
question was determined from the field which previously was "updated".
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Fixes: 5513bd0b4675 ("add xenstore domain flag to hypervisor")
|
||||
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -318,6 +318,26 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* Handle sub-ops not requiring the domctl lock. */
|
||||
+ switch ( op->cmd )
|
||||
+ {
|
||||
+ case XEN_DOMCTL_getdomaininfo:
|
||||
+ ret = xsm_getdomaininfo(XSM_XS_PRIV, d);
|
||||
+ if ( !ret )
|
||||
+ {
|
||||
+ getdomaininfo(d, &op->u.getdomaininfo);
|
||||
+
|
||||
+ ASSERT(op->domain == op->u.getdomaininfo.domain);
|
||||
+ copyback = true;
|
||||
+ }
|
||||
+
|
||||
+ goto domctl_out_unlock_domonly;
|
||||
+
|
||||
+ default:
|
||||
+ /* Everything else handled further down. */
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
ret = xsm_domctl(XSM_OTHER, d, op->cmd,
|
||||
/* SSIDRef only applicable for cmd == createdomain */
|
||||
op->u.createdomain.ssidref);
|
||||
@@ -516,17 +536,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
copyback = 1;
|
||||
break;
|
||||
|
||||
- case XEN_DOMCTL_getdomaininfo:
|
||||
- ret = xsm_getdomaininfo(XSM_XS_PRIV, d);
|
||||
- if ( ret )
|
||||
- break;
|
||||
-
|
||||
- getdomaininfo(d, &op->u.getdomaininfo);
|
||||
-
|
||||
- op->domain = op->u.getdomaininfo.domain;
|
||||
- copyback = 1;
|
||||
- break;
|
||||
-
|
||||
case XEN_DOMCTL_getvcpucontext:
|
||||
{
|
||||
vcpu_guest_context_u c = { .nat = NULL };
|
||||
--- a/xen/include/xsm/dummy.h
|
||||
+++ b/xen/include/xsm/dummy.h
|
||||
@@ -172,9 +172,13 @@ static XSM_INLINE int cf_check xsm_domct
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
case XEN_DOMCTL_unbind_pt_irq:
|
||||
return xsm_default_action(XSM_DM_PRIV, current->domain, d);
|
||||
- case XEN_DOMCTL_getdomaininfo:
|
||||
case XEN_DOMCTL_get_domain_state:
|
||||
return xsm_default_action(XSM_XS_PRIV, current->domain, d);
|
||||
+
|
||||
+ case XEN_DOMCTL_getdomaininfo:
|
||||
+ ASSERT_UNREACHABLE();
|
||||
+ return -EILSEQ;
|
||||
+
|
||||
default:
|
||||
return xsm_default_action(XSM_PRIV, current->domain, d);
|
||||
}
|
||||
--- a/xen/xsm/flask/hooks.c
|
||||
+++ b/xen/xsm/flask/hooks.c
|
||||
@@ -682,8 +682,12 @@ static int cf_check flask_domctl(struct
|
||||
*/
|
||||
return avc_current_has_perm(ssidref, SECCLASS_DOMAIN, DOMAIN__CREATE, NULL);
|
||||
|
||||
- /* These have individual XSM hooks (common/domctl.c) */
|
||||
+ /* These have individual XSM hooks and don't make it here. */
|
||||
case XEN_DOMCTL_getdomaininfo:
|
||||
+ ASSERT_UNREACHABLE();
|
||||
+ return -EILSEQ;
|
||||
+
|
||||
+ /* These have individual XSM hooks (common/domctl.c) */
|
||||
case XEN_DOMCTL_scheduler_op:
|
||||
case XEN_DOMCTL_irq_permission:
|
||||
case XEN_DOMCTL_iomem_permission:
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
From: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Subject: domctl: protect locking for get_domain_state
|
||||
|
||||
When DOMID_INVALID is passed, the dom exec handler lock is being taken
|
||||
without any check that the domain is even allowed to take the lock. This
|
||||
allows for an unauthorized domain to DoS the get_domain_state domctl op.
|
||||
Move to consider the op effectively being called against the hypervisor.
|
||||
Thus it is the target of the call being invoked to identify the last
|
||||
domain with a state change. The subsequent check of whether the source
|
||||
domain is allowed the state of the last domain to change state is still
|
||||
relevant.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/tools/flask/policy/modules/xenstore.te
|
||||
+++ b/tools/flask/policy/modules/xenstore.te
|
||||
@@ -14,6 +14,7 @@ allow xenstore_t xen_t:xen writeconsole;
|
||||
# Xenstore queries domaininfo on all domains
|
||||
allow xenstore_t domain_type:domain getdomaininfo;
|
||||
allow xenstore_t domain_type:domain2 get_domain_state;
|
||||
+allow xenstore_t domxen_t:domain2 get_domain_state;
|
||||
|
||||
# As a shortcut, the following 3 rules are used instead of adding a domain_comms
|
||||
# rule between xenstore_t and every domain type that talks to xenstore
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -216,12 +216,8 @@ int get_domain_state(struct xen_domctl_g
|
||||
if ( info->pad0 )
|
||||
return -EINVAL;
|
||||
|
||||
- if ( d )
|
||||
+ if ( d != dom_xen )
|
||||
{
|
||||
- rc = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
- if ( rc )
|
||||
- return rc;
|
||||
-
|
||||
set_domain_state_info(info, d);
|
||||
|
||||
return 0;
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -304,13 +304,19 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
fallthrough;
|
||||
case XEN_DOMCTL_test_assign_device:
|
||||
case XEN_DOMCTL_vm_event_op:
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
if ( op->domain == DOMID_INVALID )
|
||||
{
|
||||
d = NULL;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
+ if ( op->domain == DOMID_INVALID )
|
||||
+ {
|
||||
+ d = dom_xen;
|
||||
+ break;
|
||||
+ }
|
||||
+ fallthrough;
|
||||
default:
|
||||
d = rcu_lock_domain_by_id(op->domain);
|
||||
if ( !d )
|
||||
@@ -863,7 +869,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_get_domain_state:
|
||||
- ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
+ ret = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
+ if ( !ret )
|
||||
+ ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
if ( !ret )
|
||||
copyback = true;
|
||||
break;
|
||||
@@ -876,7 +884,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
domctl_lock_release();
|
||||
|
||||
domctl_out_unlock_domonly:
|
||||
- if ( d && d != dom_io )
|
||||
+ if ( d && !is_system_domain(d) )
|
||||
rcu_unlock_domain(d);
|
||||
|
||||
if ( copyback && __copy_to_guest(u_domctl, op, 1) )
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domctl: handle XEN_DOMCTL_get_domain_state without acquiring domctl lock
|
||||
|
||||
get_domain_state() uses its own locking. Thus, with caller side locking
|
||||
irrelevant, it can as well be called with the domctl lock not held.
|
||||
|
||||
Move the handling not only ahead of acquiring the lock, but also ahead
|
||||
of the XSM check, leveraging that the sub-op has its own hook.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Fixes: 3ad3df1bd0aa ("xen: add new domctl get_domain_state")
|
||||
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -339,6 +339,14 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
|
||||
goto domctl_out_unlock_domonly;
|
||||
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
+ ret = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
+ if ( !ret )
|
||||
+ ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
+ if ( !ret )
|
||||
+ copyback = true;
|
||||
+ goto domctl_out_unlock_domonly;
|
||||
+
|
||||
default:
|
||||
/* Everything else handled further down. */
|
||||
break;
|
||||
@@ -868,14 +876,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
- ret = xsm_get_domain_state(XSM_XS_PRIV, d);
|
||||
- if ( !ret )
|
||||
- ret = get_domain_state(&op->u.get_domain_state, d, &op->domain);
|
||||
- if ( !ret )
|
||||
- copyback = true;
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
ret = arch_do_domctl(op, d, u_domctl);
|
||||
break;
|
||||
--- a/xen/include/xsm/dummy.h
|
||||
+++ b/xen/include/xsm/dummy.h
|
||||
@@ -172,10 +172,9 @@ static XSM_INLINE int cf_check xsm_domct
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
case XEN_DOMCTL_unbind_pt_irq:
|
||||
return xsm_default_action(XSM_DM_PRIV, current->domain, d);
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
- return xsm_default_action(XSM_XS_PRIV, current->domain, d);
|
||||
|
||||
case XEN_DOMCTL_getdomaininfo:
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
ASSERT_UNREACHABLE();
|
||||
return -EILSEQ;
|
||||
|
||||
--- a/xen/xsm/flask/hooks.c
|
||||
+++ b/xen/xsm/flask/hooks.c
|
||||
@@ -684,6 +684,7 @@ static int cf_check flask_domctl(struct
|
||||
|
||||
/* These have individual XSM hooks and don't make it here. */
|
||||
case XEN_DOMCTL_getdomaininfo:
|
||||
+ case XEN_DOMCTL_get_domain_state:
|
||||
ASSERT_UNREACHABLE();
|
||||
return -EILSEQ;
|
||||
|
||||
@@ -694,7 +695,6 @@ static int cf_check flask_domctl(struct
|
||||
case XEN_DOMCTL_memory_mapping:
|
||||
case XEN_DOMCTL_set_target:
|
||||
case XEN_DOMCTL_vm_event_op:
|
||||
- case XEN_DOMCTL_get_domain_state:
|
||||
|
||||
/* These have individual XSM hooks (arch/../domctl.c) */
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domain: locking for iomem_caps accesses
|
||||
|
||||
In order to be able to pull at least the XEN_DOMCTL_iomem_mapping handling
|
||||
out of the domctl-locked region, a separate (per-domain) lock is needed to
|
||||
synchronize in particular with XEN_DOMCTL_iomem_permission.
|
||||
|
||||
Locking is added only as far as domctl-s are affected. Uses presently
|
||||
outside of the domctl lock may want dealing with subsequently (perhaps
|
||||
limited to non-__init code).
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/common/domain.c
|
||||
+++ b/xen/common/domain.c
|
||||
@@ -518,10 +518,15 @@ static int late_hwdom_init(struct domain
|
||||
* may be modified after this hypercall returns if a more complex
|
||||
* device model is desired.
|
||||
*/
|
||||
+ write_lock(&dom0->caps_lock);
|
||||
rangeset_swap(d->irq_caps, dom0->irq_caps);
|
||||
rangeset_swap(d->iomem_caps, dom0->iomem_caps);
|
||||
#ifdef CONFIG_X86
|
||||
rangeset_swap(d->arch.ioport_caps, dom0->arch.ioport_caps);
|
||||
+#endif
|
||||
+ write_unlock(&dom0->caps_lock);
|
||||
+
|
||||
+#ifdef CONFIG_X86
|
||||
setup_io_bitmap(d);
|
||||
setup_io_bitmap(dom0);
|
||||
#endif
|
||||
@@ -873,6 +878,7 @@ struct domain *domain_create(domid_t dom
|
||||
rspin_lock_init_prof(d, domain_lock);
|
||||
rspin_lock_init_prof(d, page_alloc_lock);
|
||||
spin_lock_init(&d->hypercall_deadlock_mutex);
|
||||
+ rwlock_init(&d->caps_lock);
|
||||
INIT_PAGE_LIST_HEAD(&d->page_list);
|
||||
INIT_PAGE_LIST_HEAD(&d->extra_page_list);
|
||||
INIT_PAGE_LIST_HEAD(&d->xenpage_list);
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -267,6 +267,35 @@ static struct vnuma_info *vnuma_init(con
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
+void iocaps_double_lock(struct domain *d, bool write)
|
||||
+{
|
||||
+ struct domain *currd = current->domain;
|
||||
+
|
||||
+ if ( d->domain_id > currd->domain_id )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( write )
|
||||
+ write_lock(&d->caps_lock);
|
||||
+ else
|
||||
+ read_lock(&d->caps_lock);
|
||||
+
|
||||
+ if ( d->domain_id < currd->domain_id )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+}
|
||||
+
|
||||
+void iocaps_double_unlock(struct domain *d, bool write)
|
||||
+{
|
||||
+ struct domain *currd = current->domain;
|
||||
+
|
||||
+ if ( d != currd )
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( write )
|
||||
+ write_unlock(&d->caps_lock);
|
||||
+ else
|
||||
+ read_unlock(&d->caps_lock);
|
||||
+}
|
||||
+
|
||||
static bool is_stable_domctl(uint32_t cmd)
|
||||
{
|
||||
return cmd == XEN_DOMCTL_get_domain_state;
|
||||
@@ -687,6 +716,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
if ( (mfn + nr_mfns - 1) < mfn ) /* wrap? */
|
||||
break;
|
||||
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
if ( !iomem_access_permitted(current->domain,
|
||||
mfn, mfn + nr_mfns - 1) ||
|
||||
xsm_iomem_permission(XSM_HOOK, d, mfn, mfn + nr_mfns - 1, allow) )
|
||||
@@ -695,6 +726,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = iomem_permit_access(d, mfn, mfn + nr_mfns - 1);
|
||||
else
|
||||
ret = iomem_deny_access(d, mfn, mfn + nr_mfns - 1);
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -719,19 +752,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
break;
|
||||
#endif
|
||||
|
||||
+ iocaps_double_lock(d, false);
|
||||
+
|
||||
ret = -EPERM;
|
||||
if ( !iomem_access_permitted(current->domain, mfn, mfn_end) ||
|
||||
- !iomem_access_permitted(d, mfn, mfn_end) )
|
||||
- break;
|
||||
-
|
||||
- ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add);
|
||||
- if ( ret )
|
||||
- break;
|
||||
-
|
||||
- if ( !paging_mode_translate(d) )
|
||||
- break;
|
||||
-
|
||||
- if ( add )
|
||||
+ !iomem_access_permitted(d, mfn, mfn_end) ||
|
||||
+ (ret = xsm_iomem_mapping(XSM_HOOK, d, mfn, mfn_end, add)) ||
|
||||
+ !paging_mode_translate(d) )
|
||||
+ /* Nothing. */;
|
||||
+ else if ( add )
|
||||
{
|
||||
printk(XENLOG_G_DEBUG
|
||||
"memory_map:add: dom%d gfn=%lx mfn=%lx nr=%lx\n",
|
||||
@@ -755,6 +784,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
"memory_map: error %ld removing dom%d access to [%lx,%lx]\n",
|
||||
ret, d->domain_id, mfn, mfn_end);
|
||||
}
|
||||
+
|
||||
+ iocaps_double_unlock(d, false);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/include/xen/iocap.h
|
||||
+++ b/xen/include/xen/iocap.h
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <asm/iocap.h>
|
||||
#include <asm/p2m.h>
|
||||
|
||||
+void iocaps_double_lock(struct domain *d, bool write);
|
||||
+void iocaps_double_unlock(struct domain *d, bool write);
|
||||
+
|
||||
static inline int iomem_permit_access(struct domain *d, unsigned long s,
|
||||
unsigned long e)
|
||||
{
|
||||
--- a/xen/include/xen/sched.h
|
||||
+++ b/xen/include/xen/sched.h
|
||||
@@ -536,6 +536,7 @@ struct domain
|
||||
#endif
|
||||
|
||||
/* I/O capabilities (access to IRQs and memory-mapped I/O). */
|
||||
+ rwlock_t caps_lock;
|
||||
struct rangeset *iomem_caps;
|
||||
struct rangeset *irq_caps;
|
||||
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: x86/domain: locking for ioport_caps accesses
|
||||
|
||||
In order to be able to pull at least the XEN_DOMCTL_ioport_mapping
|
||||
handling out of the domctl-locked region, the new separate (per-domain)
|
||||
lock is used to synchronize in particular with
|
||||
XEN_DOMCTL_ioport_permission.
|
||||
|
||||
Locking is added only as far as domctl-s are affected. Uses presently
|
||||
outside of the domctl lock may want dealing with subsequently (perhaps
|
||||
limited to non-__init code).
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
|
||||
--- a/xen/arch/x86/domctl.c
|
||||
+++ b/xen/arch/x86/domctl.c
|
||||
@@ -233,6 +233,8 @@ long arch_do_domctl(
|
||||
unsigned int np = domctl->u.ioport_permission.nr_ports;
|
||||
int allow = domctl->u.ioport_permission.allow_access;
|
||||
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
if ( (fp + np) <= fp || (fp + np) > MAX_IOPORTS )
|
||||
ret = -EINVAL;
|
||||
else if ( !ioports_access_permitted(currd, fp, fp + np - 1) ||
|
||||
@@ -242,6 +244,8 @@ long arch_do_domctl(
|
||||
ret = ioports_permit_access(d, fp, fp + np - 1);
|
||||
else
|
||||
ret = ioports_deny_access(d, fp, fp + np - 1);
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -648,16 +652,13 @@ long arch_do_domctl(
|
||||
break;
|
||||
}
|
||||
|
||||
- ret = -EPERM;
|
||||
- if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) )
|
||||
- break;
|
||||
-
|
||||
- ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add);
|
||||
- if ( ret )
|
||||
- break;
|
||||
-
|
||||
hvm = &d->arch.hvm;
|
||||
- if ( add )
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
+ if ( !ioports_access_permitted(currd, fmp, fmp + np - 1) ||
|
||||
+ (ret = xsm_ioport_mapping(XSM_HOOK, d, fmp, fmp + np - 1, add)) )
|
||||
+ ret = ret ?: -EPERM;
|
||||
+ else if ( add )
|
||||
{
|
||||
printk(XENLOG_G_INFO
|
||||
"ioport_map:add: dom%d gport=%x mport=%x nr=%x\n",
|
||||
@@ -718,6 +720,8 @@ long arch_do_domctl(
|
||||
"ioport_map: error %ld denying dom%d access to [%x,%x]\n",
|
||||
ret, d->domain_id, fmp, fmp + np - 1);
|
||||
}
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/arch/x86/setup.c
|
||||
+++ b/xen/arch/x86/setup.c
|
||||
@@ -2339,9 +2339,12 @@ void __hwdom_init setup_io_bitmap(struct
|
||||
return;
|
||||
|
||||
bitmap_fill(d->arch.hvm.io_bitmap, 0x10000);
|
||||
+
|
||||
+ read_lock(&d->caps_lock);
|
||||
if ( rangeset_report_ranges(d->arch.ioport_caps, 0, 0x10000,
|
||||
io_bitmap_cb, d) )
|
||||
BUG();
|
||||
+ read_unlock(&d->caps_lock);
|
||||
|
||||
/*
|
||||
* We need to trap 4-byte accesses to 0xcf8 (see admin_io_okay(),
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: domain: locking for irq_caps accesses
|
||||
|
||||
In order to be able to pull at least the XEN_DOMCTL_{,un}bind_pt_irq
|
||||
handling out of the domctl-locked region, a separate (per-domain) lock is
|
||||
needed to synchronize in particular with XEN_DOMCTL_{irq,gsi}_permission.
|
||||
|
||||
Locking is added only as far as domctl-s are affected. Uses presently
|
||||
outside of the domctl lock may want dealing with subsequently (perhaps
|
||||
limited to non-__init code).
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Reviewed-by: Julien Grall <julien@xen.org>
|
||||
|
||||
--- a/xen/arch/arm/domctl.c
|
||||
+++ b/xen/arch/arm/domctl.c
|
||||
@@ -76,6 +76,7 @@ long arch_do_domctl(struct xen_domctl *d
|
||||
case XEN_DOMCTL_bind_pt_irq:
|
||||
{
|
||||
int rc;
|
||||
+ struct domain *currd = current->domain;
|
||||
struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq;
|
||||
uint32_t irq = bind->u.spi.spi;
|
||||
uint32_t virq = bind->machine_irq;
|
||||
@@ -107,21 +108,26 @@ long arch_do_domctl(struct xen_domctl *d
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
- if ( !irq_access_permitted(current->domain, irq) )
|
||||
- return -EPERM;
|
||||
+ read_lock(&currd->caps_lock);
|
||||
|
||||
- if ( !vgic_reserve_virq(d, virq) )
|
||||
- return -EBUSY;
|
||||
-
|
||||
- rc = route_irq_to_guest(d, virq, irq, "routed IRQ");
|
||||
- if ( rc )
|
||||
- vgic_free_virq(d, virq);
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ rc = -EPERM;
|
||||
+ else if ( !vgic_reserve_virq(d, virq) )
|
||||
+ rc = -EBUSY;
|
||||
+ else
|
||||
+ {
|
||||
+ rc = route_irq_to_guest(d, virq, irq, "routed IRQ");
|
||||
+ if ( rc )
|
||||
+ vgic_free_virq(d, virq);
|
||||
+ }
|
||||
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
return rc;
|
||||
}
|
||||
case XEN_DOMCTL_unbind_pt_irq:
|
||||
{
|
||||
int rc;
|
||||
+ struct domain *currd = current->domain;
|
||||
struct xen_domctl_bind_pt_irq *bind = &domctl->u.bind_pt_irq;
|
||||
uint32_t irq = bind->u.spi.spi;
|
||||
uint32_t virq = bind->machine_irq;
|
||||
@@ -138,16 +144,15 @@ long arch_do_domctl(struct xen_domctl *d
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
- if ( !irq_access_permitted(current->domain, irq) )
|
||||
- return -EPERM;
|
||||
-
|
||||
- rc = release_guest_irq(d, virq);
|
||||
- if ( rc )
|
||||
- return rc;
|
||||
+ read_lock(&currd->caps_lock);
|
||||
|
||||
- vgic_free_virq(d, virq);
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ rc = -EPERM;
|
||||
+ else if ( !(rc = release_guest_irq(d, virq)) )
|
||||
+ vgic_free_virq(d, virq);
|
||||
|
||||
- return 0;
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
case XEN_DOMCTL_vuart_op:
|
||||
--- a/xen/arch/x86/domctl.c
|
||||
+++ b/xen/arch/x86/domctl.c
|
||||
@@ -267,16 +267,17 @@ long arch_do_domctl(
|
||||
break;
|
||||
}
|
||||
|
||||
- ret = -EPERM;
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
if ( !irq_access_permitted(currd, irq) ||
|
||||
xsm_irq_permission(XSM_HOOK, d, irq, flags) )
|
||||
- break;
|
||||
-
|
||||
- if ( flags )
|
||||
+ ret = -EPERM;
|
||||
+ else if ( flags )
|
||||
ret = irq_permit_access(d, irq);
|
||||
else
|
||||
ret = irq_deny_access(d, irq);
|
||||
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -579,20 +580,27 @@ long arch_do_domctl(
|
||||
break;
|
||||
|
||||
irq = domain_pirq_to_irq(d, bind->machine_irq);
|
||||
- ret = -EPERM;
|
||||
- if ( irq <= 0 || !irq_access_permitted(currd, irq) )
|
||||
- break;
|
||||
+ if ( irq <= 0 )
|
||||
+ ret = -EPERM;
|
||||
|
||||
- ret = -ESRCH;
|
||||
- if ( is_iommu_enabled(d) )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ ret = -EPERM;
|
||||
+ else if ( is_iommu_enabled(d) )
|
||||
{
|
||||
pcidevs_lock();
|
||||
ret = pt_irq_create_bind(d, bind);
|
||||
pcidevs_unlock();
|
||||
+
|
||||
+ if ( ret < 0 )
|
||||
+ printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for %pd\n",
|
||||
+ ret, d);
|
||||
}
|
||||
- if ( ret < 0 )
|
||||
- printk(XENLOG_G_ERR "pt_irq_create_bind failed (%ld) for dom%d\n",
|
||||
- ret, d->domain_id);
|
||||
+ else
|
||||
+ ret = -ESRCH;
|
||||
+
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -605,23 +613,26 @@ long arch_do_domctl(
|
||||
if ( !is_hvm_domain(d) )
|
||||
break;
|
||||
|
||||
- ret = -EPERM;
|
||||
- if ( irq <= 0 || !irq_access_permitted(currd, irq) )
|
||||
- break;
|
||||
-
|
||||
ret = xsm_unbind_pt_irq(XSM_HOOK, d, bind);
|
||||
if ( ret )
|
||||
break;
|
||||
|
||||
- if ( is_iommu_enabled(d) )
|
||||
+ read_lock(&currd->caps_lock);
|
||||
+
|
||||
+ if ( !irq_access_permitted(currd, irq) )
|
||||
+ ret = -EPERM;
|
||||
+ else if ( is_iommu_enabled(d) )
|
||||
{
|
||||
pcidevs_lock();
|
||||
ret = pt_irq_destroy_bind(d, bind);
|
||||
pcidevs_unlock();
|
||||
+
|
||||
+ if ( ret < 0 )
|
||||
+ printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for %pd\n",
|
||||
+ ret, d);
|
||||
}
|
||||
- if ( ret < 0 )
|
||||
- printk(XENLOG_G_ERR "pt_irq_destroy_bind failed (%ld) for dom%d\n",
|
||||
- ret, d->domain_id);
|
||||
+
|
||||
+ read_unlock(&currd->caps_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/xen/common/domctl.c
|
||||
+++ b/xen/common/domctl.c
|
||||
@@ -695,6 +695,9 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ iocaps_double_lock(d, true);
|
||||
+
|
||||
irq = pirq_access_permitted(current->domain, pirq);
|
||||
if ( !irq || xsm_irq_permission(XSM_HOOK, d, irq, allow) )
|
||||
ret = -EPERM;
|
||||
@@ -702,6 +705,8 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
|
||||
ret = irq_permit_access(d, irq);
|
||||
else
|
||||
ret = irq_deny_access(d, irq);
|
||||
+
|
||||
+ iocaps_double_unlock(d, true);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
From: Jan Beulich <jbeulich@suse.com>
|
||||
Subject: XSM/Flask: split the .iomem_mapping() hook
|
||||
|
||||
It's used twice in entirely different situations. The use in do_domctl()
|
||||
wants to become an ordinary XSM_DM_PRIV invocation, while the one in vPCI
|
||||
code need to remain XSM_HOOK (it may plausibly become XSM_TARGET). For
|
||||
Flask, the same backing function will continue to be used for the time
|
||||
being.
|
||||
|
||||
This is part of XSA-492.
|
||||
|
||||
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||||
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
|
||||
|
||||
--- a/xen/drivers/vpci/header.c
|
||||
+++ b/xen/drivers/vpci/header.c
|
||||
@@ -67,7 +67,7 @@ static int cf_check map_range(
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
- rc = xsm_iomem_mapping(XSM_HOOK, map->d, map_mfn, m_end, map->map);
|
||||
+ rc = xsm_iomem_mapping_vpci(XSM_HOOK, map->d, map_mfn, m_end, map->map);
|
||||
if ( rc )
|
||||
{
|
||||
printk(XENLOG_G_WARNING
|
||||
--- a/xen/include/xsm/dummy.h
|
||||
+++ b/xen/include/xsm/dummy.h
|
||||
@@ -580,6 +580,13 @@ static XSM_INLINE int cf_check xsm_iomem
|
||||
return xsm_default_action(action, current->domain, d);
|
||||
}
|
||||
|
||||
+static XSM_INLINE int cf_check xsm_iomem_mapping_vpci(
|
||||
+ XSM_DEFAULT_ARG struct domain *d, uint64_t s, uint64_t e, uint8_t allow)
|
||||
+{
|
||||
+ XSM_ASSERT_ACTION(XSM_HOOK);
|
||||
+ return xsm_default_action(action, current->domain, d);
|
||||
+}
|
||||
+
|
||||
static XSM_INLINE int cf_check xsm_pci_config_permission(
|
||||
XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf, uint16_t start,
|
||||
uint16_t end, uint8_t access)
|
||||
--- a/xen/include/xsm/xsm.h
|
||||
+++ b/xen/include/xsm/xsm.h
|
||||
@@ -118,6 +118,8 @@ struct xsm_ops {
|
||||
uint8_t allow);
|
||||
int (*iomem_mapping)(struct domain *d, uint64_t s, uint64_t e,
|
||||
uint8_t allow);
|
||||
+ int (*iomem_mapping_vpci)(struct domain *d, uint64_t s, uint64_t e,
|
||||
+ uint8_t allow);
|
||||
int (*pci_config_permission)(struct domain *d, uint32_t machine_bdf,
|
||||
uint16_t start, uint16_t end, uint8_t access);
|
||||
|
||||
@@ -523,6 +525,12 @@ static inline int xsm_iomem_mapping(
|
||||
return alternative_call(xsm_ops.iomem_mapping, d, s, e, allow);
|
||||
}
|
||||
|
||||
+static inline int xsm_iomem_mapping_vpci(
|
||||
+ xsm_default_t def, struct domain *d, uint64_t s, uint64_t e, uint8_t allow)
|
||||
+{
|
||||
+ return alternative_call(xsm_ops.iomem_mapping_vpci, d, s, e, allow);
|
||||
+}
|
||||
+
|
||||
static inline int xsm_pci_config_permission(
|
||||
xsm_default_t def, struct domain *d, uint32_t machine_bdf, uint16_t start,
|
||||
uint16_t end, uint8_t access)
|
||||
--- a/xen/xsm/dummy.c
|
||||
+++ b/xen/xsm/dummy.c
|
||||
@@ -76,6 +76,7 @@ static const struct xsm_ops __initconst_
|
||||
.irq_permission = xsm_irq_permission,
|
||||
.iomem_permission = xsm_iomem_permission,
|
||||
.iomem_mapping = xsm_iomem_mapping,
|
||||
+ .iomem_mapping_vpci = xsm_iomem_mapping_vpci,
|
||||
.pci_config_permission = xsm_pci_config_permission,
|
||||
.get_vnumainfo = xsm_get_vnumainfo,
|
||||
|
||||
--- a/xen/xsm/flask/hooks.c
|
||||
+++ b/xen/xsm/flask/hooks.c
|
||||
@@ -1950,6 +1950,7 @@ static const struct xsm_ops __initconst_
|
||||
.irq_permission = flask_irq_permission,
|
||||
.iomem_permission = flask_iomem_permission,
|
||||
.iomem_mapping = flask_iomem_mapping,
|
||||
+ .iomem_mapping_vpci = flask_iomem_mapping,
|
||||
.pci_config_permission = flask_pci_config_permission,
|
||||
|
||||
.resource_plug_core = flask_resource_plug_core,
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
/*
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue