Commit 2825982d9d66ebba4b532a07391dfbb357f71c5f
1 parent
4cc7720cd1
Exists in
master
and in
7 other branches
[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
crypto/algapi.c
... | ... | @@ -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 | { |
crypto/api.c
... | ... | @@ -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) |
crypto/internal.h
... | ... | @@ -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). |