Skip to content

Commit e91c251

Browse files
pmladekJiri Kosina
authored andcommitted
livepatch: Initialize shadow variables safely by a custom callback
The existing API allows to pass a sample data to initialize the shadow data. It works well when the data are position independent. But it fails miserably when we need to set a pointer to the shadow structure itself. Unfortunately, we might need to initialize the pointer surprisingly often because of struct list_head. It is even worse because the list might be hidden in other common structures, for example, struct mutex, struct wait_queue_head. For example, this was needed to fix races in ALSA sequencer. It required to add mutex into struct snd_seq_client. See commit b3defb7 ("ALSA: seq: Make ioctls race-free") and commit d15d662 ("ALSA: seq: Fix racy pool initializations") This patch makes the API more safe. A custom constructor function and data are passed to klp_shadow_*alloc() functions instead of the sample data. Note that ctor_data are no longer a template for shadow->data. It might point to any data that might be necessary when the constructor is called. Also note that the constructor is called under klp_shadow_lock. It is an internal spin_lock that synchronizes alloc() vs. get() operations, see klp_shadow_get_or_alloc(). On one hand, this adds a risk of ABBA deadlocks. On the other hand, it allows to do some operations safely. For example, we could add the new structure into an existing list. This must be done only once when the structure is allocated. Reported-by: Nicolai Stange <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Acked-by: Miroslav Benes <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent e1c70f3 commit e91c251

File tree

5 files changed

+104
-47
lines changed

5 files changed

+104
-47
lines changed

Documentation/livepatch/shadow-vars.txt

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ meta-data and shadow-data:
3434
- data[] - storage for shadow data
3535

3636
It is important to note that the klp_shadow_alloc() and
37-
klp_shadow_get_or_alloc() calls, described below, store a *copy* of the
38-
data that the functions are provided. Callers should provide whatever
39-
mutual exclusion is required of the shadow data.
37+
klp_shadow_get_or_alloc() are zeroing the variable by default.
38+
They also allow to call a custom constructor function when a non-zero
39+
value is needed. Callers should provide whatever mutual exclusion
40+
is required.
41+
42+
Note that the constructor is called under klp_shadow_lock spinlock. It allows
43+
to do actions that can be done only once when a new variable is allocated.
4044

4145
* klp_shadow_get() - retrieve a shadow variable data pointer
4246
- search hashtable for <obj, id> pair
@@ -47,7 +51,7 @@ mutual exclusion is required of the shadow data.
4751
- WARN and return NULL
4852
- if <obj, id> doesn't already exist
4953
- allocate a new shadow variable
50-
- copy data into the new shadow variable
54+
- initialize the variable using a custom constructor and data when provided
5155
- add <obj, id> to the global hashtable
5256

5357
* klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable
@@ -56,7 +60,7 @@ mutual exclusion is required of the shadow data.
5660
- return existing shadow variable
5761
- if <obj, id> doesn't already exist
5862
- allocate a new shadow variable
59-
- copy data into the new shadow variable
63+
- initialize the variable using a custom constructor and data when provided
6064
- add <obj, id> pair to the global hashtable
6165

6266
* klp_shadow_free() - detach and free a <obj, id> shadow variable
@@ -107,7 +111,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
107111
sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
108112

109113
/* Attach a corresponding shadow variable, then initialize it */
110-
ps_lock = klp_shadow_alloc(sta, PS_LOCK, NULL, sizeof(*ps_lock), gfp);
114+
ps_lock = klp_shadow_alloc(sta, PS_LOCK, sizeof(*ps_lock), gfp,
115+
NULL, NULL);
111116
if (!ps_lock)
112117
goto shadow_fail;
113118
spin_lock_init(ps_lock);
@@ -148,16 +153,24 @@ shadow variables to parents already in-flight.
148153
For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is
149154
inside ieee80211_sta_ps_deliver_wakeup():
150155

156+
int ps_lock_shadow_ctor(void *obj, void *shadow_data, void *ctor_data)
157+
{
158+
spinlock_t *lock = shadow_data;
159+
160+
spin_lock_init(lock);
161+
return 0;
162+
}
163+
151164
#define PS_LOCK 1
152165
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
153166
{
154-
DEFINE_SPINLOCK(ps_lock_fallback);
155167
spinlock_t *ps_lock;
156168

157169
/* sync with ieee80211_tx_h_unicast_ps_buf */
158170
ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK,
159-
&ps_lock_fallback, sizeof(ps_lock_fallback),
160-
GFP_ATOMIC);
171+
sizeof(*ps_lock), GFP_ATOMIC,
172+
ps_lock_shadow_ctor, NULL);
173+
161174
if (ps_lock)
162175
spin_lock(ps_lock);
163176
...

