aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/livepatch/shadow-vars.txt31
-rw-r--r--include/linux/livepatch.h14
-rw-r--r--kernel/livepatch/shadow.c82
-rw-r--r--samples/livepatch/livepatch-shadow-fix1.c18
-rw-r--r--samples/livepatch/livepatch-shadow-fix2.c6
5 files changed, 104 insertions, 47 deletions
diff --git a/Documentation/livepatch/shadow-vars.txt b/Documentation/livepatch/shadow-vars.txt
index 89c66634d600..9c7ae191641c 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
36It is important to note that the klp_shadow_alloc() and 36It is important to note that the klp_shadow_alloc() and
37klp_shadow_get_or_alloc() calls, described below, store a *copy* of the 37klp_shadow_get_or_alloc() are zeroing the variable by default.
38data that the functions are provided. Callers should provide whatever 38They also allow to call a custom constructor function when a non-zero
39mutual exclusion is required of the shadow data. 39value is needed. Callers should provide whatever mutual exclusion
40is required.
41
42Note that the constructor is called under klp_shadow_lock spinlock. It allows
43to 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,7 +60,7 @@ 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
@@ -107,7 +111,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
107 sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); 111 sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
108 112
109 /* Attach a corresponding shadow variable, then initialize it */ 113 /* 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);
111 if (!ps_lock) 116 if (!ps_lock)
112 goto shadow_fail; 117 goto shadow_fail;
113 spin_lock_init(ps_lock); 118 spin_lock_init(ps_lock);
@@ -148,16 +153,24 @@ shadow variables to parents already in-flight.
148For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is 153For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is
149inside ieee80211_sta_ps_deliver_wakeup(): 154inside ieee80211_sta_ps_deliver_wakeup():
150 155
156int 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
151#define PS_LOCK 1 164#define PS_LOCK 1
152void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) 165void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
153{ 166{
154 DEFINE_SPINLOCK(ps_lock_fallback);
155 spinlock_t *ps_lock; 167 spinlock_t *ps_lock;
156 168
157 /* sync with ieee80211_tx_h_unicast_ps_buf */ 169 /* sync with ieee80211_tx_h_unicast_ps_buf */
158 ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK, 170 ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK,
159 &ps_lock_fallback, sizeof(ps_lock_fallback), 171 sizeof(*ps_lock), GFP_ATOMIC,
160 GFP_ATOMIC); 172 ps_lock_shadow_ctor, NULL);
173
161 if (ps_lock) 174 if (ps_lock)
162 spin_lock(ps_lock); 175 spin_lock(ps_lock);
163 ... 176 ...
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 4754f01c1abb..7e084321b146 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -186,11 +186,17 @@ 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
189typedef int (*klp_shadow_ctor_t)(void *obj,
190 void *shadow_data,
191 void *ctor_data);
192
189void *klp_shadow_get(void *obj, unsigned long id); 193void *klp_shadow_get(void *obj, unsigned long id);
190void *klp_shadow_alloc(void *obj, unsigned long id, void *data, 194void *klp_shadow_alloc(void *obj, unsigned long id,
191 size_t size, gfp_t gfp_flags); 195 size_t size, gfp_t gfp_flags,
192void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, 196 klp_shadow_ctor_t ctor, void *ctor_data);
193 size_t size, gfp_t gfp_flags); 197void *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);
194void klp_shadow_free(void *obj, unsigned long id); 200void klp_shadow_free(void *obj, unsigned long id);
195void klp_shadow_free_all(unsigned long id); 201void klp_shadow_free_all(unsigned long id);
196 202
diff --git a/kernel/livepatch/shadow.c b/kernel/livepatch/shadow.c
index fdac27588d60..b10a0bbb7f84 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}
114EXPORT_SYMBOL_GPL(klp_shadow_get); 114EXPORT_SYMBOL_GPL(klp_shadow_get);
115 115
116static void *__klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, 116static 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 */
189void *klp_shadow_alloc(void *obj, unsigned long id, void *data, 208void *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}
194EXPORT_SYMBOL_GPL(klp_shadow_alloc); 215EXPORT_SYMBOL_GPL(klp_shadow_alloc);
195 216
@@ -197,25 +218,28 @@ 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 */
215void *klp_shadow_get_or_alloc(void *obj, unsigned long id, void *data, 237void *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}
220EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); 244EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc);
221 245
diff --git a/samples/livepatch/livepatch-shadow-fix1.c b/samples/livepatch/livepatch-shadow-fix1.c
index 830c55514f9f..04151c7f2631 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 */
65static 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
59struct dummy *livepatch_fix1_dummy_alloc(void) 74struct 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);
diff --git a/samples/livepatch/livepatch-shadow-fix2.c b/samples/livepatch/livepatch-shadow-fix2.c
index ff9948f0ec00..d6c62844dc15 100644
--- a/samples/livepatch/livepatch-shadow-fix2.c
+++ b/samples/livepatch/livepatch-shadow-fix2.c
@@ -53,17 +53,15 @@ struct dummy {
53bool livepatch_fix2_dummy_check(struct dummy *d, unsigned long jiffies) 53bool 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