diff options
Diffstat (limited to 'crypto/api.c')
-rw-r--r-- | crypto/api.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/crypto/api.c b/crypto/api.c index 394169a8577d..b4728811ce3b 100644 --- a/crypto/api.c +++ b/crypto/api.c | |||
@@ -13,9 +13,12 @@ | |||
13 | * any later version. | 13 | * any later version. |
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | |||
17 | #include <linux/compiler.h> | ||
16 | #include <linux/init.h> | 18 | #include <linux/init.h> |
17 | #include <linux/crypto.h> | 19 | #include <linux/crypto.h> |
18 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/kmod.h> | ||
19 | #include <linux/rwsem.h> | 22 | #include <linux/rwsem.h> |
20 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
21 | #include "internal.h" | 24 | #include "internal.h" |
@@ -33,7 +36,7 @@ static inline void crypto_alg_put(struct crypto_alg *alg) | |||
33 | module_put(alg->cra_module); | 36 | module_put(alg->cra_module); |
34 | } | 37 | } |
35 | 38 | ||
36 | struct crypto_alg *crypto_alg_lookup(const char *name) | 39 | static struct crypto_alg *crypto_alg_lookup(const char *name) |
37 | { | 40 | { |
38 | struct crypto_alg *q, *alg = NULL; | 41 | struct crypto_alg *q, *alg = NULL; |
39 | 42 | ||
@@ -54,6 +57,13 @@ struct crypto_alg *crypto_alg_lookup(const char *name) | |||
54 | return alg; | 57 | return alg; |
55 | } | 58 | } |
56 | 59 | ||
60 | /* A far more intelligent version of this is planned. For now, just | ||
61 | * try an exact match on the name of the algorithm. */ | ||
62 | static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) | ||
63 | { | ||
64 | return try_then_request_module(crypto_alg_lookup(name), name); | ||
65 | } | ||
66 | |||
57 | static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) | 67 | static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) |
58 | { | 68 | { |
59 | tfm->crt_flags = 0; | 69 | tfm->crt_flags = 0; |
@@ -117,20 +127,46 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) | |||
117 | } | 127 | } |
118 | } | 128 | } |
119 | 129 | ||
130 | static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) | ||
131 | { | ||
132 | unsigned int len; | ||
133 | |||
134 | switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { | ||
135 | default: | ||
136 | BUG(); | ||
137 | |||
138 | case CRYPTO_ALG_TYPE_CIPHER: | ||
139 | len = crypto_cipher_ctxsize(alg, flags); | ||
140 | break; | ||
141 | |||
142 | case CRYPTO_ALG_TYPE_DIGEST: | ||
143 | len = crypto_digest_ctxsize(alg, flags); | ||
144 | break; | ||
145 | |||
146 | case CRYPTO_ALG_TYPE_COMPRESS: | ||
147 | len = crypto_compress_ctxsize(alg, flags); | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | return len + alg->cra_alignmask; | ||
152 | } | ||
153 | |||
120 | struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) | 154 | struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) |
121 | { | 155 | { |
122 | struct crypto_tfm *tfm = NULL; | 156 | struct crypto_tfm *tfm = NULL; |
123 | struct crypto_alg *alg; | 157 | struct crypto_alg *alg; |
158 | unsigned int tfm_size; | ||
124 | 159 | ||
125 | alg = crypto_alg_mod_lookup(name); | 160 | alg = crypto_alg_mod_lookup(name); |
126 | if (alg == NULL) | 161 | if (alg == NULL) |
127 | goto out; | 162 | goto out; |
128 | 163 | ||
129 | tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL); | 164 | tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); |
165 | tfm = kmalloc(tfm_size, GFP_KERNEL); | ||
130 | if (tfm == NULL) | 166 | if (tfm == NULL) |
131 | goto out_put; | 167 | goto out_put; |
132 | 168 | ||
133 | memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); | 169 | memset(tfm, 0, tfm_size); |
134 | 170 | ||
135 | tfm->__crt_alg = alg; | 171 | tfm->__crt_alg = alg; |
136 | 172 | ||
@@ -155,8 +191,14 @@ out: | |||
155 | 191 | ||
156 | void crypto_free_tfm(struct crypto_tfm *tfm) | 192 | void crypto_free_tfm(struct crypto_tfm *tfm) |
157 | { | 193 | { |
158 | struct crypto_alg *alg = tfm->__crt_alg; | 194 | struct crypto_alg *alg; |
159 | int size = sizeof(*tfm) + alg->cra_ctxsize; | 195 | int size; |
196 | |||
197 | if (unlikely(!tfm)) | ||
198 | return; | ||
199 | |||
200 | alg = tfm->__crt_alg; | ||
201 | size = sizeof(*tfm) + alg->cra_ctxsize; | ||
160 | 202 | ||
161 | crypto_exit_ops(tfm); | 203 | crypto_exit_ops(tfm); |
162 | crypto_alg_put(alg); | 204 | crypto_alg_put(alg); |
@@ -168,6 +210,12 @@ int crypto_register_alg(struct crypto_alg *alg) | |||
168 | { | 210 | { |
169 | int ret = 0; | 211 | int ret = 0; |
170 | struct crypto_alg *q; | 212 | struct crypto_alg *q; |
213 | |||
214 | if (alg->cra_alignmask & (alg->cra_alignmask + 1)) | ||
215 | return -EINVAL; | ||
216 | |||
217 | if (alg->cra_alignmask > PAGE_SIZE) | ||
218 | return -EINVAL; | ||
171 | 219 | ||
172 | down_write(&crypto_alg_sem); | 220 | down_write(&crypto_alg_sem); |
173 | 221 | ||