Commit 6bfd48096ff8ecabf955958b51ddfa7988eb0a14

Authored by Herbert Xu
1 parent 492e2b63eb

[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 <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 6 changed files with 280 additions and 53 deletions Side-by-side Diff

... ... @@ -10,6 +10,7 @@
10 10 *
11 11 */
12 12  
  13 +#include <linux/err.h>
13 14 #include <linux/errno.h>
14 15 #include <linux/init.h>
15 16 #include <linux/kernel.h>
16 17  
17 18  
18 19  
19 20  
20 21  
21 22  
22 23  
23 24  
... ... @@ -73,27 +74,96 @@
73 74 return crypto_set_driver_name(alg);
74 75 }
75 76  
76   -static int __crypto_register_alg(struct crypto_alg *alg)
  77 +static void crypto_destroy_instance(struct crypto_alg *alg)
77 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)
  121 +{
78 122 struct crypto_alg *q;
79   - int ret = -EEXIST;
  123 + int ret = -EAGAIN;
80 124  
  125 + if (crypto_is_dead(alg))
  126 + goto out;
  127 +
  128 + INIT_LIST_HEAD(&alg->cra_users);
  129 +
  130 + ret = -EEXIST;
  131 +
81 132 atomic_set(&alg->cra_refcnt, 1);
82 133 list_for_each_entry(q, &crypto_alg_list, cra_list) {
83 134 if (q == alg)
84 135 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)) {
88 141 struct crypto_larval *larval = (void *)q;
89 142  
  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;
90 149 if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
91 150 continue;
92 151 if (!crypto_mod_get(alg))
93 152 continue;
  153 +
94 154 larval->adult = alg;
95 155 complete(&larval->completion);
  156 + continue;
96 157 }
  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);
97 167 }
98 168  
99 169 list_add(&alg->cra_list, &crypto_alg_list);
100 170  
... ... @@ -105,8 +175,20 @@
105 175 return ret;
106 176 }
107 177  
  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 +
108 189 int crypto_register_alg(struct crypto_alg *alg)
109 190 {
  191 + LIST_HEAD(list);
110 192 int err;
111 193  
112 194 err = crypto_check_alg(alg);
113 195  
114 196  
115 197  
116 198  
... ... @@ -114,23 +196,35 @@
114 196 return err;
115 197  
116 198 down_write(&crypto_alg_sem);
117   - err = __crypto_register_alg(alg);
  199 + err = __crypto_register_alg(alg, &list);
118 200 up_write(&crypto_alg_sem);
119 201  
  202 + crypto_remove_final(&list);
120 203 return err;
121 204 }
122 205 EXPORT_SYMBOL_GPL(crypto_register_alg);
123 206  
  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 +
124 221 int crypto_unregister_alg(struct crypto_alg *alg)
125 222 {
126   - int ret = -ENOENT;
  223 + int ret;
  224 + LIST_HEAD(list);
127 225  
128 226 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);
134 228 up_write(&crypto_alg_sem);
135 229  
136 230 if (ret)
... ... @@ -140,6 +234,7 @@
140 234 if (alg->cra_destroy)
141 235 alg->cra_destroy(alg);
142 236  
  237 + crypto_remove_final(&list);
143 238 return 0;
144 239 }
145 240 EXPORT_SYMBOL_GPL(crypto_unregister_alg);
... ... @@ -170,6 +265,7 @@
170 265 struct crypto_instance *inst;
171 266 struct hlist_node *p, *n;
172 267 struct hlist_head *list;
  268 + LIST_HEAD(users);
173 269  
174 270 down_write(&crypto_alg_sem);
175 271  
... ... @@ -178,9 +274,8 @@
178 274  
179 275 list = &tmpl->instances;
180 276 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);
184 279 }
185 280  
186 281 crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
... ... @@ -191,6 +286,7 @@
191 286 BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
192 287 tmpl->free(inst);
193 288 }
  289 + crypto_remove_final(&users);
