Commit 2825982d9d66ebba4b532a07391dfbb357f71c5f

Authored by Herbert Xu
1 parent 4cc7720cd1

[CRYPTO] api: Added event notification

This patch adds a notifier chain for algorithm/template registration events.
This will be used to register compound algorithms such as cbc(aes).  In
future this will also be passed onto user-space through netlink.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 4 changed files with 199 additions and 14 deletions Side-by-side Diff

... ... @@ -21,6 +21,24 @@
21 21  
22 22 static LIST_HEAD(crypto_template_list);
23 23  
  24 +void crypto_larval_error(const char *name)
  25 +{
  26 + struct crypto_alg *alg;
  27 +
  28 + down_read(&crypto_alg_sem);
  29 + alg = __crypto_alg_lookup(name);
  30 + up_read(&crypto_alg_sem);
  31 +
  32 + if (alg) {
  33 + if (crypto_is_larval(alg)) {
  34 + struct crypto_larval *larval = (void *)alg;
  35 + complete(&larval->completion);
  36 + }
  37 + crypto_mod_put(alg);
  38 + }
  39 +}
  40 +EXPORT_SYMBOL_GPL(crypto_larval_error);
  41 +
24 42 static inline int crypto_set_driver_name(struct crypto_alg *alg)
25 43 {
26 44 static const char suffix[] = "-generic";
27 45  
28 46  
29 47  
... ... @@ -60,14 +78,27 @@
60 78 struct crypto_alg *q;
61 79 int ret = -EEXIST;
62 80  
  81 + atomic_set(&alg->cra_refcnt, 1);
63 82 list_for_each_entry(q, &crypto_alg_list, cra_list) {
64 83 if (q == alg)
65 84 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))) {
  88 + struct crypto_larval *larval = (void *)q;
  89 +
  90 + if (!crypto_mod_get(alg))
  91 + continue;
  92 + larval->adult = alg;
  93 + complete(&larval->completion);
  94 + }
66 95 }
67 96  
68 97 list_add(&alg->cra_list, &crypto_alg_list);
69   - atomic_set(&alg->cra_refcnt, 1);
  98 +
  99 + crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
70 100 ret = 0;
  101 +
71 102 out:
72 103 return ret;
73 104 }
... ... @@ -97,6 +128,7 @@
97 128 list_del_init(&alg->cra_list);
98 129 ret = 0;
99 130 }
  131 + crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
100 132 up_write(&crypto_alg_sem);
101 133  
102 134 if (ret)
... ... @@ -123,6 +155,7 @@
123 155 }
124 156  
125 157 list_add(&tmpl->list, &crypto_template_list);
  158 + crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
126 159 err = 0;
127 160 out:
128 161 up_write(&crypto_alg_sem);
129 162  
... ... @@ -145,8 +178,11 @@
145 178 hlist_for_each_entry(inst, p, list, list) {
146 179 BUG_ON(list_empty(&inst->alg.cra_list));
147 180 list_del_init(&inst->alg.cra_list);
  181 + crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
148 182 }
149 183  
  184 + crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
  185 +
150 186 up_write(&crypto_alg_sem);
151 187  
152 188 hlist_for_each_entry_safe(inst, p, n, list, list) {
... ... @@ -211,6 +247,18 @@
211 247 return err;
212 248 }
213 249 EXPORT_SYMBOL_GPL(crypto_register_instance);
  250 +
  251 +int crypto_register_notifier(struct notifier_block *nb)
  252 +{
  253 + return blocking_notifier_chain_register(&crypto_chain, nb);
  254 +}
  255 +EXPORT_SYMBOL_GPL(crypto_register_notifier);
  256 +
  257 +int crypto_unregister_notifier(struct notifier_block *nb)
  258 +{
  259 + return blocking_notifier_chain_unregister(&crypto_chain, nb);
  260 +}
  261 +EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
