Fix CVE-2020-27675 (rhbz 1891114 1891115)
Signed-off-by: Justin M. Forbes <jforbes@fedoraproject.org>
This commit is contained in:
parent
011aad74d2
commit
82b65923c7
|
@ -0,0 +1,161 @@
|
|||
From 073d0552ead5bfc7a3a9c01de590e924f11b5dd2 Mon Sep 17 00:00:00 2001
|
||||
From: Juergen Gross <jgross@suse.com>
|
||||
Date: Mon, 7 Sep 2020 15:47:27 +0200
|
||||
Subject: [PATCH] xen/events: avoid removing an event channel while handling it
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Today it can happen that an event channel is being removed from the
|
||||
system while the event handling loop is active. This can lead to a
|
||||
race resulting in crashes or WARN() splats when trying to access the
|
||||
irq_info structure related to the event channel.
|
||||
|
||||
Fix this problem by using a rwlock taken as reader in the event
|
||||
handling loop and as writer when deallocating the irq_info structure.
|
||||
|
||||
As the observed problem was a NULL dereference in evtchn_from_irq()
|
||||
make this function more robust against races by testing the irq_info
|
||||
pointer to be not NULL before dereferencing it.
|
||||
|
||||
And finally make all accesses to evtchn_to_irq[row][col] atomic ones
|
||||
in order to avoid seeing partial updates of an array element in irq
|
||||
handling. Note that irq handling can be entered only for event channels
|
||||
which have been valid before, so any not populated row isn't a problem
|
||||
in this regard, as rows are only ever added and never removed.
|
||||
|
||||
This is XSA-331.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
|
||||
Reported-by: Jinoh Kang <luke1337@theori.io>
|
||||
Signed-off-by: Juergen Gross <jgross@suse.com>
|
||||
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
|
||||
Reviewed-by: Wei Liu <wl@xen.org>
|
||||
---
|
||||
drivers/xen/events/events_base.c | 41 ++++++++++++++++++++++++++++----
|
||||
1 file changed, 36 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
|
||||
index 6f02c18fa65c..407741ece084 100644
|
||||
--- a/drivers/xen/events/events_base.c
|
||||
+++ b/drivers/xen/events/events_base.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irqnr.h>
|
||||
#include <linux/pci.h>
|
||||
+#include <linux/spinlock.h>
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/desc.h>
|
||||
@@ -71,6 +72,23 @@ const struct evtchn_ops *evtchn_ops;
|
||||
*/
|
||||
static DEFINE_MUTEX(irq_mapping_update_lock);
|
||||
|
||||
+/*
|
||||
+ * Lock protecting event handling loop against removing event channels.
|
||||
+ * Adding of event channels is no issue as the associated IRQ becomes active
|
||||
+ * only after everything is setup (before request_[threaded_]irq() the handler
|
||||
+ * can't be entered for an event, as the event channel will be unmasked only
|
||||
+ * then).
|
||||
+ */
|
||||
+static DEFINE_RWLOCK(evtchn_rwlock);
|
||||
+
|
||||
+/*
|
||||
+ * Lock hierarchy:
|
||||
+ *
|
||||
+ * irq_mapping_update_lock
|
||||
+ * evtchn_rwlock
|
||||
+ * IRQ-desc lock
|
||||
+ */
|
||||
+
|
||||
static LIST_HEAD(xen_irq_list_head);
|
||||
|
||||
/* IRQ <-> VIRQ mapping. */
|
||||
@@ -105,7 +123,7 @@ static void clear_evtchn_to_irq_row(unsigned row)
|
||||
unsigned col;
|
||||
|
||||
for (col = 0; col < EVTCHN_PER_ROW; col++)
|
||||
- evtchn_to_irq[row][col] = -1;
|
||||
+ WRITE_ONCE(evtchn_to_irq[row][col], -1);
|
||||
}
|
||||
|
||||
static void clear_evtchn_to_irq_all(void)
|
||||
@@ -142,7 +160,7 @@ static int set_evtchn_to_irq(evtchn_port_t evtchn, unsigned int irq)
|
||||
clear_evtchn_to_irq_row(row);
|
||||
}
|
||||
|
||||
- evtchn_to_irq[row][col] = irq;
|
||||
+ WRITE_ONCE(evtchn_to_irq[row][col], irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -152,7 +170,7 @@ int get_evtchn_to_irq(evtchn_port_t evtchn)
|
||||
return -1;
|
||||
if (evtchn_to_irq[EVTCHN_ROW(evtchn)] == NULL)
|
||||
return -1;
|
||||
- return evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)];
|
||||
+ return READ_ONCE(evtchn_to_irq[EVTCHN_ROW(evtchn)][EVTCHN_COL(evtchn)]);
|
||||
}
|
||||
|
||||
/* Get info for IRQ */
|
||||
@@ -261,10 +279,14 @@ static void xen_irq_info_cleanup(struct irq_info *info)
|
||||
*/
|
||||
evtchn_port_t evtchn_from_irq(unsigned irq)
|
||||
{
|
||||
- if (WARN(irq >= nr_irqs, "Invalid irq %d!\n", irq))
|
||||
+ const struct irq_info *info = NULL;
|
||||
+
|
||||
+ if (likely(irq < nr_irqs))
|
||||
+ info = info_for_irq(irq);
|
||||
+ if (!info)
|
||||
return 0;
|
||||
|
||||
- return info_for_irq(irq)->evtchn;
|
||||
+ return info->evtchn;
|
||||
}
|
||||
|
||||
unsigned int irq_from_evtchn(evtchn_port_t evtchn)
|
||||
@@ -440,16 +462,21 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
|
||||
static void xen_free_irq(unsigned irq)
|
||||
{
|
||||
struct irq_info *info = info_for_irq(irq);
|
||||
+ unsigned long flags;
|
||||
|
||||
if (WARN_ON(!info))
|
||||
return;
|
||||
|
||||
+ write_lock_irqsave(&evtchn_rwlock, flags);
|
||||
+
|
||||
list_del(&info->list);
|
||||
|
||||
set_info_for_irq(irq, NULL);
|
||||
|
||||
WARN_ON(info->refcnt > 0);
|
||||
|
||||
+ write_unlock_irqrestore(&evtchn_rwlock, flags);
|
||||
+
|
||||
kfree(info);
|
||||
|
||||
/* Legacy IRQ descriptors are managed by the arch. */
|
||||
@@ -1233,6 +1260,8 @@ static void __xen_evtchn_do_upcall(void)
|
||||
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
+ read_lock(&evtchn_rwlock);
|
||||
+
|
||||
do {
|
||||
vcpu_info->evtchn_upcall_pending = 0;
|
||||
|
||||
@@ -1243,6 +1272,8 @@ static void __xen_evtchn_do_upcall(void)
|
||||
virt_rmb(); /* Hypervisor can set upcall pending. */
|
||||
|
||||
} while (vcpu_info->evtchn_upcall_pending);
|
||||
+
|
||||
+ read_unlock(&evtchn_rwlock);
|
||||
}
|
||||
|
||||
void xen_evtchn_do_upcall(struct pt_regs *regs)
|
||||
--
|
||||
2.28.0
|
||||
|
|
@ -902,6 +902,9 @@ Patch130: arm64-dts-allwinner-h5-OrangePi-PC2-Fix-ethernet-node.patch
|
|||
# https://patchwork.kernel.org/project/linux-arm-kernel/patch/20201023194902.368239-1-jernej.skrabec@siol.net/
|
||||
Patch131: arm64-dts-allwinner-h6-Pine-H64-Fix-ethernet-node.patch
|
||||
|
||||
# CVE-2020-27675 rhbz 1891114 1891115
|
||||
Patch132: 0001-xen-events-avoid-removing-an-event-channel-while-han.patch
|
||||
|
||||
# END OF PATCH DEFINITIONS
|
||||
|
||||
%endif
|
||||
|
@ -3017,6 +3020,7 @@ fi
|
|||
%changelog
|
||||
* Thu Oct 29 07:55:15 CDT 2020 Justin M. Forbes <jforbes@fedoraproject.org> - 5.8.17-300
|
||||
- Linux v5.8.17
|
||||
- Fix CVE-2020-27675 (rhbz 1891114 1891115)
|
||||
|
||||
* Wed Oct 28 2020 Peter Robinson <pbrobinson@fedoraproject.org>
|
||||
- Fixes for AllWinner wired network issues due to Realtek PHY driver change (rhbz 1889090)
|
||||
|
|
Loading…
Reference in New Issue