diff options
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r-- | crypto/algapi.c | 147 |
1 files changed, 124 insertions, 23 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c index e65cb50cf4af..7c41e7405c41 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c | |||
@@ -21,15 +21,15 @@ | |||
21 | 21 | ||
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | 23 | ||
24 | static void crypto_remove_final(struct list_head *list); | ||
25 | |||
24 | static LIST_HEAD(crypto_template_list); | 26 | static LIST_HEAD(crypto_template_list); |
25 | 27 | ||
26 | void crypto_larval_error(const char *name, u32 type, u32 mask) | 28 | void crypto_larval_error(const char *name, u32 type, u32 mask) |
27 | { | 29 | { |
28 | struct crypto_alg *alg; | 30 | struct crypto_alg *alg; |
29 | 31 | ||
30 | down_read(&crypto_alg_sem); | 32 | alg = crypto_alg_lookup(name, type, mask); |
31 | alg = __crypto_alg_lookup(name, type, mask); | ||
32 | up_read(&crypto_alg_sem); | ||
33 | 33 | ||
34 | if (alg) { | 34 | if (alg) { |
35 | if (crypto_is_larval(alg)) { | 35 | if (crypto_is_larval(alg)) { |
@@ -128,23 +128,97 @@ static void crypto_remove_spawns(struct list_head *spawns, | |||
128 | } | 128 | } |
129 | } | 129 | } |
130 | 130 | ||
131 | static int __crypto_register_alg(struct crypto_alg *alg, | 131 | static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg) |
132 | struct list_head *list) | ||
133 | { | 132 | { |
134 | struct crypto_alg *q; | 133 | struct crypto_alg *q; |
134 | struct crypto_larval *larval; | ||
135 | int ret = -EAGAIN; | 135 | int ret = -EAGAIN; |
136 | 136 | ||
137 | if (crypto_is_dead(alg)) | 137 | if (crypto_is_dead(alg)) |
138 | goto out; | 138 | goto err; |
139 | 139 | ||
140 | INIT_LIST_HEAD(&alg->cra_users); | 140 | INIT_LIST_HEAD(&alg->cra_users); |
141 | 141 | ||
142 | /* No cheating! */ | ||
143 | alg->cra_flags &= ~CRYPTO_ALG_TESTED; | ||
144 | |||
142 | ret = -EEXIST; | 145 | ret = -EEXIST; |
143 | 146 | ||
144 | atomic_set(&alg->cra_refcnt, 1); | 147 | atomic_set(&alg->cra_refcnt, 1); |
145 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | 148 | list_for_each_entry(q, &crypto_alg_list, cra_list) { |
146 | if (q == alg) | 149 | if (q == alg) |
147 | goto out; | 150 | goto err; |
151 | |||
152 | if (crypto_is_larval(q)) { | ||
153 | if (!strcmp(alg->cra_driver_name, q->cra_driver_name)) | ||
154 | goto err; | ||
155 | continue; | ||
156 | } | ||
157 | |||
158 | if (!strcmp(q->cra_driver_name, alg->cra_name) || | ||
159 | !strcmp(q->cra_name, alg->cra_driver_name)) | ||
160 | goto err; | ||
161 | } | ||
162 | |||
163 | larval = crypto_larval_alloc(alg->cra_name, | ||
164 | alg->cra_flags | CRYPTO_ALG_TESTED, 0); | ||
165 | if (IS_ERR(larval)) | ||
166 | goto out; | ||
167 | |||
168 | ret = -ENOENT; | ||
169 | larval->adult = crypto_mod_get(alg); | ||
170 | if (!larval->adult) | ||
171 | goto free_larval; | ||
172 | |||
173 | atomic_set(&larval->alg.cra_refcnt, 1); | ||
174 | memcpy(larval->alg.cra_driver_name, alg->cra_driver_name, | ||
175 | CRYPTO_MAX_ALG_NAME); | ||
176 | larval->alg.cra_priority = alg->cra_priority; | ||
177 | |||
178 | list_add(&alg->cra_list, &crypto_alg_list); | ||
179 | list_add(&larval->alg.cra_list, &crypto_alg_list); | ||
180 | |||
181 | out: | ||
182 | return larval; | ||
183 | |||
184 | free_larval: | ||
185 | kfree(larval); | ||
186 | err: | ||
187 | larval = ERR_PTR(ret); | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | void crypto_alg_tested(const char *name, int err) | ||
192 | { | ||
193 | struct crypto_larval *test; | ||
194 | struct crypto_alg *alg; | ||
195 | struct crypto_alg *q; | ||
196 | LIST_HEAD(list); | ||
197 | |||
198 | down_write(&crypto_alg_sem); | ||
199 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | ||
200 | if (!crypto_is_larval(q)) | ||
201 | continue; | ||
202 | |||
203 | test = (struct crypto_larval *)q; | ||
204 | |||
205 | if (!strcmp(q->cra_driver_name, name)) | ||
206 | goto found; | ||
207 | } | ||
208 | |||
209 | printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err); | ||
210 | goto unlock; | ||
211 | |||
212 | found: | ||
213 | alg = test->adult; | ||
214 | if (err || list_empty(&alg->cra_list)) | ||
215 | goto complete; | ||
216 | |||
217 | alg->cra_flags |= CRYPTO_ALG_TESTED; | ||
218 | |||
219 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | ||
220 | if (q == alg) | ||
221 | continue; | ||
148 | 222 | ||
149 | if (crypto_is_moribund(q)) | 223 | if (crypto_is_moribund(q)) |
150 | continue; | 224 | continue; |
@@ -180,17 +254,18 @@ static int __crypto_register_alg(struct crypto_alg *alg, | |||
180 | q->cra_priority > alg->cra_priority) | 254 | q->cra_priority > alg->cra_priority) |
181 | continue; | 255 | continue; |
182 | 256 | ||
183 | crypto_remove_spawns(&q->cra_users, list, alg->cra_flags); | 257 | crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags); |
184 | } | 258 | } |
185 | |||
186 | list_add(&alg->cra_list, &crypto_alg_list); | ||
187 | 259 | ||
188 | crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg); | 260 | complete: |
189 | ret = 0; | 261 | complete_all(&test->completion); |
190 | 262 | ||
191 | out: | 263 | unlock: |
192 | return ret; | 264 | up_write(&crypto_alg_sem); |
265 | |||
266 | crypto_remove_final(&list); | ||
193 | } | 267 | } |
268 | EXPORT_SYMBOL_GPL(crypto_alg_tested); | ||
194 | 269 | ||
195 | static void crypto_remove_final(struct list_head *list) | 270 | static void crypto_remove_final(struct list_head *list) |
196 | { | 271 | { |
@@ -203,9 +278,27 @@ static void crypto_remove_final(struct list_head *list) | |||
203 | } | 278 | } |
204 | } | 279 | } |
205 | 280 | ||
281 | static void crypto_wait_for_test(struct crypto_larval *larval) | ||
282 | { | ||
283 | int err; | ||
284 | |||
285 | err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult); | ||
286 | if (err != NOTIFY_STOP) { | ||
287 | if (WARN_ON(err != NOTIFY_DONE)) | ||
288 | goto out; | ||
289 | crypto_alg_tested(larval->alg.cra_driver_name, 0); | ||
290 | } | ||
291 | |||
292 | err = wait_for_completion_interruptible(&larval->completion); | ||
293 | WARN_ON(err); | ||
294 | |||
295 | out: | ||
296 | crypto_larval_kill(&larval->alg); | ||
297 | } | ||
298 | |||
206 | int crypto_register_alg(struct crypto_alg *alg) | 299 | int crypto_register_alg(struct crypto_alg *alg) |
207 | { | 300 | { |
208 | LIST_HEAD(list); | 301 | struct crypto_larval *larval; |
209 | int err; | 302 | int err; |
210 | 303 | ||
211 | err = crypto_check_alg(alg); | 304 | err = crypto_check_alg(alg); |
@@ -213,11 +306,14 @@ int crypto_register_alg(struct crypto_alg *alg) | |||
213 | return err; | 306 | return err; |
214 | 307 | ||
215 | down_write(&crypto_alg_sem); | 308 | down_write(&crypto_alg_sem); |
216 | err = __crypto_register_alg(alg, &list); | 309 | larval = __crypto_register_alg(alg); |
217 | up_write(&crypto_alg_sem); | 310 | up_write(&crypto_alg_sem); |
218 | 311 | ||
219 | crypto_remove_final(&list); | 312 | if (IS_ERR(larval)) |
220 | return err; | 313 | return PTR_ERR(larval); |
314 | |||
315 | crypto_wait_for_test(larval); | ||
316 | return 0; | ||
221 | } | 317 | } |
222 | EXPORT_SYMBOL_GPL(crypto_register_alg); | 318 | EXPORT_SYMBOL_GPL(crypto_register_alg); |
223 | 319 | ||
@@ -335,8 +431,8 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template); | |||
335 | int crypto_register_instance(struct crypto_template *tmpl, | 431 | int crypto_register_instance(struct crypto_template *tmpl, |
336 | struct crypto_instance *inst) | 432 | struct crypto_instance *inst) |
337 | { | 433 | { |
338 | LIST_HEAD(list); | 434 | struct crypto_larval *larval; |
339 | int err = -EINVAL; | 435 | int err; |
340 | 436 | ||
341 | err = crypto_check_alg(&inst->alg); | 437 | err = crypto_check_alg(&inst->alg); |
342 | if (err) | 438 | if (err) |
@@ -346,8 +442,8 @@ int crypto_register_instance(struct crypto_template *tmpl, | |||
346 | 442 | ||
347 | down_write(&crypto_alg_sem); | 443 | down_write(&crypto_alg_sem); |
348 | 444 | ||
349 | err = __crypto_register_alg(&inst->alg, &list); | 445 | larval = __crypto_register_alg(&inst->alg); |
350 | if (err) | 446 | if (IS_ERR(larval)) |
351 | goto unlock; | 447 | goto unlock; |
352 | 448 | ||
353 | hlist_add_head(&inst->list, &tmpl->instances); | 449 | hlist_add_head(&inst->list, &tmpl->instances); |
@@ -356,7 +452,12 @@ int crypto_register_instance(struct crypto_template *tmpl, | |||
356 | unlock: | 452 | unlock: |
357 | up_write(&crypto_alg_sem); | 453 | up_write(&crypto_alg_sem); |
358 | 454 | ||
359 | crypto_remove_final(&list); | 455 | err = PTR_ERR(larval); |
456 | if (IS_ERR(larval)) | ||
457 | goto err; | ||
458 | |||
459 | crypto_wait_for_test(larval); | ||
460 | err = 0; | ||
360 | 461 | ||
361 | err: | 462 | err: |
362 | return err; | 463 | return err; |