214 262  
215 263 static int __init crypto_algapi_init(void)
216 264 {
... ... @@ -18,6 +18,7 @@
18 18 #include <linux/errno.h>
19 19 #include <linux/kernel.h>
20 20 #include <linux/kmod.h>
  21 +#include <linux/param.h>
21 22 #include <linux/slab.h>
22 23 #include <linux/string.h>
23 24 #include "internal.h"
... ... @@ -27,6 +28,9 @@
27 28 DECLARE_RWSEM(crypto_alg_sem);
28 29 EXPORT_SYMBOL_GPL(crypto_alg_sem);
29 30  
  31 +BLOCKING_NOTIFIER_HEAD(crypto_chain);
  32 +EXPORT_SYMBOL_GPL(crypto_chain);
  33 +
30 34 static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
31 35 {
32 36 atomic_inc(&alg->cra_refcnt);
33 37  
34 38  
35 39  
36 40  
37 41  
38 42  
... ... @@ -39,27 +43,24 @@
39 43 alg->cra_destroy(alg);
40 44 }
41 45  
42   -static struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
  46 +struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
43 47 {
44 48 return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
45 49 }
  50 +EXPORT_SYMBOL_GPL(crypto_mod_get);
46 51  
47   -static void crypto_mod_put(struct crypto_alg *alg)
  52 +void crypto_mod_put(struct crypto_alg *alg)
48 53 {
49 54 crypto_alg_put(alg);
50 55 module_put(alg->cra_module);
51 56 }
  57 +EXPORT_SYMBOL_GPL(crypto_mod_put);
52 58  
53   -static struct crypto_alg *crypto_alg_lookup(const char *name)
  59 +struct crypto_alg *__crypto_alg_lookup(const char *name)
54 60 {
55 61 struct crypto_alg *q, *alg = NULL;
56   - int best = -1;
  62 + int best = -2;
57 63  
58   - if (!name)
59   - return NULL;
60   -
61   - down_read(&crypto_alg_sem);
62   -
63 64 list_for_each_entry(q, &crypto_alg_list, cra_list) {
64 65 int exact, fuzzy;
65 66  
66 67  
67 68  
68 69  
... ... @@ -79,16 +80,113 @@
79 80 if (exact)
80 81 break;
81 82 }
82   -
  83 +
  84 + return alg;
  85 +}
  86 +EXPORT_SYMBOL_GPL(__crypto_alg_lookup);
  87 +
  88 +static void crypto_larval_destroy(struct crypto_alg *alg)
  89 +{
  90 + struct crypto_larval *larval = (void *)alg;
  91 +
  92 + BUG_ON(!crypto_is_larval(alg));
  93 + if (larval->adult)
  94 + crypto_mod_put(larval->adult);
  95 + kfree(larval);
  96 +}
  97 +
  98 +static struct crypto_alg *crypto_larval_alloc(const char *name)
  99 +{
  100 + struct crypto_alg *alg;
  101 + struct crypto_larval *larval;
  102 +
  103 + larval = kzalloc(sizeof(*larval), GFP_KERNEL);
  104 + if (!larval)
  105 + return NULL;
  106 +
  107 + larval->alg.cra_flags = CRYPTO_ALG_LARVAL;
  108 + larval->alg.cra_priority = -1;
  109 + larval->alg.cra_destroy = crypto_larval_destroy;
  110 +
  111 + atomic_set(&larval->alg.cra_refcnt, 2);
  112 + strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
  113 + init_completion(&larval->completion);
  114 +
  115 + down_write(&crypto_alg_sem);
  116 + alg = __crypto_alg_lookup(name);
  117 + if (!alg) {
  118 + alg = &larval->alg;
  119 + list_add(&alg->cra_list, &crypto_alg_list);
  120 + }
  121 + up_write(&crypto_alg_sem);
  122 +
  123 + if (alg != &larval->alg)
  124 + kfree(larval);
  125 +
  126 + return alg;
  127 +}
  128 +
  129 +static void crypto_larval_kill(struct crypto_alg *alg)
  130 +{
  131 + struct crypto_larval *larval = (void *)alg;
  132 +
  133 + down_write(&crypto_alg_sem);
  134 + list_del(&alg->cra_list);
  135 + up_write(&crypto_alg_sem);
  136 + complete(&larval->completion);
  137 + crypto_alg_put(alg);
  138 +}
  139 +
  140 +static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
  141 +{
  142 + struct crypto_larval *larval = (void *)alg;
  143 +
  144 + wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
  145 + alg = larval->adult;
  146 + if (alg && !crypto_mod_get(alg))
  147 + alg = NULL;
  148 + crypto_mod_put(&larval->alg);
  149 +
  150 + return alg;
  151 +}
  152 +
  153 +static struct crypto_alg *crypto_alg_lookup(const char *name)
  154 +{
  155 + struct crypto_alg *alg;
  156 +
  157 + if (!name)
  158 + return NULL;
  159 +
  160 + down_read(&crypto_alg_sem);
  161 + alg = __crypto_alg_lookup(name);
83 162 up_read(&crypto_alg_sem);
  163 +
84 164 return alg;
85 165 }
86 166  
87 167 /* A far more intelligent version of this is planned. For now, just
88 168 * try an exact match on the name of the algorithm. */
89   -static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
  169 +static struct crypto_alg *crypto_alg_mod_lookup(const char *name)
90 170 {
91   - return try_then_request_module(crypto_alg_lookup(name), name);
  171 + struct crypto_alg *alg;
  172 + struct crypto_alg *larval;
  173 +
  174 + alg = try_then_request_module(crypto_alg_lookup(name), name);
  175 + if (alg)
  176 + return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
  177 +
  178 + larval = crypto_larval_alloc(name);
  179 + if (!larval || !crypto_is_larval(larval))
  180 + return larval;
  181 +
  182 + if (crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval) == NOTIFY_STOP)
  183 + alg = crypto_larval_wait(larval);
  184 + else {
  185 + crypto_mod_put(larval);
  186 + alg = NULL;
  187 + }
  188 + crypto_larval_kill(larval);
  189 + return alg;
92 190 }
93 191  
94 192 static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
... ... @@ -14,6 +14,7 @@
14 14 #define _CRYPTO_INTERNAL_H
15 15  
16 16 #include <crypto/algapi.h>
  17 +#include <linux/completion.h>