include/linux/livepatch.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,17 @@ static inline bool klp_have_reliable_stack(void)
186186
IS_ENABLED(CONFIG_HAVE_RELIABLE_STACKTRACE);
187187
}
188188

189+
typedef int (*klp_shadow_ctor_t)(void *obj,
190+
void *shadow_data,
191+
void *ctor_data);
192+
189193
void *klp_shadow_get(void *obj, unsigned long id);
190-
void *klp_shadow_alloc(void *obj, unsigned long id, void *data,
191-
size_t size, gfp_t gfp_flags);
192-
void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
193-
size_t size, gfp_t gfp_flags);
194+
void *klp_shadow_alloc(void *obj, unsigned long id,
195+
size_t size, gfp_t gfp_flags,
196+
klp_shadow_ctor_t ctor, void *ctor_data);
197+
void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
198+
size_t size, gfp_t gfp_flags,
199+
klp_shadow_ctor_t ctor, void *ctor_data);
194200
void klp_shadow_free(void *obj, unsigned long id);
195201
void klp_shadow_free_all(unsigned long id);
196202

kernel/livepatch/shadow.c

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,10 @@ void *klp_shadow_get(void *obj, unsigned long id)
113113
}
114114
EXPORT_SYMBOL_GPL(klp_shadow_get);
115115

116-
static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
117-
size_t size, gfp_t gfp_flags, bool warn_on_exist)
116+
static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id,
117+
size_t size, gfp_t gfp_flags,
118+
klp_shadow_ctor_t ctor, void *ctor_data,
119+
bool warn_on_exist)
118120
{
119121
struct klp_shadow *new_shadow;
120122
void *shadow_data;
@@ -125,18 +127,15 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
125127
if (shadow_data)
126128
goto exists;
127129

128-
/* Allocate a new shadow variable for use inside the lock below */
130+
/*
131+
* Allocate a new shadow variable. Fill it with zeroes by default.
132+
* More complex setting can be done by @ctor function. But it is
133+
* called only when the buffer is really used (under klp_shadow_lock).
134+
*/
129135
new_shadow = kzalloc(size + sizeof(*new_shadow), gfp_flags);
130136
if (!new_shadow)
131137
return NULL;
132138

133-
new_shadow->obj = obj;
134-
new_shadow->id = id;
135-
136-
/* Initialize the shadow variable if data provided */
137-
if (data)
138-
memcpy(new_shadow->data, data, size);
139-
140139
/* Look for <obj, id> again under the lock */
141140
spin_lock_irqsave(&klp_shadow_lock, flags);
142141
shadow_data = klp_shadow_get(obj, id);
@@ -150,6 +149,22 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
150149
goto exists;
151150
}
152151

152+
new_shadow->obj = obj;
153+
new_shadow->id = id;
154+
155+
if (ctor) {
156+
int err;
157+
158+
err = ctor(obj, new_shadow->data, ctor_data);
159+
if (err) {
160+
spin_unlock_irqrestore(&klp_shadow_lock, flags);
161+
kfree(new_shadow);
162+
pr_err("Failed to construct shadow variable <%p, %lx> (%d)\n",
163+
obj, id, err);
164+
return NULL;
165+
}
166+
}
167+
153168
/* No <obj, id> found, so attach the newly allocated one */
154169
hash_add_rcu(klp_shadow_hash, &new_shadow->node,
155170
(unsigned long)new_shadow->obj);
@@ -170,52 +185,61 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
170185
* klp_shadow_alloc() - allocate and add a new shadow variable
171186
* @obj: pointer to parent object
172187
* @id: data identifier
173-
* @data: pointer to data to attach to parent
174188
* @size: size of attached data
175189
* @gfp_flags: GFP mask for allocation
190+
* @ctor: custom constructor to initialize the shadow data (optional)
191+
* @ctor_data: pointer to any data needed by @ctor (optional)
192+
*
193+
* Allocates @size bytes for new shadow variable data using @gfp_flags.
194+
* The data are zeroed by default. They are further initialized by @ctor
195+
* function if it is not NULL. The new shadow variable is then added
196+
* to the global hashtable.
176197
*
177-
* Allocates @size bytes for new shadow variable data using @gfp_flags
178-
* and copies @size bytes from @data into the new shadow variable's own
179-
* data space. If @data is NULL, @size bytes are still allocated, but
180-
* no copy is performed. The new shadow variable is then added to the
181-
* global hashtable.
198+
* If an existing <obj, id> shadow variable can be found, this routine will
199+
* issue a WARN, exit early and return NULL.
182200
*
183-
* If an existing <obj, id> shadow variable can be found, this routine
184-
* will issue a WARN, exit early and return NULL.
201+
* This function guarantees that the constructor function is called only when
202+
* the variable did not exist before. The cost is that @ctor is called
203+
* in atomic context under a spin lock.
185204
*
186205
* Return: the shadow variable data element, NULL on duplicate or
187206
* failure.
188207
*/
189-
void *klp_shadow_alloc(void *obj, unsigned long id, void *data,
190-
size_t size, gfp_t gfp_flags)
208+
void *klp_shadow_alloc(void *obj, unsigned long id,
209+
size_t size, gfp_t gfp_flags,
210+
klp_shadow_ctor_t ctor, void *ctor_data)
191211
{
192-
return __klp_shadow_get_or_alloc(obj, id, data, size, gfp_flags, true);
212+
return __klp_shadow_get_or_alloc(obj, id, size, gfp_flags,
213+
ctor, ctor_data, true);
193214
}
194215
EXPORT_SYMBOL_GPL(klp_shadow_alloc);
195216

