Skip to content

Commit 6bfd480

Browse files
committed
[CRYPTO] api: Added spawns
Spawns lock a specific crypto algorithm in place. They can then be used with crypto_spawn_tfm to allocate a tfm for that algorithm. When the base algorithm of a spawn is deregistered, all its spawns will be automatically removed. Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 492e2b6 commit 6bfd480

File tree

6 files changed

+280
-53
lines changed

6 files changed

+280
-53
lines changed

crypto/algapi.c

Lines changed: 169 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*
1111
*/
1212

13+
#include <linux/err.h>
1314
#include <linux/errno.h>
1415
#include <linux/init.h>
1516
#include <linux/kernel.h>
@@ -73,27 +74,96 @@ static int crypto_check_alg(struct crypto_alg *alg)
7374
return crypto_set_driver_name(alg);
7475
}
7576

76-
static int __crypto_register_alg(struct crypto_alg *alg)
77+
static void crypto_destroy_instance(struct crypto_alg *alg)
78+
{
79+
struct crypto_instance *inst = (void *)alg;
80+
struct crypto_template *tmpl = inst->tmpl;
81+
82+
tmpl->free(inst);
83+
crypto_tmpl_put(tmpl);
84+
}
85+
86+
static void crypto_remove_spawns(struct list_head *spawns,
87+
struct list_head *list)
88+
{
89+
struct crypto_spawn *spawn, *n;
90+
91+
list_for_each_entry_safe(spawn, n, spawns, list) {
92+
struct crypto_instance *inst = spawn->inst;
93+
struct crypto_template *tmpl = inst->tmpl;
94+
95+
list_del_init(&spawn->list);
96+
spawn->alg = NULL;
97+
98+
if (crypto_is_dead(&inst->alg))
99+
continue;
100+
101+
inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
102+
if (!tmpl || !crypto_tmpl_get(tmpl))
103+
continue;
104+
105+
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
106+
list_move(&inst->alg.cra_list, list);
107+
hlist_del(&inst->list);
108+
inst->alg.cra_destroy = crypto_destroy_instance;
109+
110+
if (!list_empty(&inst->alg.cra_users)) {
111+
if (&n->list == spawns)
112+
n = list_entry(inst->alg.cra_users.next,
113+
typeof(*n), list);
114+
__list_splice(&inst->alg.cra_users, spawns->prev);
115+
}
116+
}
117+
}
118+
119+
static int __crypto_register_alg(struct crypto_alg *alg,
120+
struct list_head *list)
77121
{
78122
struct crypto_alg *q;
79-
int ret = -EEXIST;
123+
int ret = -EAGAIN;
124+
125+
if (crypto_is_dead(alg))
126+
goto out;
127+
128+
INIT_LIST_HEAD(&alg->cra_users);
129+
130+
ret = -EEXIST;
80131

81132
atomic_set(&alg->cra_refcnt, 1);
82133
list_for_each_entry(q, &crypto_alg_list, cra_list) {
83134
if (q == alg)
84135
goto out;
85-
if (crypto_is_larval(q) &&
86-
(!strcmp(alg->cra_name, q->cra_name) ||
87-
!strcmp(alg->cra_driver_name, q->cra_name))) {
136+
137+
if (crypto_is_moribund(q))
138+
continue;
139+
140+
if (crypto_is_larval(q)) {
88141
struct crypto_larval *larval = (void *)q;
89142

143+
if (strcmp(alg->cra_name, q->cra_name) &&
144+
strcmp(alg->cra_driver_name, q->cra_name))
145+
continue;
146+
147+
if (larval->adult)
148+
continue;
90149
if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
91150
continue;
92151
if (!crypto_mod_get(alg))
93152
continue;
153+
94154
larval->adult = alg;
95155
complete(&larval->completion);
156+
continue;
96157
}
158+
159+
if (strcmp(alg->cra_name, q->cra_name))
160+
continue;
161+
162+
if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
163+
q->cra_priority > alg->cra_priority)
164+
continue;
165+
166+
crypto_remove_spawns(&q->cra_users, list);
97167
}
98168

99169
list_add(&alg->cra_list, &crypto_alg_list);
@@ -105,32 +175,56 @@ static int __crypto_register_alg(struct crypto_alg *alg)
105175
return ret;
106176
}
107177

178+
static void crypto_remove_final(struct list_head *list)
179+
{
180+
struct crypto_alg *alg;
181+
struct crypto_alg *n;
182+
183+
list_for_each_entry_safe(alg, n, list, cra_list) {
184+
list_del_init(&alg->cra_list);
185+
crypto_alg_put(alg);
186+
}
187+
}
188+
108189
int crypto_register_alg(struct crypto_alg *alg)
109190
{
191+
LIST_HEAD(list);
110192
int err;
111193

112194
err = crypto_check_alg(alg);
113195
if (err)
114196
return err;
115197

116198
down_write(&crypto_alg_sem);
117-
err = __crypto_register_alg(alg);
199+
err = __crypto_register_alg(alg, &list);
118200
up_write(&crypto_alg_sem);
119201

202+
crypto_remove_final(&list);
120203
return err;
121204
}
122205
EXPORT_SYMBOL_GPL(crypto_register_alg);
123206

