aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2018-04-16 07:36:46 -0400
committerJiri Kosina <jkosina@suse.cz>2018-04-17 07:42:48 -0400
commite91c2518a5d22a07642f35d85f39001ad379dae4 (patch)
tree3a794a957564ce90514894263e995fbd27649a8c
parente1c70f32386c4984ed8ca1a7aedb9bbff9ed3414 (diff)
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 b3defb791b26ea06 ("ALSA: seq: Make ioctls race-free") and commit d15d662e89fc667b9 ("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 <nstange@suse.de> Signed-off-by: Petr Mladek <pmladek@suse.com> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-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