As usual - dropped patched already applied there, other updated.pull/4/head v4.4.8-9
parent
e2ec0a1398
commit
d78c498a97
@ -1,84 +0,0 @@
|
||||
From 94f9cd81436c85d8c3a318ba92e236ede73752fc Mon Sep 17 00:00:00 2001
|
||||
From: Munehisa Kamata <kamatam@amazon.com>
|
||||
Date: Mon, 26 Oct 2015 19:10:52 -0700
|
||||
Subject: [PATCH] netfilter: nf_nat_redirect: add missing NULL pointer check
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Commit 8b13eddfdf04cbfa561725cfc42d6868fe896f56 ("netfilter: refactor NAT
|
||||
redirect IPv4 to use it from nf_tables") has introduced a trivial logic
|
||||
change which can result in the following crash.
|
||||
|
||||
BUG: unable to handle kernel NULL pointer dereference at 0000000000000030
|
||||
IP: [<ffffffffa033002d>] nf_nat_redirect_ipv4+0x2d/0xa0 [nf_nat_redirect]
|
||||
PGD 3ba662067 PUD 3ba661067 PMD 0
|
||||
Oops: 0000 [#1] SMP
|
||||
Modules linked in: ipv6(E) xt_REDIRECT(E) nf_nat_redirect(E) xt_tcpudp(E) iptable_nat(E) nf_conntrack_ipv4(E) nf_defrag_ipv4(E) nf_nat_ipv4(E) nf_nat(E) nf_conntrack(E) ip_tables(E) x_tables(E) binfmt_misc(E) xfs(E) libcrc32c(E) evbug(E) evdev(E) psmouse(E) i2c_piix4(E) i2c_core(E) acpi_cpufreq(E) button(E) ext4(E) crc16(E) jbd2(E) mbcache(E) dm_mirror(E) dm_region_hash(E) dm_log(E) dm_mod(E)
|
||||
CPU: 0 PID: 2536 Comm: ip Tainted: G E 4.1.7-15.23.amzn1.x86_64 #1
|
||||
Hardware name: Xen HVM domU, BIOS 4.2.amazon 05/06/2015
|
||||
task: ffff8800eb438000 ti: ffff8803ba664000 task.ti: ffff8803ba664000
|
||||
[...]
|
||||
Call Trace:
|
||||
<IRQ>
|
||||
[<ffffffffa0334065>] redirect_tg4+0x15/0x20 [xt_REDIRECT]
|
||||
[<ffffffffa02e2e99>] ipt_do_table+0x2b9/0x5e1 [ip_tables]
|
||||
[<ffffffffa0328045>] iptable_nat_do_chain+0x25/0x30 [iptable_nat]
|
||||
[<ffffffffa031777d>] nf_nat_ipv4_fn+0x13d/0x1f0 [nf_nat_ipv4]
|
||||
[<ffffffffa0328020>] ? iptable_nat_ipv4_fn+0x20/0x20 [iptable_nat]
|
||||
[<ffffffffa031785e>] nf_nat_ipv4_in+0x2e/0x90 [nf_nat_ipv4]
|
||||
[<ffffffffa03280a5>] iptable_nat_ipv4_in+0x15/0x20 [iptable_nat]
|
||||
[<ffffffff81449137>] nf_iterate+0x57/0x80
|
||||
[<ffffffff814491f7>] nf_hook_slow+0x97/0x100
|
||||
[<ffffffff814504d4>] ip_rcv+0x314/0x400
|
||||
|
||||
unsigned int
|
||||
nf_nat_redirect_ipv4(struct sk_buff *skb,
|
||||
...
|
||||
{
|
||||
...
|
||||
rcu_read_lock();
|
||||
indev = __in_dev_get_rcu(skb->dev);
|
||||
if (indev != NULL) {
|
||||
ifa = indev->ifa_list;
|
||||
newdst = ifa->ifa_local; <---
|
||||
}
|
||||
rcu_read_unlock();
|
||||
...
|
||||
}
|
||||
|
||||
Before the commit, 'ifa' had been always checked before access. After the
|
||||
commit, however, it could be accessed even if it's NULL. Interestingly,
|
||||
this was once fixed in 2003.
|
||||
|
||||
http://marc.info/?l=netfilter-devel&m=106668497403047&w=2
|
||||
|
||||
In addition to the original one, we have seen the crash when packets that
|
||||
need to be redirected somehow arrive on an interface which hasn't been
|
||||
yet fully configured.
|
||||
|
||||
This change just reverts the logic to the old behavior to avoid the crash.
|
||||
|
||||
Fixes: 8b13eddfdf04 ("netfilter: refactor NAT redirect IPv4 to use it from nf_tables")
|
||||
Signed-off-by: Munehisa Kamata <kamatam@amazon.com>
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
net/netfilter/nf_nat_redirect.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c
|
||||
index 97b75f9..d438698 100644
|
||||
--- a/net/netfilter/nf_nat_redirect.c
|
||||
+++ b/net/netfilter/nf_nat_redirect.c
|
||||
@@ -55,7 +55,7 @@ nf_nat_redirect_ipv4(struct sk_buff *skb,
|
||||
|
||||
rcu_read_lock();
|
||||
indev = __in_dev_get_rcu(skb->dev);
|
||||
- if (indev != NULL) {
|
||||
+ if (indev && indev->ifa_list) {
|
||||
ifa = indev->ifa_list;
|
||||
newdst = ifa->ifa_local;
|
||||
}
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,57 +0,0 @@
|
||||
From 4e2bc423e0cef0a42f93d989c0980301df1bd462 Mon Sep 17 00:00:00 2001
|
||||
From: David Vrabel <david.vrabel@citrix.com>
|
||||
Date: Fri, 30 Oct 2015 14:58:08 +0000
|
||||
Subject: [PATCH 1/7] xen: Add RING_COPY_REQUEST()
|
||||
|
||||
Using RING_GET_REQUEST() on a shared ring is easy to use incorrectly
|
||||
(i.e., by not considering that the other end may alter the data in the
|
||||
shared ring while it is being inspected). Safe usage of a request
|
||||
generally requires taking a local copy.
|
||||
|
||||
Provide a RING_COPY_REQUEST() macro to use instead of
|
||||
RING_GET_REQUEST() and an open-coded memcpy(). This takes care of
|
||||
ensuring that the copy is done correctly regardless of any possible
|
||||
compiler optimizations.
|
||||
|
||||
Use a volatile source to prevent the compiler from reordering or
|
||||
omitting the copy.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
v2: Update about GCC and bitfields.
|
||||
---
|
||||
include/xen/interface/io/ring.h | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
|
||||
index 7d28aff..7dc685b 100644
|
||||
--- a/include/xen/interface/io/ring.h
|
||||
+++ b/include/xen/interface/io/ring.h
|
||||
@@ -181,6 +181,20 @@ struct __name##_back_ring { \
|
||||
#define RING_GET_REQUEST(_r, _idx) \
|
||||
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
|
||||
|
||||
+/*
|
||||
+ * Get a local copy of a request.
|
||||
+ *
|
||||
+ * Use this in preference to RING_GET_REQUEST() so all processing is
|
||||
+ * done on a local copy that cannot be modified by the other end.
|
||||
+ *
|
||||
+ * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this
|
||||
+ * to be ineffective where _req is a struct which consists of only bitfields.
|
||||
+ */
|
||||
+#define RING_COPY_REQUEST(_r, _idx, _req) do { \
|
||||
+ /* Use volatile to force the copy into _req. */ \
|
||||
+ *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx); \
|
||||
+} while (0)
|
||||
+
|
||||
#define RING_GET_RESPONSE(_r, _idx) \
|
||||
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
|
||||
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,40 +0,0 @@
|
||||
From 100ac372a0e07ccc8c508c3884fa9020cfe08094 Mon Sep 17 00:00:00 2001
|
||||
From: David Vrabel <david.vrabel@citrix.com>
|
||||
Date: Fri, 30 Oct 2015 15:16:01 +0000
|
||||
Subject: [PATCH 2/7] xen-netback: don't use last request to determine minimum
|
||||
Tx credit
|
||||
|
||||
The last from guest transmitted request gives no indication about the
|
||||
minimum amount of credit that the guest might need to send a packet
|
||||
since the last packet might have been a small one.
|
||||
|
||||
Instead allow for the worst case 128 KiB packet.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
|
||||
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/net/xen-netback/netback.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
|
||||
index e481f37..b683581 100644
|
||||
--- a/drivers/net/xen-netback/netback.c
|
||||
+++ b/drivers/net/xen-netback/netback.c
|
||||
@@ -679,9 +679,7 @@ static void tx_add_credit(struct xenvif_queue *queue)
|
||||
* Allow a burst big enough to transmit a jumbo packet of up to 128kB.
|
||||
* Otherwise the interface can seize up due to insufficient credit.
|
||||
*/
|
||||
- max_burst = RING_GET_REQUEST(&queue->tx, queue->tx.req_cons)->size;
|
||||
- max_burst = min(max_burst, 131072UL);
|
||||
- max_burst = max(max_burst, queue->credit_bytes);
|
||||
+ max_burst = max(131072UL, queue->credit_bytes);
|
||||
|
||||
/* Take care that adding a new chunk of credit doesn't wrap to zero. */
|
||||
max_credit = queue->remaining_credit + queue->credit_bytes;
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,131 +0,0 @@
|
||||
From 4127e9ccae0eda622421d21132846abdf74f66ed Mon Sep 17 00:00:00 2001
|
||||
From: David Vrabel <david.vrabel@citrix.com>
|
||||
Date: Fri, 30 Oct 2015 15:17:06 +0000
|
||||
Subject: [PATCH 3/7] xen-netback: use RING_COPY_REQUEST() throughout
|
||||
|
||||
Instead of open-coding memcpy()s and directly accessing Tx and Rx
|
||||
requests, use the new RING_COPY_REQUEST() that ensures the local copy
|
||||
is correct.
|
||||
|
||||
This is more than is strictly necessary for guest Rx requests since
|
||||
only the id and gref fields are used and it is harmless if the
|
||||
frontend modifies these.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
|
||||
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/net/xen-netback/netback.c | 30 ++++++++++++++----------------
|
||||
1 file changed, 14 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
|
||||
index b683581..1049c34 100644
|
||||
--- a/drivers/net/xen-netback/netback.c
|
||||
+++ b/drivers/net/xen-netback/netback.c
|
||||
@@ -258,18 +258,18 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
|
||||
struct netrx_pending_operations *npo)
|
||||
{
|
||||
struct xenvif_rx_meta *meta;
|
||||
- struct xen_netif_rx_request *req;
|
||||
+ struct xen_netif_rx_request req;
|
||||
|
||||
- req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
|
||||
+ RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
|
||||
|
||||
meta = npo->meta + npo->meta_prod++;
|
||||
meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
|
||||
meta->gso_size = 0;
|
||||
meta->size = 0;
|
||||
- meta->id = req->id;
|
||||
+ meta->id = req.id;
|
||||
|
||||
npo->copy_off = 0;
|
||||
- npo->copy_gref = req->gref;
|
||||
+ npo->copy_gref = req.gref;
|
||||
|
||||
return meta;
|
||||
}
|
||||
@@ -424,7 +424,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
|
||||
struct xenvif *vif = netdev_priv(skb->dev);
|
||||
int nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
int i;
|
||||
- struct xen_netif_rx_request *req;
|
||||
+ struct xen_netif_rx_request req;
|
||||
struct xenvif_rx_meta *meta;
|
||||
unsigned char *data;
|
||||
int head = 1;
|
||||
@@ -443,15 +443,15 @@ static int xenvif_gop_skb(struct sk_buff *skb,
|
||||
|
||||
/* Set up a GSO prefix descriptor, if necessary */
|
||||
if ((1 << gso_type) & vif->gso_prefix_mask) {
|
||||
- req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
|
||||
+ RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
|
||||
meta = npo->meta + npo->meta_prod++;
|
||||
meta->gso_type = gso_type;
|
||||
meta->gso_size = skb_shinfo(skb)->gso_size;
|
||||
meta->size = 0;
|
||||
- meta->id = req->id;
|
||||
+ meta->id = req.id;
|
||||
}
|
||||
|
||||
- req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
|
||||
+ RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
|
||||
meta = npo->meta + npo->meta_prod++;
|
||||
|
||||
if ((1 << gso_type) & vif->gso_mask) {
|
||||
@@ -463,9 +463,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
meta->size = 0;
|
||||
- meta->id = req->id;
|
||||
+ meta->id = req.id;
|
||||
npo->copy_off = 0;
|
||||
- npo->copy_gref = req->gref;
|
||||
+ npo->copy_gref = req.gref;
|
||||
|
||||
data = skb->data;
|
||||
while (data < skb_tail_pointer(skb)) {
|
||||
@@ -709,7 +709,7 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
|
||||
spin_unlock_irqrestore(&queue->response_lock, flags);
|
||||
if (cons == end)
|
||||
break;
|
||||
- txp = RING_GET_REQUEST(&queue->tx, cons++);
|
||||
+ RING_COPY_REQUEST(&queue->tx, cons++, txp);
|
||||
} while (1);
|
||||
queue->tx.req_cons = cons;
|
||||
}
|
||||
@@ -776,8 +776,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
|
||||
if (drop_err)
|
||||
txp = &dropped_tx;
|
||||
|
||||
- memcpy(txp, RING_GET_REQUEST(&queue->tx, cons + slots),
|
||||
- sizeof(*txp));
|
||||
+ RING_COPY_REQUEST(&queue->tx, cons + slots, txp);
|
||||
|
||||
/* If the guest submitted a frame >= 64 KiB then
|
||||
* first->size overflowed and following slots will
|
||||
@@ -1110,8 +1109,7 @@ static int xenvif_get_extras(struct xenvif_queue *queue,
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
- memcpy(&extra, RING_GET_REQUEST(&queue->tx, cons),
|
||||
- sizeof(extra));
|
||||
+ RING_COPY_REQUEST(&queue->tx, cons, &extra);
|
||||
if (unlikely(!extra.type ||
|
||||
extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
|
||||
queue->tx.req_cons = ++cons;
|
||||
@@ -1320,7 +1318,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
|
||||
|
||||
idx = queue->tx.req_cons;
|
||||
rmb(); /* Ensure that we see the request before we copy it. */
|
||||
- memcpy(&txreq, RING_GET_REQUEST(&queue->tx, idx), sizeof(txreq));
|
||||
+ RING_COPY_REQUEST(&queue->tx, idx, &txreq);
|
||||
|
||||
/* Credit-based scheduling. */
|
||||
if (txreq.size > queue->remaining_credit &&
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,54 +0,0 @@
|
||||
From 084b8c2e77f1ac07e4a3a121ff957c49a9379385 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= <roger.pau@citrix.com>
|
||||
Date: Tue, 3 Nov 2015 16:34:09 +0000
|
||||
Subject: [PATCH 4/7] xen-blkback: only read request operation from shared ring
|
||||
once
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
A compiler may load a switch statement value multiple times, which could
|
||||
be bad when the value is in memory shared with the frontend.
|
||||
|
||||
When converting a non-native request to a native one, ensure that
|
||||
src->operation is only loaded once by using READ_ONCE().
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/block/xen-blkback/common.h | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
|
||||
index 68e87a0..c929ae2 100644
|
||||
--- a/drivers/block/xen-blkback/common.h
|
||||
+++ b/drivers/block/xen-blkback/common.h
|
||||
@@ -408,8 +408,8 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
|
||||
struct blkif_x86_32_request *src)
|
||||
{
|
||||
int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
|
||||
- dst->operation = src->operation;
|
||||
- switch (src->operation) {
|
||||
+ dst->operation = READ_ONCE(src->operation);
|
||||
+ switch (dst->operation) {
|
||||
case BLKIF_OP_READ:
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_WRITE_BARRIER:
|
||||
@@ -456,8 +456,8 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
|
||||
struct blkif_x86_64_request *src)
|
||||
{
|
||||
int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
|
||||
- dst->operation = src->operation;
|
||||
- switch (src->operation) {
|
||||
+ dst->operation = READ_ONCE(src->operation);
|
||||
+ switch (dst->operation) {
|
||||
case BLKIF_OP_READ:
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_WRITE_BARRIER:
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,37 +0,0 @@
|
||||
From 89739c14c72e5c1626a5cd5e09cbb2efeaadb6d8 Mon Sep 17 00:00:00 2001
|
||||
From: David Vrabel <david.vrabel@citrix.com>
|
||||
Date: Mon, 16 Nov 2015 18:02:32 +0000
|
||||
Subject: [PATCH 6/7] xen-scsiback: safely copy requests
|
||||
|
||||
The copy of the ring request was lacking a following barrier(),
|
||||
potentially allowing the compiler to optimize the copy away.
|
||||
|
||||
Use RING_COPY_REQUEST() to ensure the request is copied to local
|
||||
memory.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Reviewed-by: Juergen Gross <jgross@suse.com>
|
||||
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/xen/xen-scsiback.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
|
||||
index 43bcae8..ad4eb10 100644
|
||||
--- a/drivers/xen/xen-scsiback.c
|
||||
+++ b/drivers/xen/xen-scsiback.c
|
||||
@@ -726,7 +726,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
|
||||
if (!pending_req)
|
||||
return 1;
|
||||
|
||||
- ring_req = *RING_GET_REQUEST(ring, rc);
|
||||
+ RING_COPY_REQUEST(ring, rc, &ring_req);
|
||||
ring->req_cons = ++rc;
|
||||
|
||||
err = prepare_pending_reqs(info, &ring_req, pending_req);
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,165 +0,0 @@
|
||||
From 74aaa42e1f25309a163acd00083ecbbc186fbb47 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
|
||||
<marmarek@invisiblethingslab.com>
|
||||
Date: Wed, 16 Dec 2015 06:07:14 +0100
|
||||
Subject: [PATCH 13/13] xen-blkfront: prepare request locally, only then put it
|
||||
on the shared ring
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Organization: Invisible Things Lab
|
||||
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
|
||||
|
||||
Do not reuse data which theoretically might be already modified by the
|
||||
backend. This is mostly about private copy of the request
|
||||
(info->shadow[id].req) - make sure the request saved there is really the
|
||||
one just filled.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
|
||||
---
|
||||
drivers/block/xen-blkfront.c | 56 ++++++++++++++++++++++++--------------------
|
||||
1 file changed, 30 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
|
||||
index 5d7eb04..514cf18 100644
|
||||
--- a/drivers/block/xen-blkfront.c
|
||||
+++ b/drivers/block/xen-blkfront.c
|
||||
@@ -389,7 +389,7 @@ static int blkif_ioctl(struct block_devi
|
||||
static int blkif_queue_request(struct request *req)
|
||||
{
|
||||
struct blkfront_info *info = req->rq_disk->private_data;
|
||||
- struct blkif_request *ring_req;
|
||||
+ struct blkif_request ring_req;
|
||||
unsigned long id;
|
||||
unsigned int fsect, lsect;
|
||||
int i, ref, n;
|
||||
@@ -435,7 +435,7 @@
|
||||
new_persistent_gnts = 0;
|
||||
|
||||
/* Fill out a communications ring structure. */
|
||||
- ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
|
||||
+ RING_COPY_REQUEST(&info->ring, info->ring.req_prod_pvt, &ring_req);
|
||||
id = get_id_from_freelist(info);
|
||||
info->shadow[id].request = req;
|
||||
|
||||
@@ -435,37 +435,37 @@ static int blkif_queue_request(struct re
|
||||
info->shadow[id].request = req;
|
||||
|
||||
if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) {
|
||||
- ring_req->operation = BLKIF_OP_DISCARD;
|
||||
- ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
|
||||
- ring_req->u.discard.id = id;
|
||||
- ring_req->u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
+ ring_req.operation = BLKIF_OP_DISCARD;
|
||||
+ ring_req.u.discard.nr_sectors = blk_rq_sectors(req);
|
||||
+ ring_req.u.discard.id = id;
|
||||
+ ring_req.u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard)
|
||||
- ring_req->u.discard.flag = BLKIF_DISCARD_SECURE;
|
||||
+ ring_req.u.discard.flag = BLKIF_DISCARD_SECURE;
|
||||
else
|
||||
- ring_req->u.discard.flag = 0;
|
||||
+ ring_req.u.discard.flag = 0;
|
||||
} else {
|
||||
BUG_ON(info->max_indirect_segments == 0 &&
|
||||
req->nr_phys_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
||||
BUG_ON(info->max_indirect_segments &&
|
||||
req->nr_phys_segments > info->max_indirect_segments);
|
||||
nseg = blk_rq_map_sg(req->q, req, info->shadow[id].sg);
|
||||
- ring_req->u.rw.id = id;
|
||||
+ ring_req.u.rw.id = id;
|
||||
if (nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
|
||||
/*
|
||||
* The indirect operation can only be a BLKIF_OP_READ or
|
||||
* BLKIF_OP_WRITE
|
||||
*/
|
||||
BUG_ON(req->cmd_flags & (REQ_FLUSH | REQ_FUA));
|
||||
- ring_req->operation = BLKIF_OP_INDIRECT;
|
||||
- ring_req->u.indirect.indirect_op = rq_data_dir(req) ?
|
||||
+ ring_req.operation = BLKIF_OP_INDIRECT;
|
||||
+ ring_req.u.indirect.indirect_op = rq_data_dir(req) ?
|
||||
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
||||
- ring_req->u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
- ring_req->u.indirect.handle = info->handle;
|
||||
- ring_req->u.indirect.nr_segments = nseg;
|
||||
+ ring_req.u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
+ ring_req.u.indirect.handle = info->handle;
|
||||
+ ring_req.u.indirect.nr_segments = nseg;
|
||||
} else {
|
||||
- ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
- ring_req->u.rw.handle = info->handle;
|
||||
- ring_req->operation = rq_data_dir(req) ?
|
||||
+ ring_req.u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
+ ring_req.u.rw.handle = info->handle;
|
||||
+ ring_req.operation = rq_data_dir(req) ?
|
||||
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
||||
if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
|
||||
/*
|
||||
@@ -481,24 +481,24 @@ static int blkif_queue_request(struct re
|
||||
switch (info->feature_flush &
|
||||
((REQ_FLUSH|REQ_FUA))) {
|
||||
case REQ_FLUSH|REQ_FUA:
|
||||
- ring_req->operation =
|
||||
+ ring_req.operation =
|
||||
BLKIF_OP_WRITE_BARRIER;
|
||||
break;
|
||||
case REQ_FLUSH:
|
||||
- ring_req->operation =
|
||||
+ ring_req.operation =
|
||||
BLKIF_OP_FLUSH_DISKCACHE;
|
||||
break;
|
||||
default:
|
||||
- ring_req->operation = 0;
|
||||
+ ring_req.operation = 0;
|
||||
}
|
||||
}
|
||||
- ring_req->u.rw.nr_segments = nseg;
|
||||
+ ring_req.u.rw.nr_segments = nseg;
|
||||
}
|
||||
for_each_sg(info->shadow[id].sg, sg, nseg, i) {
|
||||
fsect = sg->offset >> 9;
|
||||
lsect = fsect + (sg->length >> 9) - 1;
|
||||
|
||||
- if ((ring_req->operation == BLKIF_OP_INDIRECT) &&
|
||||
+ if ((ring_req.operation == BLKIF_OP_INDIRECT) &&
|
||||
(i % SEGS_PER_INDIRECT_FRAME == 0)) {
|
||||
unsigned long uninitialized_var(pfn);
|
||||
|
||||
@@ -504,7 +504,7 @@ static int blkif_queue_request(struct re
|
||||
gnt_list_entry = get_grant(&gref_head, pfn, info);
|
||||
info->shadow[id].indirect_grants[n] = gnt_list_entry;
|
||||
segments = kmap_atomic(pfn_to_page(gnt_list_entry->pfn));
|
||||
- ring_req->u.indirect.indirect_grefs[n] = gnt_list_entry->gref;
|
||||
+ ring_req.u.indirect.indirect_grefs[n] = gnt_list_entry->gref;
|
||||
}
|
||||
|
||||
gnt_list_entry = get_grant(&gref_head, page_to_pfn(sg_page(sg)), info);
|
||||
@@ -537,8 +537,8 @@ static int blkif_queue_request(struct re
|
||||
kunmap_atomic(bvec_data);
|
||||
kunmap_atomic(shared_data);
|
||||
}
|
||||
- if (ring_req->operation != BLKIF_OP_INDIRECT) {
|
||||
- ring_req->u.rw.seg[i] =
|
||||
+ if (ring_req.operation != BLKIF_OP_INDIRECT) {
|
||||
+ ring_req.u.rw.seg[i] =
|
||||
(struct blkif_request_segment) {
|
||||
.gref = ref,
|
||||
.first_sect = fsect,
|
||||
@@ -556,10 +556,13 @@ static int blkif_queue_request(struct re
|
||||
kunmap_atomic(segments);
|
||||
}
|
||||
|
||||
+ /* make the request available to the backend */
|
||||
+ *RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt) = ring_req;
|
||||
+ wmb();
|
||||
info->ring.req_prod_pvt++;
|
||||
|
||||
/* Keep a private copy so we can reissue requests when recovering. */
|
||||
- info->shadow[id].req = *ring_req;
|
||||
+ info->shadow[id].req = ring_req;
|
||||
|
||||
if (new_persistent_gnts)
|
||||
gnttab_free_grant_references(gref_head);
|
@ -1,65 +0,0 @@
|
||||
From d52f00960c1070c683809faddd35a2223e2b8a6e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= <roger.pau@citrix.com>
|
||||
Date: Tue, 3 Nov 2015 16:40:43 +0000
|
||||
Subject: [PATCH 6/7] xen-blkback: read from indirect descriptors only once
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Since indirect descriptors are in memory shared with the frontend, the
|
||||
frontend could alter the first_sect and last_sect values after they have
|
||||
been validated but before they are recorded in the request. This may
|
||||
result in I/O requests that overflow the foreign page, possibly
|
||||
overwriting local pages when the I/O request is executed.
|
||||
|
||||
When parsing indirect descriptors, only read first_sect and last_sect
|
||||
once.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
|
||||
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
----
|
||||
v2: This is against v4.3
|
||||
---
|
||||
drivers/block/xen-blkback/blkback.c | 12 +++++++-----
|
||||
1 file changed, 7 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
|
||||
index 6a685ae..f2e7a38 100644
|
||||
--- a/drivers/block/xen-blkback/blkback.c
|
||||
+++ b/drivers/block/xen-blkback/blkback.c
|
||||
@@ -950,6 +950,8 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
|
||||
goto unmap;
|
||||
|
||||
for (n = 0, i = 0; n < nseg; n++) {
|
||||
+ uint8_t first_sect, last_sect;
|
||||
+
|
||||
if ((n % SEGS_PER_INDIRECT_FRAME) == 0) {
|
||||
/* Map indirect segments */
|
||||
if (segments)
|
||||
@@ -958,14 +960,14 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
|
||||
}
|
||||
i = n % SEGS_PER_INDIRECT_FRAME;
|
||||
pending_req->segments[n]->gref = segments[i].gref;
|
||||
- seg[n].nsec = segments[i].last_sect -
|
||||
- segments[i].first_sect + 1;
|
||||
- seg[n].offset = (segments[i].first_sect << 9);
|
||||
- if ((segments[i].last_sect >= (PAGE_SIZE >> 9)) ||
|
||||
- (segments[i].last_sect < segments[i].first_sect)) {
|
||||
+ first_sect = READ_ONCE(segments[i].first_sect);
|
||||
+ last_sect = READ_ONCE(segments[i].last_sect);
|
||||
+ if (last_sect >= (PAGE_SIZE >> 9) || last_sect < first_sect) {
|
||||
rc = -EINVAL;
|
||||
goto unmap;
|
||||
}
|
||||
+ seg[n].nsec = last_sect - first_sect + 1;
|
||||
+ seg[n].offset = first_sect << 9;
|
||||
preq->nr_sects += seg[n].nsec;
|
||||
}
|
||||
|
||||
--
|
||||
2.1.0
|
||||
|
@ -0,0 +1,161 @@
|
||||
From 74aaa42e1f25309a163acd00083ecbbc186fbb47 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?=
|
||||
<marmarek@invisiblethingslab.com>
|
||||
Date: Wed, 16 Dec 2015 06:07:14 +0100
|
||||
Subject: [PATCH 13/13] xen-blkfront: prepare request locally, only then put it
|
||||
on the shared ring
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Organization: Invisible Things Lab
|
||||
Cc: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
|
||||
|
||||
Do not reuse data which theoretically might be already modified by the
|
||||
backend. This is mostly about private copy of the request
|
||||
(info->shadow[id].req) - make sure the request saved there is really the
|
||||
one just filled.
|
||||
|
||||
This is part of XSA155.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
|
||||
---
|
||||
drivers/block/xen-blkfront.c | 56 ++++++++++++++++++++++++--------------------
|
||||
1 file changed, 30 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
|
||||
index 5d7eb04..514cf18 100644
|
||||
--- a/drivers/block/xen-blkfront.c
|
||||
+++ b/drivers/block/xen-blkfront.c
|
||||
@@ -463,27 +463,29 @@ static int blkif_ioctl(struct block_devi
|
||||
static int blkif_queue_discard_req(struct request *req)
|
||||
{
|
||||
struct blkfront_info *info = req->rq_disk->private_data;
|
||||
- struct blkif_request *ring_req;
|
||||
+ struct blkif_request ring_req = { };
|
||||
unsigned long id;
|
||||
|
||||
/* Fill out a communications ring structure. */
|
||||
- ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
|
||||
id = get_id_from_freelist(info);
|
||||
info->shadow[id].request = req;
|
||||
|
||||
- ring_req->operation = BLKIF_OP_DISCARD;
|
||||
- ring_req->u.discard.nr_sectors = blk_rq_sectors(req);
|
||||
- ring_req->u.discard.id = id;
|
||||
- ring_req->u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
+ ring_req.operation = BLKIF_OP_DISCARD;
|
||||
+ ring_req.u.discard.nr_sectors = blk_rq_sectors(req);
|
||||
+ ring_req.u.discard.id = id;
|
||||
+ ring_req.u.discard.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard)
|
||||
- ring_req->u.discard.flag = BLKIF_DISCARD_SECURE;
|
||||
+ ring_req.u.discard.flag = BLKIF_DISCARD_SECURE;
|
||||
else
|
||||
- ring_req->u.discard.flag = 0;
|
||||
+ ring_req.u.discard.flag = 0;
|
||||
|
||||
+ /* make the request available to the backend */
|
||||
+ *RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt) = ring_req;
|
||||
+ wmb();
|
||||
info->ring.req_prod_pvt++;
|
||||
|
||||
/* Keep a private copy so we can reissue requests when recovering. */
|
||||
- info->shadow[id].req = *ring_req;
|
||||
+ info->shadow[id].req = ring_req;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -573,7 +575,7 @@ static void blkif_setup_rw_req_grant(uns
|
||||
static int blkif_queue_rw_req(struct request *req)
|
||||
{
|
||||
struct blkfront_info *info = req->rq_disk->private_data;
|
||||
- struct blkif_request *ring_req;
|
||||
+ struct blkif_request ring_req = { };
|
||||
unsigned long id;
|
||||
int i;
|
||||
struct setup_rw_req setup = {
|
||||
@@ -435,7 +435,6 @@
|
||||
new_persistent_gnts = 0;
|
||||
|
||||
/* Fill out a communications ring structure. */
|
||||
- ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
|
||||
id = get_id_from_freelist(info);
|
||||
info->shadow[id].request = req;
|
||||
|
||||
@@ -632,7 +633,7 @@ static int blkif_queue_rw_req(struct req
|
||||
for_each_sg(info->shadow[id].sg, sg, num_sg, i)
|
||||
num_grant += gnttab_count_grant(sg->offset, sg->length);
|
||||
|
||||
- ring_req->u.rw.id = id;
|
||||
+ ring_req.u.rw.id = id;
|
||||
info->shadow[id].num_sg = num_sg;
|
||||
if (num_grant > BLKIF_MAX_SEGMENTS_PER_REQUEST) {
|
||||
/*
|
||||
@@ -640,16 +641,16 @@ static int blkif_queue_rw_req(struct req
|
||||
* BLKIF_OP_WRITE
|
||||
*/
|
||||
BUG_ON(req->cmd_flags & (REQ_FLUSH | REQ_FUA));
|
||||
- ring_req->operation = BLKIF_OP_INDIRECT;
|
||||
- ring_req->u.indirect.indirect_op = rq_data_dir(req) ?
|
||||
+ ring_req.operation = BLKIF_OP_INDIRECT;
|
||||
+ ring_req.u.indirect.indirect_op = rq_data_dir(req) ?
|
||||
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
||||
- ring_req->u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
- ring_req->u.indirect.handle = info->handle;
|
||||
- ring_req->u.indirect.nr_segments = num_grant;
|
||||
+ ring_req.u.indirect.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
+ ring_req.u.indirect.handle = info->handle;
|
||||
+ ring_req.u.indirect.nr_segments = num_grant;
|
||||
} else {
|
||||
- ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
- ring_req->u.rw.handle = info->handle;
|
||||
- ring_req->operation = rq_data_dir(req) ?
|
||||
+ ring_req.u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
+ ring_req.u.rw.handle = info->handle;
|
||||
+ ring_req.operation = rq_data_dir(req) ?
|
||||
BLKIF_OP_WRITE : BLKIF_OP_READ;
|
||||
if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
|
||||
/*
|
||||
@@ -662,21 +663,21 @@ static int blkif_queue_rw_req(struct req
|
||||
switch (info->feature_flush &
|
||||
((REQ_FLUSH|REQ_FUA))) {
|
||||
case REQ_FLUSH|REQ_FUA:
|
||||
- ring_req->operation =
|
||||
+ ring_req.operation =
|
||||
BLKIF_OP_WRITE_BARRIER;
|
||||
break;
|
||||
case REQ_FLUSH:
|
||||
- ring_req->operation =
|
||||
+ ring_req.operation =
|
||||
BLKIF_OP_FLUSH_DISKCACHE;
|
||||
break;
|
||||
default:
|
||||
- ring_req->operation = 0;
|
||||
+ ring_req.operation = 0;
|
||||
}
|
||||
}
|
||||
- ring_req->u.rw.nr_segments = num_grant;
|
||||
+ ring_req.u.rw.nr_segments = num_grant;
|
||||
}
|
||||
|
||||
- setup.ring_req = ring_req;
|
||||
+ setup.ring_req = &ring_req;
|
||||
setup.id = id;
|
||||
for_each_sg(info->shadow[id].sg, sg, num_sg, i) {
|
||||
BUG_ON(sg->offset + sg->length > PAGE_SIZE);
|
||||
@@ -698,10 +699,13 @@ static int blkif_queue_rw_req(struct req
|
||||
if (setup.segments)
|
||||
kunmap_atomic(setup.segments);
|
||||
|
||||
+ /* make the request available to the backend */
|
||||
+ *RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt) = ring_req;
|
||||
+ wmb();
|
||||
info->ring.req_prod_pvt++;
|
||||
|
||||
/* Keep a private copy so we can reissue requests when recovering. */
|
||||
- info->shadow[id].req = *ring_req;
|
||||
+ info->shadow[id].req = ring_req;
|
||||
|
||||
if (new_persistent_gnts)
|
||||
gnttab_free_grant_references(setup.gref_head);
|
@ -1,61 +0,0 @@
|
||||
From e3de4a44cfe196e162ddeffd6379e5c4e75ff1d7 Mon Sep 17 00:00:00 2001
|
||||
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
Date: Fri, 3 Apr 2015 11:08:22 -0400
|
||||
Subject: [PATCH v2 XSA157 1/5] xen/pciback: Return error on
|
||||
XEN_PCI_OP_enable_msi when device has MSI or MSI-X enabled
|
||||
|
||||
The guest sequence of:
|
||||
|
||||
a) XEN_PCI_OP_enable_msi
|
||||
b) XEN_PCI_OP_enable_msi
|
||||
c) XEN_PCI_OP_disable_msi
|
||||
|
||||
results in hitting an BUG_ON condition in the msi.c code.
|
||||
|
||||
The MSI code uses an dev->msi_list to which it adds MSI entries.
|
||||
Under the above conditions an BUG_ON() can be hit. The device
|
||||
passed in the guest MUST have MSI capability.
|
||||
|
||||
The a) adds the entry to the dev->msi_list and sets msi_enabled.
|
||||
The b) adds a second entry but adding in to SysFS fails (duplicate entry)
|
||||
and deletes all of the entries from msi_list and returns (with msi_enabled
|
||||
is still set). c) pci_disable_msi passes the msi_enabled checks and hits:
|
||||
|
||||
BUG_ON(list_empty(dev_to_msi_list(&dev->dev)));
|
||||
|
||||
and blows up.
|
||||
|
||||
The patch adds a simple check in the XEN_PCI_OP_enable_msi to guard
|
||||
against that. The check for msix_enabled is not stricly neccessary.
|
||||
|
||||
This is part of XSA-157.
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/xen/xen-pciback/pciback_ops.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
|
||||
index c4a0666..5ce573a 100644
|
||||
--- a/drivers/xen/xen-pciback/pciback_ops.c
|
||||
+++ b/drivers/xen/xen-pciback/pciback_ops.c
|
||||
@@ -144,7 +144,12 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev,
|
||||
if (unlikely(verbose_request))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s: enable MSI\n", pci_name(dev));
|
||||
|
||||
- status = pci_enable_msi(dev);
|
||||
+ if (dev->msi_enabled)
|
||||
+ status = -EALREADY;
|
||||
+ else if (dev->msix_enabled)
|
||||
+ status = -ENXIO;
|
||||
+ else
|
||||
+ status = pci_enable_msi(dev);
|
||||
|
||||
if (status) {
|
||||
pr_warn_ratelimited("%s: error enabling MSI for guest %u: err %d\n",
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,81 +0,0 @@
|
||||
From aa48314c60da1035a8e6cc05bec12838a074de98 Mon Sep 17 00:00:00 2001
|
||||
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
Date: Mon, 2 Nov 2015 17:24:08 -0500
|
||||
Subject: [PATCH v2 XSA157 3/5] xen/pciback: Do not install an IRQ handler for
|
||||
MSI interrupts.
|
||||
|
||||
Otherwise an guest can subvert the generic MSI code to trigger
|
||||
an BUG_ON condition during MSI interrupt freeing:
|
||||
|
||||
for (i = 0; i < entry->nvec_used; i++)
|
||||
BUG_ON(irq_has_action(entry->irq + i));
|
||||
|
||||
Xen PCI backed installs an IRQ handler (request_irq) for
|
||||
the dev->irq whenever the guest writes PCI_COMMAND_MEMORY
|
||||
(or PCI_COMMAND_IO) to the PCI_COMMAND register. This is
|
||||
done in case the device has legacy interrupts the GSI line
|
||||
is shared by the backend devices.
|
||||
|
||||
To subvert the backend the guest needs to make the backend
|
||||
to change the dev->irq from the GSI to the MSI interrupt line,
|
||||
make the backend allocate an interrupt handler, and then command
|
||||
the backend to free the MSI interrupt and hit the BUG_ON.
|
||||
|
||||
Since the backend only calls 'request_irq' when the guest
|
||||
writes to the PCI_COMMAND register the guest needs to call
|
||||
XEN_PCI_OP_enable_msi before any other operation. This will
|
||||
cause the generic MSI code to setup an MSI entry and
|
||||
populate dev->irq with the new PIRQ value.
|
||||
|
||||
Then the guest can write to PCI_COMMAND PCI_COMMAND_MEMORY
|
||||
and cause the backend to setup an IRQ handler for dev->irq
|
||||
(which instead of the GSI value has the MSI pirq). See
|
||||
'xen_pcibk_control_isr'.
|
||||
|
||||
Then the guest disables the MSI: XEN_PCI_OP_disable_msi
|
||||
which ends up triggering the BUG_ON condition in 'free_msi_irqs'
|
||||
as there is an IRQ handler for the entry->irq (dev->irq).
|
||||
|
||||
Note that this cannot be done using MSI-X as the generic
|
||||
code does not over-write dev->irq with the MSI-X PIRQ values.
|
||||
|
||||
The patch inhibits setting up the IRQ handler if MSI or
|
||||
MSI-X (for symmetry reasons) code had been called successfully.
|
||||
|
||||
P.S.
|
||||
Xen PCIBack when it sets up the device for the guest consumption
|
||||
ends up writting 0 to the PCI_COMMAND (see xen_pcibk_reset_device).
|
||||
XSA-120 addendum patch removed that - however when upstreaming said
|
||||
addendum we found that it caused issues with qemu upstream. That
|
||||
has now been fixed in qemu upstream.
|
||||
|
||||
This is part of XSA-157
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/xen/xen-pciback/pciback_ops.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
|
||||
index a107928..5bb76c0 100644
|
||||
--- a/drivers/xen/xen-pciback/pciback_ops.c
|
||||
+++ b/drivers/xen/xen-pciback/pciback_ops.c
|
||||
@@ -70,6 +70,13 @@ static void xen_pcibk_control_isr(struct pci_dev *dev, int reset)
|
||||
enable ? "enable" : "disable");
|
||||
|
||||
if (enable) {
|
||||
+ /*
|
||||
+ * The MSI or MSI-X should not have an IRQ handler. Otherwise
|
||||
+ * if the guest terminates we BUG_ON in free_msi_irqs.
|
||||
+ */
|
||||
+ if (dev->msi_enabled || dev->msix_enabled)
|
||||
+ goto out;
|
||||
+
|
||||
rc = request_irq(dev_data->irq,
|
||||
xen_pcibk_guest_interrupt, IRQF_SHARED,
|
||||
dev_data->irq_name, dev);
|
||||
--
|
||||
2.1.0
|
||||
|
@ -1,105 +0,0 @@
|
||||
From 59a403750d3796b45376041a4843fcde436ae37e Mon Sep 17 00:00:00 2001
|
||||
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
Date: Wed, 1 Apr 2015 10:49:47 -0400
|
||||
Subject: [PATCH v2 XSA157 4/5] xen/pciback: For XEN_PCI_OP_disable_msi[|x]
|
||||
only disable if device has MSI(X) enabled.
|
||||
|
||||
Otherwise just continue on, returning the same values as
|
||||
previously (return of 0, and op->result has the PIRQ value).
|
||||
|
||||
This does not change the behavior of XEN_PCI_OP_disable_msi[|x].
|
||||
|
||||
The pci_disable_msi or pci_disable_msix have the checks for
|
||||
msi_enabled or msix_enabled so they will error out immediately.
|
||||
|
||||
However the guest can still call these operations and cause
|
||||
us to disable the 'ack_intr'. That means the backend IRQ handler
|
||||
for the legacy interrupt will not respond to interrupts anymore.
|
||||
|
||||
This will lead to (if the device is causing an interrupt storm)
|
||||
for the Linux generic code to disable the interrupt line.
|
||||
|
||||
Naturally this will only happen if the device in question
|
||||
is plugged in on the motherboard on shared level interrupt GSI.
|
||||
|
||||
This is part of XSA-157
|
||||
|
||||
CC: stable@vger.kernel.org
|
||||
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
|
||||
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
|
||||
---
|
||||
drivers/xen/xen-pciback/pciback_ops.c | 33 ++++++++++++++++++++-------------
|
||||
1 file changed, 20 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
|
||||
index 5bb76c0..648c09c 100644
|
||||
--- a/drivers/xen/xen-pciback/pciback_ops.c
|
||||
+++ b/drivers/xen/xen-pciback/pciback_ops.c
|
||||
@@ -185,20 +185,23 @@ static
|
||||
int xen_pcibk_disable_msi(struct xen_pcibk_device *pdev,
|
||||
struct pci_dev *dev, struct xen_pci_op *op)
|
||||
{
|
||||
- struct xen_pcibk_dev_data *dev_data;
|
||||
-
|
||||
if (unlikely(verbose_request))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s: disable MSI\n",
|
||||
pci_name(dev));
|
||||
- pci_disable_msi(dev);
|
||||
|
||||
+ if (dev->msi_enabled) {
|
||||
+ struct xen_pcibk_dev_data *dev_data;
|
||||
+
|
||||
+ pci_disable_msi(dev);
|
||||
+
|
||||
+ dev_data = pci_get_drvdata(dev);
|
||||
+ if (dev_data)
|
||||
+ dev_data->ack_intr = 1;
|
||||
+ }
|
||||
op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
|
||||
if (unlikely(verbose_request))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s: MSI: %d\n", pci_name(dev),
|
||||
op->value);
|
||||
- dev_data = pci_get_drvdata(dev);
|
||||
- if (dev_data)
|
||||
- dev_data->ack_intr = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -264,23 +267,27 @@ static
|
||||
int xen_pcibk_disable_msix(struct xen_pcibk_device *pdev,
|
||||
struct pci_dev *dev, struct xen_pci_op *op)
|
||||
{
|
||||
- struct xen_pcibk_dev_data *dev_data;
|
||||
if (unlikely(verbose_request))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s: disable MSI-X\n",
|
||||
pci_name(dev));
|
||||
- pci_disable_msix(dev);
|
||||
|
||||
+ if (dev->msix_enabled) {
|
||||
+ struct xen_pcibk_dev_data *dev_data;
|
||||
+
|
||||
+ pci_disable_msix(dev);
|
||||
+
|
||||
+ dev_data = pci_get_drvdata(dev);
|
||||
+ if (dev_data)
|
||||
+ dev_data->ack_intr = 1;
|
||||
+ }
|
||||
/*
|
||||
* SR-IOV devices (which don't have any legacy IRQ) have
|
||||
* an undefined IRQ value of zero.
|
||||
*/
|
||||
op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
|
||||
if (unlikely(verbose_request))
|
||||
- printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", pci_name(dev),
|
||||
- op->value);
|
||||
- dev_data = pci_get_drvdata(dev);
|
||||
- if (dev_data)
|
||||
- dev_data->ack_intr = 1;
|
||||
+ printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n",
|
||||
+ pci_name(dev), op->value);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
--
|
||||
2.1.0
|
||||
|
Loading…
Reference in new issue