aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/algapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r--crypto/algapi.c143
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
24static void crypto_remove_final(struct list_head *list);
25
24static LIST_HEAD(crypto_template_list); 26static LIST_HEAD(crypto_template_list);
25 27
26void crypto_larval_error(const char *name, u32 type, u32 mask) 28void 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
129static int __crypto_register_alg(struct crypto_alg *alg, 131static 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
181out:
182 return larval;
183
184free_larval:
185 kfree(larval);
186err:
187 larval = ERR_PTR(ret);
188 goto out;
189}
190
191void 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
212found:
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); 260complete:
187 ret = 0; 261 complete_all(&test->completion);
188 262
189out: 263unlock:
190 return ret; 264 up_write(&crypto_alg_sem);
265
266 crypto_remove_final(&list);
191} 267}
268EXPORT_SYMBOL_GPL(crypto_alg_tested);
192 269
193static void crypto_remove_final(struct list_head *list) 270static 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
281static 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
295out:
296 crypto_larval_kill(&larval->alg);
297}
298
204int crypto_register_alg(struct crypto_alg *alg) 299int 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}
220EXPORT_SYMBOL_GPL(crypto_register_alg); 318EXPORT_SYMBOL_GPL(crypto_register_alg);
221 319
@@ -333,8 +431,8 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template);
333int crypto_register_instance(struct crypto_template *tmpl, 431int 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,
354unlock: 452unlock:
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
359err: 462err:
360 return err; 463 return err;