17 18 #include <linux/mm.h>
18 19 #include <linux/highmem.h>
19 20 #include <linux/interrupt.h>
20 21  
21 22  
22 23  
... ... @@ -21,15 +22,32 @@
21 22 #include <linux/list.h>
22 23 #include <linux/module.h>
23 24 #include <linux/kernel.h>
  25 +#include <linux/notifier.h>
24 26 #include <linux/rwsem.h>
25 27 #include <linux/slab.h>
26 28 #include <asm/kmap_types.h>
27 29  
  30 +/* Crypto notification events. */
  31 +enum {
  32 + CRYPTO_MSG_ALG_REQUEST,
  33 + CRYPTO_MSG_ALG_REGISTER,
  34 + CRYPTO_MSG_ALG_UNREGISTER,
  35 + CRYPTO_MSG_TMPL_REGISTER,
  36 + CRYPTO_MSG_TMPL_UNREGISTER,
  37 +};
  38 +
28 39 struct crypto_instance;
29 40 struct crypto_template;
30 41  
  42 +struct crypto_larval {
  43 + struct crypto_alg alg;
  44 + struct crypto_alg *adult;
  45 + struct completion completion;
  46 +};
  47 +
31 48 extern struct list_head crypto_alg_list;
32 49 extern struct rw_semaphore crypto_alg_sem;
  50 +extern struct blocking_notifier_head crypto_chain;
33 51  
34 52 extern enum km_type crypto_km_types[];
35 53  
... ... @@ -104,6 +122,10 @@
104 122 return alg->cra_ctxsize;
105 123 }
106 124  
  125 +struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
  126 +void crypto_mod_put(struct crypto_alg *alg);
  127 +struct crypto_alg *__crypto_alg_lookup(const char *name);
  128 +
107 129 int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
108 130 int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
109 131 int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
110 132  
... ... @@ -116,9 +138,14 @@
116 138 void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
117 139 void crypto_exit_compress_ops(struct crypto_tfm *tfm);
118 140  
  141 +void crypto_larval_error(const char *name);
  142 +
119 143 int crypto_register_instance(struct crypto_template *tmpl,
120 144 struct crypto_instance *inst);
121 145  
  146 +int crypto_register_notifier(struct notifier_block *nb);
  147 +int crypto_unregister_notifier(struct notifier_block *nb);
  148 +
122 149 static inline int crypto_tmpl_get(struct crypto_template *tmpl)
123 150 {
124 151 return try_module_get(tmpl->module);
... ... @@ -127,6 +154,16 @@
127 154 static inline void crypto_tmpl_put(struct crypto_template *tmpl)
128 155 {
129 156 module_put(tmpl->module);
  157 +}
  158 +
  159 +static inline int crypto_is_larval(struct crypto_alg *alg)
  160 +{
  161 + return alg->cra_flags & CRYPTO_ALG_LARVAL;
  162 +}
  163 +
  164 +static inline int crypto_notify(unsigned long val, void *v)
  165 +{
  166 + return blocking_notifier_call_chain(&crypto_chain, val, v);
130 167 }
131 168  
132 169 #endif /* _CRYPTO_INTERNAL_H */
include/linux/crypto.h
... ... @@ -29,10 +29,12 @@
29 29 /*
30 30 * Algorithm masks and types.
31 31 */
32   -#define CRYPTO_ALG_TYPE_MASK 0x000000ff
  32 +#define CRYPTO_ALG_TYPE_MASK 0x0000000f
33 33 #define CRYPTO_ALG_TYPE_CIPHER 0x00000001
34 34 #define CRYPTO_ALG_TYPE_DIGEST 0x00000002
35 35 #define CRYPTO_ALG_TYPE_COMPRESS 0x00000004
  36 +
  37 +#define CRYPTO_ALG_LARVAL 0x00000010
36 38  
37 39 /*
38 40 * Transform masks and values (for crt_flags).