diff options
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r-- | crypto/algapi.c | 143 |
1 files changed, 123 insertions, 20 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c index e9154c1347ca..7c41e7405c41 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c | |||
@@ -21,6 +21,8 @@ | |||
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) |
@@ -126,23 +128,97 @@ static void crypto_remove_spawns(struct list_head *spawns, | |||
126 | } | 128 | } |
127 | } | 129 | } |
128 | 130 | ||
129 | static int __crypto_register_alg(struct crypto_alg *alg, | 131 | static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg) |
130 | struct list_head *list) | ||
131 | { | 132 | { |
132 | struct crypto_alg *q; | 133 | struct crypto_alg *q; |
134 | struct crypto_larval *larval; | ||
133 | int ret = -EAGAIN; | 135 | int ret = -EAGAIN; |
134 | 136 | ||
135 | if (crypto_is_dead(alg)) | 137 | if (crypto_is_dead(alg)) |
136 | goto out; | 138 | goto err; |
137 | 139 | ||
138 | INIT_LIST_HEAD(&alg->cra_users); | 140 | INIT_LIST_HEAD(&alg->cra_users); |
139 | 141 | ||
142 | /* No cheating! */ | ||
143 | alg->cra_flags &= ~CRYPTO_ALG_TESTED; | ||
144 | |||
140 | ret = -EEXIST; | 145 | ret = -EEXIST; |
141 | 146 | ||
142 | atomic_set(&alg->cra_refcnt, 1); | 147 | atomic_set(&alg->cra_refcnt, 1); |
143 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | 148 | list_for_each_entry(q, &crypto_alg_list, cra_list) { |
144 | if (q == alg) | 149 | if (q == alg) |
145 | 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; | ||
146 | 222 | ||
147 | if (crypto_is_moribund(q)) | 223 | if (crypto_is_moribund(q)) |
148 | continue; | 224 | continue; |
@@ -178,17 +254,18 @@ static int __crypto_register_alg(struct crypto_alg *alg, | |||
178 | q->cra_priority > alg->cra_priority) | 254 | q->cra_priority > alg->cra_priority) |
179 | continue; | 255 | continue; |
180 | 256 | ||
181 | crypto_remove_spawns(&q->cra_users, list, alg->cra_flags); | 257 | crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags); |
182 | } | 258 | } |
183 | |||
184 | list_add(&alg->cra_list, &crypto_alg_list); | ||
185 | 259 | ||
186 | crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg); | 260 | complete: |
187 | ret = 0; | 261 | complete_all(&test->completion); |
188 | 262 | ||
189 | out: | 263 | unlock: |
190 | return ret; | 264 | up_write(&crypto_alg_sem); |
265 | |||
266 | crypto_remove_final(&list); | ||
191 | } | 267 | } |
268 | EXPORT_SYMBOL_GPL(crypto_alg_tested); | ||
192 | 269 | ||
193 | static void crypto_remove_final(struct list_head *list) | 270 | static void crypto_remove_final(struct list_head *list) |
194 | { | 271 | { |
@@ -201,9 +278,27 @@ static void crypto_remove_final(struct list_head *list) | |||
201 | } | 278 | } |
202 | } | 279 | } |
203 | 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 | |||
204 | int crypto_register_alg(struct crypto_alg *alg) | 299 | int crypto_register_alg(struct crypto_alg *alg) |
205 | { | 300 | { |
206 | LIST_HEAD(list); | 301 | struct crypto_larval *larval; |
207 | int err; | 302 | int err; |
208 | 303 | ||
209 | err = crypto_check_alg(alg); | 304 | err = crypto_check_alg(alg); |
@@ -211,11 +306,14 @@ int crypto_register_alg(struct crypto_alg *alg) | |||
211 | return err; | 306 | return err; |
212 | 307 | ||
213 | down_write(&crypto_alg_sem); | 308 | down_write(&crypto_alg_sem); |
214 | err = __crypto_register_alg(alg, &list); | 309 | larval = __crypto_register_alg(alg); |
215 | up_write(&crypto_alg_sem); | 310 | up_write(&crypto_alg_sem); |
216 | 311 | ||
217 | crypto_remove_final(&list); | 312 | if (IS_ERR(larval)) |
218 | return err; | 313 | return PTR_ERR(larval); |
314 | |||
315 | crypto_wait_for_test(larval); | ||
316 | return 0; | ||
219 | } | 317 | } |
220 | EXPORT_SYMBOL_GPL(crypto_register_alg); | 318 | EXPORT_SYMBOL_GPL(crypto_register_alg); |
221 | 319 | ||
@@ -333,8 +431,8 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template); | |||
333 | int crypto_register_instance(struct crypto_template *tmpl, | 431 | int crypto_register_instance(struct crypto_template *tmpl, |
334 | struct crypto_instance *inst) | 432 | struct crypto_instance *inst) |
335 | { | 433 | { |
336 | LIST_HEAD(list); | 434 | struct crypto_larval *larval; |
337 | int err = -EINVAL; | 435 | int err; |
338 | 436 | ||
339 | err = crypto_check_alg(&inst->alg); | 437 | err = crypto_check_alg(&inst->alg); |
340 | if (err) | 438 | if (err) |
@@ -344,8 +442,8 @@ int crypto_register_instance(struct crypto_template *tmpl, | |||
344 | 442 | ||
345 | down_write(&crypto_alg_sem); | 443 | down_write(&crypto_alg_sem); |
346 | 444 | ||
347 | err = __crypto_register_alg(&inst->alg, &list); | 445 | larval = __crypto_register_alg(&inst->alg); |
348 | if (err) | 446 | if (IS_ERR(larval)) |
349 | goto unlock; | 447 | goto unlock; |
350 | 448 | ||
351 | hlist_add_head(&inst->list, &tmpl->instances); | 449 | hlist_add_head(&inst->list, &tmpl->instances); |
@@ -354,7 +452,12 @@ int crypto_register_instance(struct crypto_template *tmpl, | |||
354 | unlock: | 452 | unlock: |
355 | up_write(&crypto_alg_sem); | 453 | up_write(&crypto_alg_sem); |
356 | 454 | ||
357 | 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; | ||
358 | 461 | ||
359 | err: | 462 | err: |
360 | return err; | 463 | return err; |