196217
/**
197218
* klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable
198219
* @obj: pointer to parent object
199220
* @id: data identifier
200-
* @data: pointer to data to attach to parent
201221
* @size: size of attached data
202222
* @gfp_flags: GFP mask for allocation
223+
* @ctor: custom constructor to initialize the shadow data (optional)
224+
* @ctor_data: pointer to any data needed by @ctor (optional)
203225
*
204226
* Returns a pointer to existing shadow data if an <obj, id> shadow
205227
* variable is already present. Otherwise, it creates a new shadow
206228
* variable like klp_shadow_alloc().
207229
*
208-
* This function guarantees that only one shadow variable exists with
209-
* the given @id for the given @obj. It also guarantees that the shadow
210-
* variable will be initialized by the given @data only when it did not
211-
* exist before.
230+
* This function guarantees that only one shadow variable exists with the given
231+
* @id for the given @obj. It also guarantees that the constructor function
232+
* will be called only when the variable did not exist before. The cost is
233+
* that @ctor is called in atomic context under a spin lock.
212234
*
213235
* Return: the shadow variable data element, NULL on failure.
214236
*/
215-
void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data,
216-
size_t size, gfp_t gfp_flags)
237+
void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
238+
size_t size, gfp_t gfp_flags,
239+
klp_shadow_ctor_t ctor, void *ctor_data)
217240
{
218-
return __klp_shadow_get_or_alloc(obj, id, data, size, gfp_flags, false);
241+
return __klp_shadow_get_or_alloc(obj, id, size, gfp_flags,
242+
ctor, ctor_data, false);
219243
}
220244
EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc);
221245

samples/livepatch/livepatch-shadow-fix1.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ struct dummy {
5656
unsigned long jiffies_expire;
5757
};
5858

59+
/*
60+
* The constructor makes more sense together with klp_shadow_get_or_alloc().
61+
* In this example, it would be safe to assign the pointer also to the shadow
62+
* variable returned by klp_shadow_alloc(). But we wanted to show the more
63+
* complicated use of the API.
64+
*/
65+
static int shadow_leak_ctor(void *obj, void *shadow_data, void *ctor_data)
66+
{
67+
void **shadow_leak = shadow_data;
68+
void *leak = ctor_data;
69+
70+
*shadow_leak = leak;
71+
return 0;
72+
}
73+
5974
struct dummy *livepatch_fix1_dummy_alloc(void)
6075
{
6176
struct dummy *d;
@@ -74,7 +89,8 @@ struct dummy *livepatch_fix1_dummy_alloc(void)
7489
* pointer to handle resource release.
7590
*/
7691
leak = kzalloc(sizeof(int), GFP_KERNEL);
77-
klp_shadow_alloc(d, SV_LEAK, &leak, sizeof(leak), GFP_KERNEL);
92+
klp_shadow_alloc(d, SV_LEAK, sizeof(leak), GFP_KERNEL,
93+
shadow_leak_ctor, leak);
7894

7995
pr_info("%s: dummy @ %p, expires @ %lx\n",
8096
__func__, d, d->jiffies_expire);

samples/livepatch/livepatch-shadow-fix2.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,15 @@ struct dummy {
5353
bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies)
5454
{
5555
int *shadow_count;
56-
int count;
5756

5857
/*
5958
* Patch: handle in-flight dummy structures, if they do not
6059
* already have a SV_COUNTER shadow variable, then attach a
6160
* new one.
6261
*/
63-
count = 0;
6462
shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER,
65-
&count, sizeof(count),
66-
GFP_NOWAIT);
63+
sizeof(*shadow_count), GFP_NOWAIT,
64+
NULL, NULL);
6765
if (shadow_count)
6866
*shadow_count += 1;
6967

0 commit comments

Comments
 (0)