|
|
4d6e2c0 |
From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= <roger.pau@citrix.com>
|
|
|
4d6e2c0 |
Subject: rwlock: introduce support for blocking speculation into critical
|
|
|
4d6e2c0 |
regions
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
Introduce inline wrappers as required and add direct calls to
|
|
|
4d6e2c0 |
block_lock_speculation() in order to prevent speculation into the rwlock
|
|
|
4d6e2c0 |
protected critical regions.
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
Note the rwlock primitives are adjusted to use the non speculation safe variants
|
|
|
4d6e2c0 |
of the spinlock handlers, as a speculation barrier is added in the rwlock
|
|
|
4d6e2c0 |
calling wrappers.
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
trylock variants are protected by using lock_evaluate_nospec().
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
This is part of XSA-453 / CVE-2024-2193
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
|
|
|
4d6e2c0 |
Reviewed-by: Jan Beulich <jbeulich@suse.com>
|
|
|
4d6e2c0 |
(cherry picked from commit a1fb15f61692b1fa9945fc51f55471ace49cdd59)
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c
|
|
|
4d6e2c0 |
index 18224a4bb5d6..290602936df6 100644
|
|
|
4d6e2c0 |
--- a/xen/common/rwlock.c
|
|
|
4d6e2c0 |
+++ b/xen/common/rwlock.c
|
|
|
4d6e2c0 |
@@ -34,8 +34,11 @@ void queue_read_lock_slowpath(rwlock_t *lock)
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
/*
|
|
|
4d6e2c0 |
* Put the reader into the wait queue.
|
|
|
4d6e2c0 |
+ *
|
|
|
4d6e2c0 |
+ * Use the speculation unsafe helper, as it's the caller responsibility to
|
|
|
4d6e2c0 |
+ * issue a speculation barrier if required.
|
|
|
4d6e2c0 |
*/
|
|
|
4d6e2c0 |
- spin_lock(&lock->lock);
|
|
|
4d6e2c0 |
+ _spin_lock(&lock->lock);
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
/*
|
|
|
4d6e2c0 |
* At the head of the wait queue now, wait until the writer state
|
|
|
4d6e2c0 |
@@ -66,8 +69,13 @@ void queue_write_lock_slowpath(rwlock_t *lock)
|
|
|
4d6e2c0 |
{
|
|
|
4d6e2c0 |
u32 cnts;
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
- /* Put the writer into the wait queue. */
|
|
|
4d6e2c0 |
- spin_lock(&lock->lock);
|
|
|
4d6e2c0 |
+ /*
|
|
|
4d6e2c0 |
+ * Put the writer into the wait queue.
|
|
|
4d6e2c0 |
+ *
|
|
|
4d6e2c0 |
+ * Use the speculation unsafe helper, as it's the caller responsibility to
|
|
|
4d6e2c0 |
+ * issue a speculation barrier if required.
|
|
|
4d6e2c0 |
+ */
|
|
|
4d6e2c0 |
+ _spin_lock(&lock->lock);
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
/* Try to acquire the lock directly if no reader is present. */
|
|
|
4d6e2c0 |
if ( !atomic_read(&lock->cnts) &&
|
|
|
4d6e2c0 |
diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h
|
|
|
4d6e2c0 |
index e0d2b41c5c7e..9a0d3ec23847 100644
|
|
|
4d6e2c0 |
--- a/xen/include/xen/rwlock.h
|
|
|
4d6e2c0 |
+++ b/xen/include/xen/rwlock.h
|
|
|
4d6e2c0 |
@@ -259,27 +259,49 @@ static inline int _rw_is_write_locked(const rwlock_t *lock)
|
|
|
4d6e2c0 |
return (atomic_read(&lock->cnts) & _QW_WMASK) == _QW_LOCKED;
|
|
|
4d6e2c0 |
}
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
-#define read_lock(l) _read_lock(l)
|
|
|
4d6e2c0 |
-#define read_lock_irq(l) _read_lock_irq(l)
|
|
|
4d6e2c0 |
+static always_inline void read_lock(rwlock_t *l)
|
|
|
4d6e2c0 |
+{
|
|
|
4d6e2c0 |
+ _read_lock(l);
|
|
|
4d6e2c0 |
+ block_lock_speculation();
|
|
|
4d6e2c0 |
+}
|
|
|
4d6e2c0 |
+
|
|
|
4d6e2c0 |
+static always_inline void read_lock_irq(rwlock_t *l)
|
|
|
4d6e2c0 |
+{
|
|
|
4d6e2c0 |
+ _read_lock_irq(l);
|
|
|
4d6e2c0 |
+ block_lock_speculation();
|
|
|
4d6e2c0 |
+}
|
|
|
4d6e2c0 |
+
|
|
|
4d6e2c0 |
#define read_lock_irqsave(l, f) \
|
|
|
4d6e2c0 |
({ \
|
|
|
4d6e2c0 |
BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \
|
|
|
4d6e2c0 |
((f) = _read_lock_irqsave(l)); \
|
|
|
4d6e2c0 |
+ block_lock_speculation(); \
|
|
|
4d6e2c0 |
})
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
#define read_unlock(l) _read_unlock(l)
|
|
|
4d6e2c0 |
#define read_unlock_irq(l) _read_unlock_irq(l)
|
|
|
4d6e2c0 |
#define read_unlock_irqrestore(l, f) _read_unlock_irqrestore(l, f)
|
|
|
4d6e2c0 |
-#define read_trylock(l) _read_trylock(l)
|
|
|
4d6e2c0 |
+#define read_trylock(l) lock_evaluate_nospec(_read_trylock(l))
|
|
|
4d6e2c0 |
+
|
|
|
4d6e2c0 |
+static always_inline void write_lock(rwlock_t *l)
|
|
|
4d6e2c0 |
+{
|
|
|
4d6e2c0 |
+ _write_lock(l);
|
|
|
4d6e2c0 |
+ block_lock_speculation();
|
|
|
4d6e2c0 |
+}
|
|
|
4d6e2c0 |
+
|
|
|
4d6e2c0 |
+static always_inline void write_lock_irq(rwlock_t *l)
|
|
|
4d6e2c0 |
+{
|
|
|
4d6e2c0 |
+ _write_lock_irq(l);
|
|
|
4d6e2c0 |
+ block_lock_speculation();
|
|
|
4d6e2c0 |
+}
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
-#define write_lock(l) _write_lock(l)
|
|
|
4d6e2c0 |
-#define write_lock_irq(l) _write_lock_irq(l)
|
|
|
4d6e2c0 |
#define write_lock_irqsave(l, f) \
|
|
|
4d6e2c0 |
({ \
|
|
|
4d6e2c0 |
BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \
|
|
|
4d6e2c0 |
((f) = _write_lock_irqsave(l)); \
|
|
|
4d6e2c0 |
+ block_lock_speculation(); \
|
|
|
4d6e2c0 |
})
|
|
|
4d6e2c0 |
-#define write_trylock(l) _write_trylock(l)
|
|
|
4d6e2c0 |
+#define write_trylock(l) lock_evaluate_nospec(_write_trylock(l))
|
|
|
4d6e2c0 |
|
|
|
4d6e2c0 |
#define write_unlock(l) _write_unlock(l)
|
|
|
4d6e2c0 |
#define write_unlock_irq(l) _write_unlock_irq(l)
|