1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
From 7454dad6ee15f9fa6d84fc285d366b86f3d47494 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= <roger.pau@citrix.com>
Date: Tue, 13 Feb 2024 16:08:52 +0100
Subject: [PATCH 49/67] rwlock: introduce support for blocking speculation into
critical regions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introduce inline wrappers as required and add direct calls to
block_lock_speculation() in order to prevent speculation into the rwlock
protected critical regions.
Note the rwlock primitives are adjusted to use the non speculation safe variants
of the spinlock handlers, as a speculation barrier is added in the rwlock
calling wrappers.
trylock variants are protected by using lock_evaluate_nospec().
This is part of XSA-453 / CVE-2024-2193
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit a1fb15f61692b1fa9945fc51f55471ace49cdd59)
---
xen/common/rwlock.c | 14 +++++++++++---
xen/include/xen/rwlock.h | 34 ++++++++++++++++++++++++++++------
2 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c
index aa15529bbe..cda06b9d6e 100644
--- a/xen/common/rwlock.c
+++ b/xen/common/rwlock.c
@@ -34,8 +34,11 @@ void queue_read_lock_slowpath(rwlock_t *lock)
/*
* Put the reader into the wait queue.
+ *
+ * Use the speculation unsafe helper, as it's the caller responsibility to
+ * issue a speculation barrier if required.
*/
- spin_lock(&lock->lock);
+ _spin_lock(&lock->lock);
/*
* At the head of the wait queue now, wait until the writer state
@@ -64,8 +67,13 @@ void queue_write_lock_slowpath(rwlock_t *lock)
{
u32 cnts;
- /* Put the writer into the wait queue. */
- spin_lock(&lock->lock);
+ /*
+ * Put the writer into the wait queue.
+ *
+ * Use the speculation unsafe helper, as it's the caller responsibility to
+ * issue a speculation barrier if required.
+ */
+ _spin_lock(&lock->lock);
/* Try to acquire the lock directly if no reader is present. */
if ( !atomic_read(&lock->cnts) &&
diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h
index 0cc9167715..fd0458be94 100644
--- a/xen/include/xen/rwlock.h
+++ b/xen/include/xen/rwlock.h
@@ -247,27 +247,49 @@ static inline int _rw_is_write_locked(rwlock_t *lock)
return (atomic_read(&lock->cnts) & _QW_WMASK) == _QW_LOCKED;
}
-#define read_lock(l) _read_lock(l)
-#define read_lock_irq(l) _read_lock_irq(l)
+static always_inline void read_lock(rwlock_t *l)
+{
+ _read_lock(l);
+ block_lock_speculation();
+}
+
+static always_inline void read_lock_irq(rwlock_t *l)
+{
+ _read_lock_irq(l);
+ block_lock_speculation();
+}
+
#define read_lock_irqsave(l, f) \
({ \
BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \
((f) = _read_lock_irqsave(l)); \
+ block_lock_speculation(); \
})
#define read_unlock(l) _read_unlock(l)
#define read_unlock_irq(l) _read_unlock_irq(l)
#define read_unlock_irqrestore(l, f) _read_unlock_irqrestore(l, f)
-#define read_trylock(l) _read_trylock(l)
+#define read_trylock(l) lock_evaluate_nospec(_read_trylock(l))
+
+static always_inline void write_lock(rwlock_t *l)
+{
+ _write_lock(l);
+ block_lock_speculation();
+}
+
+static always_inline void write_lock_irq(rwlock_t *l)
+{
+ _write_lock_irq(l);
+ block_lock_speculation();
+}
-#define write_lock(l) _write_lock(l)
-#define write_lock_irq(l) _write_lock_irq(l)
#define write_lock_irqsave(l, f) \
({ \
BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long)); \
((f) = _write_lock_irqsave(l)); \
+ block_lock_speculation(); \
})
-#define write_trylock(l) _write_trylock(l)
+#define write_trylock(l) lock_evaluate_nospec(_write_trylock(l))
#define write_unlock(l) _write_unlock(l)
#define write_unlock_irq(l) _write_unlock_irq(l)
--
2.44.0
|