diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-20 11:51:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-20 11:51:55 -0400 |
commit | 41e3bef52e42c03cb7234f2d8419352478c92926 (patch) | |
tree | fb704ba35a9263084a4606d1d326c90cd1591c40 | |
parent | 36e584de256a8155a292a96288bd78a3a328aa4f (diff) | |
parent | 3b2c77d000fe9f7d02e9e726e00dccf9f92b256f (diff) |
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
-rw-r--r-- | Documentation/livepatch/shadow-vars.txt | 41 | ||||
-rw-r--r-- | include/linux/livepatch.h | 19 | ||||
-rw-r--r-- | kernel/livepatch/shadow.c | 108 | ||||
-rw-r--r-- | samples/livepatch/livepatch-shadow-fix1.c | 43 | ||||
-rw-r--r-- | samples/livepatch/livepatch-shadow-fix2.c | 33 |
5 files changed, 163 insertions, 81 deletions
diff --git a/Documentation/livepatch/shadow-vars.txt b/Documentation/livepatch/shadow-vars.txt index 89c66634d600..ecc09a7be5dd 100644 --- a/Documentation/livepatch/shadow-vars.txt +++ b/Documentation/livepatch/shadow-vars.txt | |||
@@ -34,9 +34,13 @@ meta-data and shadow-data: | |||
34 | - data[] - storage for shadow data | 34 | - data[] - storage for shadow data |
35 | 35 | ||
36 | It is important to note that the klp_shadow_alloc() and | 36 | 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 | 37 | klp_shadow_get_or_alloc() are zeroing the variable by default. |
38 | data that the functions are provided. Callers should provide whatever | 38 | They also allow to call a custom constructor function when a non-zero |
39 | mutual exclusion is required of the shadow data. | 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. | ||
40 | 44 | ||
41 | * klp_shadow_get() - retrieve a shadow variable data pointer | 45 | * klp_shadow_get() - retrieve a shadow variable data pointer |
42 | - search hashtable for <obj, id> pair | 46 | - search hashtable for <obj, id> pair |
@@ -47,7 +51,7 @@ mutual exclusion is required of the shadow data. | |||
47 | - WARN and return NULL | 51 | - WARN and return NULL |
48 | - if <obj, id> doesn't already exist | 52 | - if <obj, id> doesn't already exist |
49 | - allocate a new shadow variable | 53 | - 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 |
51 | - add <obj, id> to the global hashtable | 55 | - add <obj, id> to the global hashtable |
52 | 56 | ||
53 | * klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable | 57 | * 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. | |||
56 | - return existing shadow variable | 60 | - return existing shadow variable |
57 | - if <obj, id> doesn't already exist | 61 | - if <obj, id> doesn't already exist |
58 | - allocate a new shadow variable | 62 | - 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 |
60 | - add <obj, id> pair to the global hashtable | 64 | - add <obj, id> pair to the global hashtable |
61 | 65 | ||
62 | * klp_shadow_free() - detach and free a <obj, id> shadow variable | 66 | * klp_shadow_free() - detach and free a <obj, id> shadow variable |
63 | - find and remove a <obj, id> reference from global hashtable | 67 | - 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 | ||
65 | 71 | ||
66 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables | 72 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables |
67 | - find and remove any <*, id> references from global hashtable | 73 | - 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 | ||
69 | 77 | ||
70 | 78 | ||
71 | 2. Use cases | 79 | 2. Use cases |
@@ -107,7 +115,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
107 | sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); | 115 | sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); |
108 | 116 | ||
109 | /* Attach a corresponding shadow variable, then initialize it */ | 117 | /* 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); | ||
111 | if (!ps_lock) | 120 | if (!ps_lock) |
112 | goto shadow_fail; | 121 | goto shadow_fail; |
113 | spin_lock_init(ps_lock); | 122 | spin_lock_init(ps_lock); |
@@ -131,7 +140,7 @@ variable: | |||
131 | 140 | ||
132 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) | 141 | void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) |
133 | { | 142 | { |
134 | klp_shadow_free(sta, PS_LOCK); | 143 | klp_shadow_free(sta, PS_LOCK, NULL); |
135 | kfree(sta); | 144 | kfree(sta); |
136 | ... | 145 | ... |
137 | 146 | ||
@@ -148,16 +157,24 @@ shadow variables to parents already in-flight. | |||
148 | For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is | 157 | For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is |
149 | inside ieee80211_sta_ps_deliver_wakeup(): | 158 | inside ieee80211_sta_ps_deliver_wakeup(): |
150 | 159 | ||
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 | |||
151 | #define PS_LOCK 1 | 168 | #define PS_LOCK 1 |
152 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | 169 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) |
153 | { | 170 | { |
154 | DEFINE_SPINLOCK(ps_lock_fallback); | ||
155 | spinlock_t *ps_lock; | 171 | spinlock_t *ps_lock; |
156 | 172 | ||
157 | /* sync with ieee80211_tx_h_unicast_ps_buf */ | 173 | /* sync with ieee80211_tx_h_unicast_ps_buf */ |
158 | ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK, | 174 | ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK, |
159 | &ps_lock_fallback, sizeof(ps_lock_fallback), | 175 | sizeof(*ps_lock), GFP_ATOMIC, |
160 | GFP_ATOMIC); | 176 | ps_lock_shadow_ctor, NULL); |
177 | |||
161 | if (ps_lock) | 178 | if (ps_lock) |
162 | spin_lock(ps_lock); | 179 | spin_lock(ps_lock); |
163 | ... | 180 | ... |
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 4754f01c1abb..aec44b1d9582 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h | |||
@@ -186,13 +186,20 @@ static inline bool klp_have_reliable_stack(void) | |||
186 | IS_ENABLED(CONFIG_HAVE_RELIABLE_STACKTRACE); | 186 | IS_ENABLED(CONFIG_HAVE_RELIABLE_STACKTRACE); |
187 | } | 187 | } |
188 | 188 | ||
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 | |||
189 | void *klp_shadow_get(void *obj, unsigned long id); | 194 | void *klp_shadow_get(void *obj, unsigned long id); |
190 | void *klp_shadow_alloc(void *obj, unsigned long id, void *data, | 195 | void *klp_shadow_alloc(void *obj, unsigned long id, |
191 | size_t size, gfp_t gfp_flags); | 196 | size_t size, gfp_t gfp_flags, |
192 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | 197 | klp_shadow_ctor_t ctor, void *ctor_data); |
193 | size_t size, gfp_t gfp_flags); | 198 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, |
194 | void klp_shadow_free(void *obj, unsigned long id); | 199 | size_t size, gfp_t gfp_flags, |
195 | void klp_shadow_free_all(unsigned long id); | 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); | ||
196 | 203 | ||
197 | #else /* !CONFIG_LIVEPATCH */ | 204 | #else /* !CONFIG_LIVEPATCH */ |
198 | 205 | ||
diff --git a/kernel/livepatch/shadow.c b/kernel/livepatch/shadow.c index fdac27588d60..83958c814439 100644 --- a/kernel/livepatch/shadow.c +++ b/kernel/livepatch/shadow.c | |||
@@ -113,8 +113,10 @@ void *klp_shadow_get(void *obj, unsigned long id) | |||
113 | } | 113 | } |
114 | EXPORT_SYMBOL_GPL(klp_shadow_get); | 114 | EXPORT_SYMBOL_GPL(klp_shadow_get); |
115 | 115 | ||
116 | static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | 116 | static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, |
117 | size_t size, gfp_t gfp_flags, bool warn_on_exist) | 117 | size_t size, gfp_t gfp_flags, |
118 | klp_shadow_ctor_t ctor, void *ctor_data, | ||
119 | bool warn_on_exist) | ||
118 | { | 120 | { |
119 | struct klp_shadow *new_shadow; | 121 | struct klp_shadow *new_shadow; |
120 | void *shadow_data; | 122 | void *shadow_data; |
@@ -125,18 +127,15 @@ static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | |||
125 | if (shadow_data) | 127 | if (shadow_data) |
126 | goto exists; | 128 | goto exists; |
127 | 129 | ||
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 | */ | ||
129 | new_shadow = kzalloc(size + sizeof(*new_shadow), gfp_flags); | 135 | new_shadow = kzalloc(size + sizeof(*new_shadow), gfp_flags); |
130 | if (!new_shadow) | 136 | if (!new_shadow) |
131 | return NULL; | 137 | return NULL; |
132 | 138 | ||
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 | |||
140 | /* Look for <obj, id> again under the lock */ | 139 | /* Look for <obj, id> again under the lock */ |
141 | spin_lock_irqsave(&klp_shadow_lock, flags); | 140 | spin_lock_irqsave(&klp_shadow_lock, flags); |
142 | shadow_data = klp_shadow_get(obj, id); | 141 | 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, | |||
150 | goto exists; | 149 | goto exists; |
151 | } | 150 | } |
152 | 151 | ||
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 | |||
153 | /* No <obj, id> found, so attach the newly allocated one */ | 168 | /* No <obj, id> found, so attach the newly allocated one */ |
154 | hash_add_rcu(klp_shadow_hash, &new_shadow->node, | 169 | hash_add_rcu(klp_shadow_hash, &new_shadow->node, |
155 | (unsigned long)new_shadow->obj); | 170 | (unsigned long)new_shadow->obj); |
@@ -170,26 +185,32 @@ exists: | |||
170 | * klp_shadow_alloc() - allocate and add a new shadow variable | 185 | * klp_shadow_alloc() - allocate and add a new shadow variable |
171 | * @obj: pointer to parent object | 186 | * @obj: pointer to parent object |
172 | * @id: data identifier | 187 | * @id: data identifier |
173 | * @data: pointer to data to attach to parent | ||
174 | * @size: size of attached data | 188 | * @size: size of attached data |
175 | * @gfp_flags: GFP mask for allocation | 189 | * @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. | ||
176 | * | 197 | * |
177 | * Allocates @size bytes for new shadow variable data using @gfp_flags | 198 | * If an existing <obj, id> shadow variable can be found, this routine will |
178 | * and copies @size bytes from @data into the new shadow variable's own | 199 | * issue a WARN, exit early and return NULL. |
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. | ||
182 | * | 200 | * |
183 | * If an existing <obj, id> shadow variable can be found, this routine | 201 | * This function guarantees that the constructor function is called only when |
184 | * will issue a WARN, exit early and return NULL. | 202 | * the variable did not exist before. The cost is that @ctor is called |
203 | * in atomic context under a spin lock. | ||
185 | * | 204 | * |
186 | * Return: the shadow variable data element, NULL on duplicate or | 205 | * Return: the shadow variable data element, NULL on duplicate or |
187 | * failure. | 206 | * failure. |
188 | */ | 207 | */ |
189 | void *klp_shadow_alloc(void *obj, unsigned long id, void *data, | 208 | void *klp_shadow_alloc(void *obj, unsigned long id, |
190 | size_t size, gfp_t gfp_flags) | 209 | size_t size, gfp_t gfp_flags, |
210 | klp_shadow_ctor_t ctor, void *ctor_data) | ||
191 | { | 211 | { |
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); | ||
193 | } | 214 | } |
194 | EXPORT_SYMBOL_GPL(klp_shadow_alloc); | 215 | EXPORT_SYMBOL_GPL(klp_shadow_alloc); |
195 | 216 | ||
@@ -197,37 +218,51 @@ EXPORT_SYMBOL_GPL(klp_shadow_alloc); | |||
197 | * klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable | 218 | * klp_shadow_get_or_alloc() - get existing or allocate a new shadow variable |
198 | * @obj: pointer to parent object | 219 | * @obj: pointer to parent object |
199 | * @id: data identifier | 220 | * @id: data identifier |
200 | * @data: pointer to data to attach to parent | ||
201 | * @size: size of attached data | 221 | * @size: size of attached data |
202 | * @gfp_flags: GFP mask for allocation | 222 | * @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) | ||
203 | * | 225 | * |
204 | * Returns a pointer to existing shadow data if an <obj, id> shadow | 226 | * Returns a pointer to existing shadow data if an <obj, id> shadow |
205 | * variable is already present. Otherwise, it creates a new shadow | 227 | * variable is already present. Otherwise, it creates a new shadow |
206 | * variable like klp_shadow_alloc(). | 228 | * variable like klp_shadow_alloc(). |
207 | * | 229 | * |
208 | * This function guarantees that only one shadow variable exists with | 230 | * This function guarantees that only one shadow variable exists with the given |
209 | * the given @id for the given @obj. It also guarantees that the shadow | 231 | * @id for the given @obj. It also guarantees that the constructor function |
210 | * variable will be initialized by the given @data only when it did not | 232 | * will be called only when the variable did not exist before. The cost is |
211 | * exist before. | 233 | * that @ctor is called in atomic context under a spin lock. |
212 | * | 234 | * |
213 | * Return: the shadow variable data element, NULL on failure. | 235 | * Return: the shadow variable data element, NULL on failure. |
214 | */ | 236 | */ |
215 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, | 237 | void *klp_shadow_get_or_alloc(void *obj, unsigned long id, |
216 | size_t size, gfp_t gfp_flags) | 238 | size_t size, gfp_t gfp_flags, |
239 | klp_shadow_ctor_t ctor, void *ctor_data) | ||
217 | { | 240 | { |
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); | ||
219 | } | 243 | } |
220 | EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); | 244 | EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); |
221 | 245 | ||
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 | |||
222 | /** | 255 | /** |
223 | * klp_shadow_free() - detach and free a <obj, id> shadow variable | 256 | * klp_shadow_free() - detach and free a <obj, id> shadow variable |
224 | * @obj: pointer to parent object | 257 | * @obj: pointer to parent object |
225 | * @id: data identifier | 258 | * @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) | ||
226 | * | 261 | * |
227 | * This function releases the memory for this <obj, id> shadow variable | 262 | * This function releases the memory for this <obj, id> shadow variable |
228 | * instance, callers should stop referencing it accordingly. | 263 | * instance, callers should stop referencing it accordingly. |
229 | */ | 264 | */ |
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) |
231 | { | 266 | { |
232 | struct klp_shadow *shadow; | 267 | struct klp_shadow *shadow; |
233 | unsigned long flags; | 268 | unsigned long flags; |
@@ -239,8 +274,7 @@ void klp_shadow_free(void *obj, unsigned long id) | |||
239 | (unsigned long)obj) { | 274 | (unsigned long)obj) { |
240 | 275 | ||
241 | if (klp_shadow_match(shadow, obj, id)) { | 276 | if (klp_shadow_match(shadow, obj, id)) { |
242 | hash_del_rcu(&shadow->node); | 277 | klp_shadow_free_struct(shadow, dtor); |
243 | kfree_rcu(shadow, rcu_head); | ||
244 | break; | 278 | break; |
245 | } | 279 | } |
246 | } | 280 | } |
@@ -252,11 +286,13 @@ EXPORT_SYMBOL_GPL(klp_shadow_free); | |||
252 | /** | 286 | /** |
253 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables | 287 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables |
254 | * @id: data identifier | 288 | * @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) | ||
255 | * | 291 | * |
256 | * This function releases the memory for all <*, id> shadow variable | 292 | * This function releases the memory for all <*, id> shadow variable |
257 | * instances, callers should stop referencing them accordingly. | 293 | * instances, callers should stop referencing them accordingly. |
258 | */ | 294 | */ |
259 | void klp_shadow_free_all(unsigned long id) | 295 | void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) |
260 | { | 296 | { |
261 | struct klp_shadow *shadow; | 297 | struct klp_shadow *shadow; |
262 | unsigned long flags; | 298 | unsigned long flags; |
@@ -266,10 +302,8 @@ void klp_shadow_free_all(unsigned long id) | |||
266 | 302 | ||
267 | /* Delete all <*, id> from hash */ | 303 | /* Delete all <*, id> from hash */ |
268 | hash_for_each(klp_shadow_hash, i, shadow, node) { | 304 | hash_for_each(klp_shadow_hash, i, shadow, node) { |
269 | if (klp_shadow_match(shadow, shadow->obj, id)) { | 305 | if (klp_shadow_match(shadow, shadow->obj, id)) |
270 | hash_del_rcu(&shadow->node); | 306 | klp_shadow_free_struct(shadow, dtor); |
271 | kfree_rcu(shadow, rcu_head); | ||
272 | } | ||
273 | } | 307 | } |
274 | 308 | ||
275 | spin_unlock_irqrestore(&klp_shadow_lock, flags); | 309 | spin_unlock_irqrestore(&klp_shadow_lock, flags); |
diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c index 830c55514f9f..49b13553eaae 100644 --- a/samples/livepatch/livepatch-shadow-fix1.c +++ b/samples/livepatch/livepatch-shadow-fix1.c | |||
@@ -56,6 +56,21 @@ struct dummy { | |||
56 | unsigned long jiffies_expire; | 56 | unsigned long jiffies_expire; |
57 | }; | 57 | }; |
58 | 58 | ||
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 | |||
59 | struct dummy *livepatch_fix1_dummy_alloc(void) | 74 | struct dummy *livepatch_fix1_dummy_alloc(void) |
60 | { | 75 | { |
61 | struct dummy *d; | 76 | struct dummy *d; |
@@ -74,7 +89,8 @@ struct dummy *livepatch_fix1_dummy_alloc(void) | |||
74 | * pointer to handle resource release. | 89 | * pointer to handle resource release. |
75 | */ | 90 | */ |
76 | leak = kzalloc(sizeof(int), GFP_KERNEL); | 91 | 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); | ||
78 | 94 | ||
79 | pr_info("%s: dummy @ %p, expires @ %lx\n", | 95 | pr_info("%s: dummy @ %p, expires @ %lx\n", |
80 | __func__, d, d->jiffies_expire); | 96 | __func__, d, d->jiffies_expire); |
@@ -82,9 +98,19 @@ struct dummy *livepatch_fix1_dummy_alloc(void) | |||
82 | return d; | 98 | return d; |
83 | } | 99 | } |
84 | 100 | ||
101 | static void livepatch_fix1_dummy_leak_dtor(void *obj, void *shadow_data) | ||
102 | { | ||
103 | void *d = obj; | ||
104 | void **shadow_leak = shadow_data; | ||
105 | |||
106 | kfree(*shadow_leak); | ||
107 | pr_info("%s: dummy @ %p, prevented leak @ %p\n", | ||
108 | __func__, d, *shadow_leak); | ||
109 | } | ||
110 | |||
85 | void livepatch_fix1_dummy_free(struct dummy *d) | 111 | void livepatch_fix1_dummy_free(struct dummy *d) |
86 | { | 112 | { |
87 | void **shadow_leak, *leak; | 113 | void **shadow_leak; |
88 | 114 | ||
89 | /* | 115 | /* |
90 | * Patch: fetch the saved SV_LEAK shadow variable, detach and | 116 | * Patch: fetch the saved SV_LEAK shadow variable, detach and |
@@ -93,15 +119,10 @@ void livepatch_fix1_dummy_free(struct dummy *d) | |||
93 | * was loaded.) | 119 | * was loaded.) |
94 | */ | 120 | */ |
95 | shadow_leak = klp_shadow_get(d, SV_LEAK); | 121 | shadow_leak = klp_shadow_get(d, SV_LEAK); |
96 | if (shadow_leak) { | 122 | if (shadow_leak) |
97 | leak = *shadow_leak; | 123 | klp_shadow_free(d, SV_LEAK, livepatch_fix1_dummy_leak_dtor); |
98 | klp_shadow_free(d, SV_LEAK); | 124 | else |
99 | kfree(leak); | ||
100 | pr_info("%s: dummy @ %p, prevented leak @ %p\n", | ||
101 | __func__, d, leak); | ||
102 | } else { | ||
103 | pr_info("%s: dummy @ %p leaked!\n", __func__, d); | 125 | pr_info("%s: dummy @ %p leaked!\n", __func__, d); |
104 | } | ||
105 | 126 | ||
106 | kfree(d); | 127 | kfree(d); |
107 | } | 128 | } |
@@ -147,7 +168,7 @@ static int livepatch_shadow_fix1_init(void) | |||
147 | static void livepatch_shadow_fix1_exit(void) | 168 | static void livepatch_shadow_fix1_exit(void) |
148 | { | 169 | { |
149 | /* Cleanup any existing SV_LEAK shadow variables */ | 170 | /* Cleanup any existing SV_LEAK shadow variables */ |
150 | klp_shadow_free_all(SV_LEAK); | 171 | klp_shadow_free_all(SV_LEAK, livepatch_fix1_dummy_leak_dtor); |
151 | 172 | ||
152 | WARN_ON(klp_unregister_patch(&patch)); | 173 | WARN_ON(klp_unregister_patch(&patch)); |
153 | } | 174 | } |
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c index ff9948f0ec00..b34c7bf83356 100644 --- a/samples/livepatch/livepatch-shadow-fix2.c +++ b/samples/livepatch/livepatch-shadow-fix2.c | |||
@@ -53,39 +53,42 @@ struct dummy { | |||
53 | bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) | 53 | bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) |
54 | { | 54 | { |
55 | int *shadow_count; | 55 | int *shadow_count; |
56 | int count; | ||
57 | 56 | ||
58 | /* | 57 | /* |
59 | * Patch: handle in-flight dummy structures, if they do not | 58 | * Patch: handle in-flight dummy structures, if they do not |
60 | * already have a SV_COUNTER shadow variable, then attach a | 59 | * already have a SV_COUNTER shadow variable, then attach a |
61 | * new one. | 60 | * new one. |
62 | */ | 61 | */ |
63 | count = 0; | ||
64 | shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, | 62 | shadow_count = klp_shadow_get_or_alloc(d, SV_COUNTER, |
65 | &count, sizeof(count), | 63 | sizeof(*shadow_count), GFP_NOWAIT, |
66 | GFP_NOWAIT); | 64 | NULL, NULL); |
67 | if (shadow_count) | 65 | if (shadow_count) |
68 | *shadow_count += 1; | 66 | *shadow_count += 1; |
69 | 67 | ||
70 | return time_after(jiffies, d->jiffies_expire); | 68 | return time_after(jiffies, d->jiffies_expire); |
71 | } | 69 | } |
72 | 70 | ||
71 | static void livepatch_fix2_dummy_leak_dtor(void *obj, void *shadow_data) | ||
72 | { | ||
73 | void *d = obj; | ||
74 | void **shadow_leak = shadow_data; | ||
75 | |||
76 | kfree(*shadow_leak); | ||
77 | pr_info("%s: dummy @ %p, prevented leak @ %p\n", | ||
78 | __func__, d, *shadow_leak); | ||
79 | } | ||
80 | |||
73 | void livepatch_fix2_dummy_free(struct dummy *d) | 81 | void livepatch_fix2_dummy_free(struct dummy *d) |
74 | { | 82 | { |
75 | void **shadow_leak, *leak; | 83 | void **shadow_leak; |
76 | int *shadow_count; | 84 | int *shadow_count; |
77 | 85 | ||
78 | /* Patch: copy the memory leak patch from the fix1 module. */ | 86 | /* Patch: copy the memory leak patch from the fix1 module. */ |
79 | shadow_leak = klp_shadow_get(d, SV_LEAK); | 87 | shadow_leak = klp_shadow_get(d, SV_LEAK); |
80 | if (shadow_leak) { | 88 | if (shadow_leak) |
81 | leak = *shadow_leak; | 89 | klp_shadow_free(d, SV_LEAK, livepatch_fix2_dummy_leak_dtor); |
82 | klp_shadow_free(d, SV_LEAK); | 90 | else |
83 | kfree(leak); | ||
84 | pr_info("%s: dummy @ %p, prevented leak @ %p\n", | ||
85 | __func__, d, leak); | ||
86 | } else { | ||
87 | pr_info("%s: dummy @ %p leaked!\n", __func__, d); | 91 | pr_info("%s: dummy @ %p leaked!\n", __func__, d); |
88 | } | ||
89 | 92 | ||
90 | /* | 93 | /* |
91 | * Patch: fetch the SV_COUNTER shadow variable and display | 94 | * Patch: fetch the SV_COUNTER shadow variable and display |
@@ -95,7 +98,7 @@ void livepatch_fix2_dummy_free(struct dummy *d) | |||
95 | if (shadow_count) { | 98 | if (shadow_count) { |
96 | pr_info("%s: dummy @ %p, check counter = %d\n", | 99 | pr_info("%s: dummy @ %p, check counter = %d\n", |
97 | __func__, d, *shadow_count); | 100 | __func__, d, *shadow_count); |
98 | klp_shadow_free(d, SV_COUNTER); | 101 | klp_shadow_free(d, SV_COUNTER, NULL); |
99 | } | 102 | } |
100 | 103 | ||
101 | kfree(d); | 104 | kfree(d); |
@@ -142,7 +145,7 @@ static int livepatch_shadow_fix2_init(void) | |||
142 | static void livepatch_shadow_fix2_exit(void) | 145 | static void livepatch_shadow_fix2_exit(void) |
143 | { | 146 | { |
144 | /* Cleanup any existing SV_COUNTER shadow variables */ | 147 | /* Cleanup any existing SV_COUNTER shadow variables */ |
145 | klp_shadow_free_all(SV_COUNTER); | 148 | klp_shadow_free_all(SV_COUNTER, NULL); |
146 | 149 | ||
147 | WARN_ON(klp_unregister_patch(&patch)); | 150 | WARN_ON(klp_unregister_patch(&patch)); |
148 | } | 151 | } |