194 290 }
195 291 EXPORT_SYMBOL_GPL(crypto_unregister_template);
196 292  
... ... @@ -222,6 +318,7 @@
222 318 int crypto_register_instance(struct crypto_template *tmpl,
223 319 struct crypto_instance *inst)
224 320 {
  321 + LIST_HEAD(list);
225 322 int err = -EINVAL;
226 323  
227 324 if (inst->alg.cra_destroy)
... ... @@ -235,7 +332,7 @@
235 332  
236 333 down_write(&crypto_alg_sem);
237 334  
238   - err = __crypto_register_alg(&inst->alg);
  335 + err = __crypto_register_alg(&inst->alg, &list);
239 336 if (err)
240 337 goto unlock;
241 338  
242 339  
... ... @@ -245,10 +342,66 @@
245 342 unlock:
246 343 up_write(&crypto_alg_sem);
247 344  
  345 + crypto_remove_final(&list);
  346 +
248 347 err:
249 348 return err;
250 349 }
251 350 EXPORT_SYMBOL_GPL(crypto_register_instance);
  351 +
  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);
252 405  
253 406 int crypto_register_notifier(struct notifier_block *nb)
254 407 {
... ... @@ -15,11 +15,13 @@
15 15 *
16 16 */
17 17  
  18 +#include <linux/err.h>
18 19 #include <linux/errno.h>
19 20 #include <linux/kernel.h>
20 21 #include <linux/kmod.h>
21 22 #include <linux/module.h>
22 23 #include <linux/param.h>
  24 +#include <linux/sched.h>
23 25 #include <linux/slab.h>
24 26 #include <linux/string.h>
25 27 #include "internal.h"
... ... @@ -38,12 +40,6 @@
38 40 return alg;
39 41 }
40 42  
41   -static inline void crypto_alg_put(struct crypto_alg *alg)
42   -{
43   - if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
44   - alg->cra_destroy(alg);
45   -}
46   -
47 43 struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
48 44 {
49 45 return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
... ... @@ -65,6 +61,9 @@
65 61 list_for_each_entry(q, &crypto_alg_list, cra_list) {
66 62 int exact, fuzzy;
67 63  
  64 + if (crypto_is_moribund(q))
  65 + continue;
  66 +
68 67 if ((q->cra_flags ^ type) & mask)
69 68 continue;
70 69  
... ... @@ -111,7 +110,7 @@
111 110  
112 111 larval = kzalloc(sizeof(*larval), GFP_KERNEL);
113 112 if (!larval)
114   - return NULL;
  113 + return ERR_PTR(-ENOMEM);
115 114  
116 115 larval->mask = mask;
117 116 larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
... ... @@ -153,8 +152,11 @@
153 152  
154 153 wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
155 154 alg = larval->adult;
156   - if (alg && !crypto_mod_get(alg))
157   - alg = NULL;
  155 + if (alg) {
  156 + if (!crypto_mod_get(alg))
  157 + alg = ERR_PTR(-EAGAIN);
  158 + } else
  159 + alg = ERR_PTR(-ENOENT);
158 160 crypto_mod_put(&larval->alg);
159 161  
160 162 return alg;
... ... @@ -165,9 +167,6 @@
165 167 {
166 168 struct crypto_alg *alg;
167 169  
168   - if (!name)
169   - return NULL;
170   -
171 170 down_read(&crypto_alg_sem);
172 171 alg = __crypto_alg_lookup(name, type, mask);
173 172 up_read(&crypto_alg_sem);
... ... @@ -181,7 +180,10 @@
181 180 struct crypto_alg *larval;
182 181 int ok;
183 182  
184   - mask &= ~CRYPTO_ALG_LARVAL;
  183 + if (!name)
  184 + return ERR_PTR(-ENOENT);
  185 +
  186 + mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
185 187 type &= mask;
186 188  
187 189 alg = try_then_request_module(crypto_alg_lookup(name, type, mask),
... ... @@ -190,7 +192,7 @@
190 192 return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
191 193  
192 194 larval = crypto_larval_alloc(name, type, mask);
193   - if (!larval || !crypto_is_larval(larval))
  195 + if (IS_ERR(larval) || !crypto_is_larval(larval))
194 196 return larval;
195 197  
196 198 ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval);
... ... @@ -203,7 +205,7 @@
203 205 alg = crypto_larval_wait(larval);
204 206 else {
205 207 crypto_mod_put(larval);
206   - alg = NULL;
  208 + alg = ERR_PTR(-ENOENT);
207 209 }
208 210 crypto_larval_kill(larval);
209 211 return alg;
210 212  
211 213  
212 214  
213 215  
214 216  
215 217  
216 218  
217 219  
218 220  
... ... @@ -298,31 +300,40 @@
298 300 return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
299 301 }
300 302  
301   -struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
  303 +void crypto_shoot_alg(struct crypto_alg *alg)
302 304 {
  305 + down_write(&crypto_alg_sem);
  306 + alg->cra_flags |= CRYPTO_ALG_DYING;
  307 + up_write(&crypto_alg_sem);
  308 +}
  309 +EXPORT_SYMBOL_GPL(crypto_shoot_alg);
  310 +
  311 +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags)
  312 +{
303 313 struct crypto_tfm *tfm = NULL;
304   - struct crypto_alg *alg;
305 314 unsigned int tfm_size;
  315 + int err = -ENOMEM;
306 316  
307   - alg = crypto_alg_mod_lookup(name, 0, 0);
308   - if (alg == NULL)
309   - goto out;
310   -
311 317 tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
312 318 tfm = kzalloc(tfm_size, GFP_KERNEL);
313 319 if (tfm == NULL)
314   - goto out_put;
  320 + goto out;
315 321  
316 322 tfm->__crt_alg = alg;
317   -
318   - if (crypto_init_flags(tfm, flags))
  323 +
  324 + err = crypto_init_flags(tfm, flags);
  325 + if (err)
319 326 goto out_free_tfm;
320 327  
321   - if (crypto_init_ops(tfm))
  328 + err = crypto_init_ops(tfm);
  329 + if (err)
322 330 goto out_free_tfm;
323 331  
324   - if (alg->cra_init && alg->cra_init(tfm))
  332 + if (alg->cra_init && (err = alg->cra_init(tfm))) {
  333 + if (err == -EAGAIN)
  334 + crypto_shoot_alg(alg);
325 335 goto cra_init_failed;
  336 + }
326 337  
327 338 goto out;
328 339  
329 340  
330 341  
... ... @@ -330,13 +341,37 @@
330 341 crypto_exit_ops(tfm);
331 342 out_free_tfm:
332 343 kfree(tfm);
333   - tfm = NULL;
334   -out_put:
335   - crypto_mod_put(alg);
  344 + tfm = ERR_PTR(err);
336 345 out:
337 346 return tfm;
338 347 }
  348 +EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
339 349  
  350 +struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
  351 +{
  352 + struct crypto_tfm *tfm = NULL;
  353 + int err;
  354 +
  355 + do {
  356 + struct crypto_alg *alg;
  357 +
  358 + alg = crypto_alg_mod_lookup(name, 0, 0);
  359 + err = PTR_ERR(alg);
  360 + if (IS_ERR(alg))
  361 + continue;
  362 +
  363 + tfm = __crypto_alloc_tfm(alg, flags);
  364 + err = 0;
  365 + if (IS_ERR(tfm)) {
  366 + crypto_mod_put(alg);
  367 + err = PTR_ERR(tfm);
  368 + tfm = NULL;
  369 + }
  370 + } while (err == -EAGAIN && !signal_pending(current));
  371 +
  372 + return tfm;
  373 +}
  374 +
340 375 void crypto_free_tfm(struct crypto_tfm *tfm)
341 376 {
342 377 struct crypto_alg *alg;
... ... @@ -361,7 +396,7 @@
361 396 int ret = 0;
362 397 struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0);
363 398  
364   - if (alg) {
  399 + if (!IS_ERR(alg)) {
365 400 crypto_mod_put(alg);
366 401 ret = 1;
367 402 }
... ... @@ -17,6 +17,7 @@
17 17 #include <linux/module.h>
18 18 #include <linux/notifier.h>
19 19 #include <linux/rtnetlink.h>
  20 +#include <linux/sched.h>
20 21 #include <linux/string.h>
21 22 #include <linux/workqueue.h>
22 23  
23 24  
24 25  
... ... @@ -44,20 +45,24 @@
44 45 struct cryptomgr_param *param = data;
45 46 struct crypto_template *tmpl;
46 47 struct crypto_instance *inst;
  48 + int err;
47 49  
48 50 tmpl = crypto_lookup_template(param->template);
49 51 if (!tmpl)
50 52 goto err;
51 53  
52   - inst = tmpl->alloc(&param->alg, sizeof(param->alg));
53   - if (IS_ERR(inst))
54   - goto err;
55   - else if ((err = crypto_register_instance(tmpl, inst))) {
56   - tmpl->free(inst);
57   - goto err;
58   - }
  54 + do {
  55 + inst = tmpl->alloc(&param->alg, sizeof(param->alg));
  56 + if (IS_ERR(inst))
  57 + err = PTR_ERR(inst);
  58 + else if ((err = crypto_register_instance(tmpl, inst)))
  59 + tmpl->free(inst);
  60 + } while (err == -EAGAIN && !signal_pending(current));
59 61  
60 62 crypto_tmpl_put(tmpl);
  63 +
  64 + if (err)
  65 + goto err;
61 66  
62 67 out:
63 68 kfree(param);
... ... @@ -142,12 +142,21 @@
142 142  
143 143 void crypto_larval_error(const char *name, u32 type, u32 mask);
144 144  
  145 +void crypto_shoot_alg(struct crypto_alg *alg);
  146 +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags);
  147 +
145 148 int crypto_register_instance(struct crypto_template *tmpl,
146 149 struct crypto_instance *inst);
147 150  
148 151 int crypto_register_notifier(struct notifier_block *nb);
149 152 int crypto_unregister_notifier(struct notifier_block *nb);
150 153  
  154 +static inline void crypto_alg_put(struct crypto_alg *alg)
  155 +{
  156 + if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
  157 + alg->cra_destroy(alg);
  158 +}
  159 +
151 160 static inline int crypto_tmpl_get(struct crypto_template *tmpl)
152 161 {
153 162 return try_module_get(tmpl->module);
... ... @@ -161,6 +170,16 @@
161 170 static inline int crypto_is_larval(struct crypto_alg *alg)
162 171 {
163 172 return alg->cra_flags & CRYPTO_ALG_LARVAL;
  173 +}
  174 +
  175 +static inline int crypto_is_dead(struct crypto_alg *alg)
  176 +{
  177 + return alg->cra_flags & CRYPTO_ALG_DEAD;
  178 +}
  179 +
  180 +static inline int crypto_is_moribund(struct crypto_alg *alg)
  181 +{
  182 + return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING);
164 183 }
165 184  
166 185 static inline int crypto_notify(unsigned long val, void *v)
include/crypto/algapi.h
... ... @@ -36,9 +36,20 @@
36 36 char name[CRYPTO_MAX_ALG_NAME];
37 37 };
38 38  
  39 +struct crypto_spawn {
  40 + struct list_head list;
  41 + struct crypto_alg *alg;
  42 + struct crypto_instance *inst;
  43 +};
  44 +
39 45 int crypto_register_template(struct crypto_template *tmpl);
40 46 void crypto_unregister_template(struct crypto_template *tmpl);
41 47 struct crypto_template *crypto_lookup_template(const char *name);
  48 +
  49 +int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
  50 + struct crypto_instance *inst);
  51 +void crypto_drop_spawn(struct crypto_spawn *spawn);
  52 +struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn);
42 53  
43 54 static inline void *crypto_instance_ctx(struct crypto_instance *inst)
44 55 {
include/linux/crypto.h
... ... @@ -35,6 +35,8 @@
35 35 #define CRYPTO_ALG_TYPE_COMPRESS 0x00000004
36 36  
37 37 #define CRYPTO_ALG_LARVAL 0x00000010
  38 +#define CRYPTO_ALG_DEAD 0x00000020
  39 +#define CRYPTO_ALG_DYING 0x00000040
38 40  
39 41 /*
40 42 * Transform masks and values (for crt_flags).
... ... @@ -145,6 +147,8 @@
145 147  
146 148 struct crypto_alg {
147 149 struct list_head cra_list;
  150 + struct list_head cra_users;
  151 +
148 152 u32 cra_flags;
149 153 unsigned int cra_blocksize;
150 154 unsigned int cra_ctxsize;