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)