aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/algapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r--crypto/algapi.c147
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
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)
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
131static int __crypto_register_alg(struct crypto_alg *alg, 131static 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
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;
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); 260complete:
189 ret = 0; 261 complete_all(&test->completion);
190 262
191out: 263unlock:
192 return ret; 264 up_write(&crypto_alg_sem);
265
266 crypto_remove_final(&list);
193} 267}
268EXPORT_SYMBOL_GPL(crypto_alg_tested);
194 269
195static void crypto_remove_final(struct list_head *list) 270static 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
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
206int crypto_register_alg(struct crypto_alg *alg) 299int 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}
222EXPORT_SYMBOL_GPL(crypto_register_alg); 318EXPORT_SYMBOL_GPL(crypto_register_alg);
223 319
@@ -335,8 +431,8 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template);
335int crypto_register_instance(struct crypto_template *tmpl, 431int 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,
356unlock: 452unlock:
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
361err: 462err:
362 return err; 463 return err;