207+
static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
208+
{
209+
if (unlikely(list_empty(&alg->cra_list)))
210+
return -ENOENT;
211+
212+
alg->cra_flags |= CRYPTO_ALG_DEAD;
213+
214+
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
215+
list_del_init(&alg->cra_list);
216+
crypto_remove_spawns(&alg->cra_users, list);
217+
218+
return 0;
219+
}
220+
124221
int crypto_unregister_alg(struct crypto_alg *alg)
125222
{
126-
int ret = -ENOENT;
223+
int ret;
224+
LIST_HEAD(list);
127225

128226
down_write(&crypto_alg_sem);
129-
if (likely(!list_empty(&alg->cra_list))) {
130-
list_del_init(&alg->cra_list);
131-
ret = 0;
132-
}
133-
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
227+
ret = crypto_remove_alg(alg, &list);
134228
up_write(&crypto_alg_sem);
135229

136230
if (ret)
@@ -140,6 +234,7 @@ int crypto_unregister_alg(struct crypto_alg *alg)
140234
if (alg->cra_destroy)
141235
alg->cra_destroy(alg);
142236

237+
crypto_remove_final(&list);
143238
return 0;
144239
}
145240
EXPORT_SYMBOL_GPL(crypto_unregister_alg);
@@ -170,6 +265,7 @@ void crypto_unregister_template(struct crypto_template *tmpl)
170265
struct crypto_instance *inst;
171266
struct hlist_node *p, *n;
172267
struct hlist_head *list;
268+
LIST_HEAD(users);
173269

174270
down_write(&crypto_alg_sem);
175271

@@ -178,9 +274,8 @@ void crypto_unregister_template(struct crypto_template *tmpl)
178274

179275
list = &tmpl->instances;
180276
hlist_for_each_entry(inst, p, list, list) {
181-
BUG_ON(list_empty(&inst->alg.cra_list));
182-
list_del_init(&inst->alg.cra_list);
183-
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
277+
int err = crypto_remove_alg(&inst->alg, &users);
278+
BUG_ON(err);
184279
}
185280

186281
crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
@@ -191,6 +286,7 @@ void crypto_unregister_template(struct crypto_template *tmpl)
191286
BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
192287
tmpl->free(inst);
193288
}
289+
crypto_remove_final(&users);
194290
}
195291
EXPORT_SYMBOL_GPL(crypto_unregister_template);
196292

@@ -222,6 +318,7 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template);
222318
int crypto_register_instance(struct crypto_template *tmpl,
223319
struct crypto_instance *inst)
224320
{
321+
LIST_HEAD(list);
225322
int err = -EINVAL;
226323

227324
if (inst->alg.cra_destroy)
@@ -235,7 +332,7 @@ int crypto_register_instance(struct crypto_template *tmpl,
235332

236333
down_write(&crypto_alg_sem);
237334

238-
err = __crypto_register_alg(&inst->alg);
335+
err = __crypto_register_alg(&inst->alg, &list);
239336
if (err)
240337
goto unlock;
241338

@@ -245,11 +342,67 @@ int crypto_register_instance(struct crypto_template *tmpl,
245342
unlock:
246343
up_write(&crypto_alg_sem);
247344

345+
crypto_remove_final(&list);
346+
248347
err:
249348
return err;
250349
}
251350
EXPORT_SYMBOL_GPL(crypto_register_instance);
252351

352+
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
353+
struct crypto_instance *inst)
354+
{
355+
int err = -EAGAIN;
356+
357+
spawn->inst = inst;
358+
359+
down_write(&crypto_alg_sem);
360+
if (!crypto_is_moribund(alg)) {
361+
list_add(&spawn->list, &alg->cra_users);
362+
spawn->alg = alg;
363+
err = 0;
364+
}
365+
up_write(&crypto_alg_sem);
366+
367+
return err;
368+
}
369+
EXPORT_SYMBOL_GPL(crypto_init_spawn);
370+
371+
void crypto_drop_spawn(struct crypto_spawn *spawn)
372+
{
373+
down_write(&crypto_alg_sem);
374+
list_del(&spawn->list);
375+
up_write(&crypto_alg_sem);
376+
}
377+
EXPORT_SYMBOL_GPL(crypto_drop_spawn);
378+
379+
struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
380+
{
381+
struct crypto_alg *alg;
382+
struct crypto_alg *alg2;
383+
struct crypto_tfm *tfm;
384+
385+
down_read(&crypto_alg_sem);
386+
alg = spawn->alg;
387+
alg2 = alg;
388+
if (alg2)
389+
alg2 = crypto_mod_get(alg2);
390+
up_read(&crypto_alg_sem);
391+
392+
if (!alg2) {
393+
if (alg)
394+
crypto_shoot_alg(alg);
395+
return ERR_PTR(-EAGAIN);
396+
}
397+
398+
tfm = __crypto_alloc_tfm(alg, 0);
399+
if (IS_ERR(tfm))
400+
crypto_mod_put(alg);
401+
402+
return tfm;
403+
}
404+
EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
405+
253406
int crypto_register_notifier(struct notifier_block *nb)
254407
{
255408
return blocking_notifier_chain_register(&crypto_chain, nb);

0 commit comments

Comments
 (0)