Skip to content

Commit 41e3bef

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching fix from Jiri Kosina: "Shadow variable API list_head initialization fix from Petr Mladek" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching: livepatch: Allow to call a custom callback when freeing shadow variables livepatch: Initialize shadow variables safely by a custom callback
2 parents 36e584d + 3b2c77d commit 41e3bef

File tree

5 files changed

+163
-81
lines changed

5 files changed

+163
-81
lines changed

Documentation/livepatch/shadow-vars.txt

Lines changed: 29 additions & 12 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,16 +60,20 @@ 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
6367
- find and remove a <obj, id> reference from global hashtable
64-
- if found, free shadow variable
68+
- if found
69+
- call destructor function if defined
70+
- free shadow variable
6571

6672
* klp_shadow_free_all() - detach and free all <*, id> shadow variables
6773
- find and remove any <*, id> references from global hashtable
68-
- if found, free shadow variable
74+
- if found
75+
- call destructor function if defined
76+
- free shadow variable
6977

7078

7179
2. Use cases
@@ -107,7 +115,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
107115
sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
108116

109117
/* Attach a corresponding shadow variable, then initialize it */
110-
ps_lock = klp_shadow_alloc(sta, PS_LOCK, NULL, sizeof(*ps_lock), gfp);
118+
ps_lock = klp_shadow_alloc(sta, PS_LOCK, sizeof(*ps_lock), gfp,
119+
NULL, NULL);
111120
if (!ps_lock)
112121
goto shadow_fail;
113122
spin_lock_init(ps_lock);
@@ -131,7 +140,7 @@ variable:
131140

132141
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
133142
{
134-
klp_shadow_free(sta, PS_LOCK);
143+
klp_shadow_free(sta, PS_LOCK, NULL);
135144
kfree(sta);
136145
...
137146

@@ -148,16 +157,24 @@ shadow variables to parents already in-flight.
148157
For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is
149158
inside ieee80211_sta_ps_deliver_wakeup():
150159

160+
int ps_lock_shadow_ctor(void *obj, void *shadow_data, void *ctor_data)
161+
{
162+
spinlock_t *lock = shadow_data;
163+
164+
spin_lock_init(lock);
165+
return 0;
166+
}
167+
151168
#define PS_LOCK 1
152169
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
153170
{
154-
DEFINE_SPINLOCK(ps_lock_fallback);
155171
spinlock_t *ps_lock;
156172

157173
/* sync with ieee80211_tx_h_unicast_ps_buf */
158174
ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK,
159-
&ps_lock_fallback, sizeof(ps_lock_fallback),
160-
GFP_ATOMIC);
175+
sizeof(*ps_lock), GFP_ATOMIC,
176+
ps_lock_shadow_ctor, NULL);
177+
161178
if (ps_lock)
162179
spin_lock(ps_lock);
163180
...

include/linux/livepatch.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,20 @@ 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+
typedef void (*klp_shadow_dtor_t)(void *obj, void *shadow_data);
193+
189194
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_free(void *obj, unsigned long id);
195-
void klp_shadow_free_all(unsigned long id);
195+
void *klp_shadow_alloc(void *obj, unsigned long id,
196+
size_t size, gfp_t gfp_flags,
197+
klp_shadow_ctor_t ctor, void *ctor_data);
198+
void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
199+
size_t size, gfp_t gfp_flags,
200+
klp_shadow_ctor_t ctor, void *ctor_data);
201+
void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor);
202+
void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor);
196203

197204
#else /* !CONFIG_LIVEPATCH */
198205

kernel/livepatch/shadow.c

Lines changed: 71 additions & 37 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,64 +185,84 @@ 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

246+
static void klp_shadow_free_struct(struct klp_shadow *shadow,
247+
klp_shadow_dtor_t dtor)
248+
{
249+
hash_del_rcu(&shadow->node);
250+
if (dtor)
251+
dtor(shadow->obj, shadow->data);
252+
kfree_rcu(shadow, rcu_head);
253+
}
254+
222255
/**
223256
* klp_shadow_free() - detach and free a <obj, id> shadow variable
224257
* @obj: pointer to parent object
225258
* @id: data identifier
259+
* @dtor: custom callback that can be used to unregister the variable
260+
* and/or free data that the shadow variable points to (optional)
226261
*
227262
* This function releases the memory for this <obj, id> shadow variable
228263
* instance, callers should stop referencing it accordingly.
229264
*/
230-
void klp_shadow_free(void *obj, unsigned long id)
265+
void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor)
231266
{
232267
struct klp_shadow *shadow;
233268
unsigned long flags;
@@ -239,8 +274,7 @@ void klp_shadow_free(void *obj, unsigned long id)
239274
(unsigned long)obj) {
240275

241276
if (klp_shadow_match(shadow, obj, id)) {
242-
hash_del_rcu(&shadow->node);
243-
kfree_rcu(shadow, rcu_head);
277+
klp_shadow_free_struct(shadow, dtor);
244278
break;
245279
}
246280
}
@@ -252,11 +286,13 @@ EXPORT_SYMBOL_GPL(klp_shadow_free);
252286
/**
253287
* klp_shadow_free_all() - detach and free all <*, id> shadow variables
254288
* @id: data identifier
289+
* @dtor: custom callback that can be used to unregister the variable
290+
* and/or free data that the shadow variable points to (optional)
255291
*
256292
* This function releases the memory for all <*, id> shadow variable
257293
* instances, callers should stop referencing them accordingly.
258294
*/
259-
void klp_shadow_free_all(unsigned long id)
295+
void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor)
260296
{
261297
struct klp_shadow *shadow;
262298
unsigned long flags;
@@ -266,10 +302,8 @@ void klp_shadow_free_all(unsigned long id)
266302

267303
/* Delete all <*, id> from hash */
268304
hash_for_each(klp_shadow_hash, i, shadow, node) {
269-
if (klp_shadow_match(shadow, shadow->obj, id)) {
270-
hash_del_rcu(&shadow->node);
271-
kfree_rcu(shadow, rcu_head);
272-
}
305+
if (klp_shadow_match(shadow, shadow->obj, id))
306+
klp_shadow_free_struct(shadow, dtor);
273307
}
274308

275309
spin_unlock_irqrestore(&klp_shadow_lock, flags);

0 commit comments

Comments
 (0)