aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/livepatch/shadow-vars.txt10
-rw-r--r--include/linux/livepatch.h5
-rw-r--r--kernel/livepatch/shadow.c26
-rw-r--r--samples/livepatch/livepatch-shadow-fix1.c25
-rw-r--r--samples/livepatch/livepatch-shadow-fix2.c27
5 files changed, 59 insertions, 34 deletions
diff --git a/Documentation/livepatch/shadow-vars.txt b/Documentation/livepatch/shadow-vars.txt
index 9c7ae191641c..ecc09a7be5dd 100644
--- a/Documentation/livepatch/shadow-vars.txt
+++ b/Documentation/livepatch/shadow-vars.txt
@@ -65,11 +65,15 @@ to do actions that can be done only once when a new variable is allocated.
65 65
66* klp_shadow_free() - detach and free a <obj, id> shadow variable 66* klp_shadow_free() - detach and free a <obj, id> shadow variable
67 - find and remove a <obj, id> reference from global hashtable 67 - find and remove a <obj, id> reference from global hashtable
68 - if found, free shadow variable 68 - if found
69 - call destructor function if defined
70 - free shadow variable
69 71
70* klp_shadow_free_all() - detach and free all <*, id> shadow variables 72* klp_shadow_free_all() - detach and free all <*, id> shadow variables
71 - find and remove any <*, id> references from global hashtable 73 - find and remove any <*, id> references from global hashtable
72 - if found, free shadow variable 74 - if found
75 - call destructor function if defined
76 - free shadow variable
73 77
74 78
752. Use cases 792. Use cases
@@ -136,7 +140,7 @@ variable:
136 140
137void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) 141void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
138{ 142{
139 klp_shadow_free(sta, PS_LOCK); 143 klp_shadow_free(sta, PS_LOCK, NULL);
140 kfree(sta); 144 kfree(sta);
141 ... 145 ...
142 146
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 7e084321b146..aec44b1d9582 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -189,6 +189,7 @@ static inline bool klp_have_reliable_stack(void)
189typedef int (*klp_shadow_ctor_t)(void *obj, 189typedef int (*klp_shadow_ctor_t)(void *obj,
190 void *shadow_data, 190 void *shadow_data,
191 void *ctor_data); 191 void *ctor_data);
192typedef void (*klp_shadow_dtor_t)(void *obj, void *shadow_data);
192 193
193void *klp_shadow_get(void *obj, unsigned long id); 194void *klp_shadow_get(void *obj, unsigned long id);
194void *klp_shadow_alloc(void *obj, unsigned long id, 195void *klp_shadow_alloc(void *obj, unsigned long id,
@@ -197,8 +198,8 @@ void *klp_shadow_alloc(void *obj, unsigned long id,
197void *klp_shadow_get_or_alloc(void *obj, unsigned long id, 198void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
198 size_t size, gfp_t gfp_flags, 199 size_t size, gfp_t gfp_flags,
199 klp_shadow_ctor_t ctor, void *ctor_data); 200 klp_shadow_ctor_t ctor, void *ctor_data);
200void klp_shadow_free(void *obj, unsigned long id); 201void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor);
201void klp_shadow_free_all(unsigned long id); 202void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor);
202 203
203#else /* !CONFIG_LIVEPATCH */ 204#else /* !CONFIG_LIVEPATCH */
204 205
diff --git a/kernel/livepatch/shadow.c b/kernel/livepatch/shadow.c
index b10a0bbb7f84..83958c814439 100644
--- a/kernel/livepatch/shadow.c
+++ b/kernel/livepatch/shadow.c
@@ -243,15 +243,26 @@ void *klp_shadow_get_or_alloc(void *obj, unsigned long id,
243} 243}
244EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); 244EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc);
245 245
246static 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
246/** 255/**
247 * klp_shadow_free() - detach and free a <obj, id> shadow variable 256 * klp_shadow_free() - detach and free a <obj, id> shadow variable
248 * @obj: pointer to parent object 257 * @obj: pointer to parent object
249 * @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)
250 * 261 *
251 * This function releases the memory for this <obj, id> shadow variable 262 * This function releases the memory for this <obj, id> shadow variable
252 * instance, callers should stop referencing it accordingly. 263 * instance, callers should stop referencing it accordingly.
253 */ 264 */
254void klp_shadow_free(void *obj, unsigned long id) 265void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor)
255{ 266{
256 struct klp_shadow *shadow; 267 struct klp_shadow *shadow;
257 unsigned long flags; 268 unsigned long flags;
@@ -263,8 +274,7 @@ void klp_shadow_free(void *obj, unsigned long id)
263 (unsigned long)obj) { 274 (unsigned long)obj) {
264 275
265 if (klp_shadow_match(shadow, obj, id)) { 276 if (klp_shadow_match(shadow, obj, id)) {
266 hash_del_rcu(&shadow->node); 277 klp_shadow_free_struct(shadow, dtor);
267 kfree_rcu(shadow, rcu_head);
268 break; 278 break;
269 } 279 }
270 } 280 }
@@ -276,11 +286,13 @@ EXPORT_SYMBOL_GPL(klp_shadow_free);
276/** 286/**
277 * klp_shadow_free_all() - detach and free all <*, id> shadow variables 287 * klp_shadow_free_all() - detach and free all <*, id> shadow variables
278 * @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)
279 * 291 *
280 * This function releases the memory for all <*, id> shadow variable 292 * This function releases the memory for all <*, id> shadow variable
281 * instances, callers should stop referencing them accordingly. 293 * instances, callers should stop referencing them accordingly.
282 */ 294 */
283void klp_shadow_free_all(unsigned long id) 295void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor)
284{ 296{
285 struct klp_shadow *shadow; 297 struct klp_shadow *shadow;
286 unsigned long flags; 298 unsigned long flags;
@@ -290,10 +302,8 @@ void klp_shadow_free_all(unsigned long id)
290 302
291 /* Delete all <*, id> from hash */ 303 /* Delete all <*, id> from hash */
292 hash_for_each(klp_shadow_hash, i, shadow, node) { 304 hash_for_each(klp_shadow_hash, i, shadow, node) {
293 if (klp_shadow_match(shadow, shadow->obj, id)) { 305 if (klp_shadow_match(shadow, shadow->obj, id))
294 hash_del_rcu(&shadow->node); 306 klp_shadow_free_struct(shadow, dtor);
295 kfree_rcu(shadow, rcu_head);
296 }
297 } 307 }
298 308
299 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 04151c7f2631..49b13553eaae 100644
--- a/samples/livepatch/livepatch-shadow-fix1.c
+++ b/samples/livepatch/livepatch-shadow-fix1.c
@@ -98,9 +98,19 @@ struct dummy *livepatch_fix1_dummy_alloc(void)
98 return d; 98 return d;
99} 99}
100 100
101static 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
101void livepatch_fix1_dummy_free(struct dummy *d) 111void livepatch_fix1_dummy_free(struct dummy *d)
102{ 112{
103 void **shadow_leak, *leak; 113 void **shadow_leak;
104 114
105 /* 115 /*
106 * Patch: fetch the saved SV_LEAK shadow variable, detach and 116 * Patch: fetch the saved SV_LEAK shadow variable, detach and
@@ -109,15 +119,10 @@ void livepatch_fix1_dummy_free(struct dummy *d)
109 * was loaded.) 119 * was loaded.)
110 */ 120 */
111 shadow_leak = klp_shadow_get(d, SV_LEAK); 121 shadow_leak = klp_shadow_get(d, SV_LEAK);
112 if (shadow_leak) { 122 if (shadow_leak)
113 leak = *shadow_leak; 123 klp_shadow_free(d, SV_LEAK, livepatch_fix1_dummy_leak_dtor);
114 klp_shadow_free(d, SV_LEAK); 124 else
115 kfree(leak);
116 pr_info("%s: dummy @ %p, prevented leak @ %p\n",
117 __func__, d, leak);
118 } else {
119 pr_info("%s: dummy @ %p leaked!\n", __func__, d); 125 pr_info("%s: dummy @ %p leaked!\n", __func__, d);
120 }
121 126
122 kfree(d); 127 kfree(d);
123} 128}
@@ -163,7 +168,7 @@ static int livepatch_shadow_fix1_init(void)
163static void livepatch_shadow_fix1_exit(void) 168static void livepatch_shadow_fix1_exit(void)
164{ 169{
165 /* Cleanup any existing SV_LEAK shadow variables */ 170 /* Cleanup any existing SV_LEAK shadow variables */
166 klp_shadow_free_all(SV_LEAK); 171 klp_shadow_free_all(SV_LEAK, livepatch_fix1_dummy_leak_dtor);
167 172
168 WARN_ON(klp_unregister_patch(&patch)); 173 WARN_ON(klp_unregister_patch(&patch));
169} 174}
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c
index d6c62844dc15..b34c7bf83356 100644
--- a/samples/livepatch/livepatch-shadow-fix2.c
+++ b/samples/livepatch/livepatch-shadow-fix2.c
@@ -68,22 +68,27 @@ bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies)
68 return time_after(jiffies, d->jiffies_expire); 68 return time_after(jiffies, d->jiffies_expire);
69} 69}
70 70
71static 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
71void livepatch_fix2_dummy_free(struct dummy *d) 81void livepatch_fix2_dummy_free(struct dummy *d)
72{ 82{
73 void **shadow_leak, *leak; 83 void **shadow_leak;
74 int *shadow_count; 84 int *shadow_count;
75 85
76 /* Patch: copy the memory leak patch from the fix1 module. */ 86 /* Patch: copy the memory leak patch from the fix1 module. */
77 shadow_leak = klp_shadow_get(d, SV_LEAK); 87 shadow_leak = klp_shadow_get(d, SV_LEAK);
78 if (shadow_leak) { 88 if (shadow_leak)
79 leak = *shadow_leak; 89 klp_shadow_free(d, SV_LEAK, livepatch_fix2_dummy_leak_dtor);
80 klp_shadow_free(d, SV_LEAK); 90 else
81 kfree(leak);
82 pr_info("%s: dummy @ %p, prevented leak @ %p\n",
83 __func__, d, leak);
84 } else {
85 pr_info("%s: dummy @ %p leaked!\n", __func__, d); 91 pr_info("%s: dummy @ %p leaked!\n", __func__, d);
86 }
87 92
88 /* 93 /*
89 * Patch: fetch the SV_COUNTER shadow variable and display 94 * Patch: fetch the SV_COUNTER shadow variable and display
@@ -93,7 +98,7 @@ void livepatch_fix2_dummy_free(struct dummy *d)
93 if (shadow_count) { 98 if (shadow_count) {
94 pr_info("%s: dummy @ %p, check counter = %d\n", 99 pr_info("%s: dummy @ %p, check counter = %d\n",
95 __func__, d, *shadow_count); 100 __func__, d, *shadow_count);
96 klp_shadow_free(d, SV_COUNTER); 101 klp_shadow_free(d, SV_COUNTER, NULL);
97 } 102 }
98 103
99 kfree(d); 104 kfree(d);
@@ -140,7 +145,7 @@ static int livepatch_shadow_fix2_init(void)
140static void livepatch_shadow_fix2_exit(void) 145static void livepatch_shadow_fix2_exit(void)
141{ 146{
142 /* Cleanup any existing SV_COUNTER shadow variables */ 147 /* Cleanup any existing SV_COUNTER shadow variables */
143 klp_shadow_free_all(SV_COUNTER); 148 klp_shadow_free_all(SV_COUNTER, NULL);
144 149
145 WARN_ON(klp_unregister_patch(&patch)); 150 WARN_ON(klp_unregister_patch(&patch));
146} 151}