diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-12-09 18:45:28 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2007-02-06 17:20:58 -0500 |
commit | fb469840b8c34b2f95b40a64b271f245cc1075b7 (patch) | |
tree | 8013f8beb39c83b80be0e40195005b0482cea69b | |
parent | 62d0cfcb27cf755cebdc93ca95dabc83608007cd (diff) |
[CRYPTO] all: Check for usage in hard IRQ context
Using blkcipher/hash crypto operations in hard IRQ context can lead
to random memory corruption due to the reuse of kmap_atomic slots.
Since crypto operations were never meant to be used in hard IRQ
contexts, this patch checks for such usage and returns an error
before kmap_atomic is performed.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | crypto/blkcipher.c | 4 | ||||
-rw-r--r-- | crypto/digest.c | 19 | ||||
-rw-r--r-- | crypto/xcbc.c | 21 |
3 files changed, 37 insertions, 7 deletions
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 6e93004f2181..cbb4c4e5c229 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/crypto.h> | 17 | #include <linux/crypto.h> |
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/hardirq.h> | ||
19 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
21 | #include <linux/scatterlist.h> | 22 | #include <linux/scatterlist.h> |
@@ -313,6 +314,9 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc, | |||
313 | struct crypto_blkcipher *tfm = desc->tfm; | 314 | struct crypto_blkcipher *tfm = desc->tfm; |
314 | unsigned int alignmask = crypto_blkcipher_alignmask(tfm); | 315 | unsigned int alignmask = crypto_blkcipher_alignmask(tfm); |
315 | 316 | ||
317 | if (WARN_ON_ONCE(in_irq())) | ||
318 | return -EDEADLK; | ||
319 | |||
316 | walk->nbytes = walk->total; | 320 | walk->nbytes = walk->total; |
317 | if (unlikely(!walk->total)) | 321 | if (unlikely(!walk->total)) |
318 | return 0; | 322 | return 0; |
diff --git a/crypto/digest.c b/crypto/digest.c index 8f4593268ce0..bc47af648cb1 100644 --- a/crypto/digest.c +++ b/crypto/digest.c | |||
@@ -14,7 +14,9 @@ | |||
14 | 14 | ||
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/hardirq.h> | ||
17 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
19 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | 20 | #include <linux/module.h> |
19 | #include <linux/scatterlist.h> | 21 | #include <linux/scatterlist.h> |
20 | 22 | ||
@@ -29,8 +31,8 @@ static int init(struct hash_desc *desc) | |||
29 | return 0; | 31 | return 0; |
30 | } | 32 | } |
31 | 33 | ||
32 | static int update(struct hash_desc *desc, | 34 | static int update2(struct hash_desc *desc, |
33 | struct scatterlist *sg, unsigned int nbytes) | 35 | struct scatterlist *sg, unsigned int nbytes) |
34 | { | 36 | { |
35 | struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); | 37 | struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); |
36 | unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); | 38 | unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); |
@@ -81,6 +83,14 @@ static int update(struct hash_desc *desc, | |||
81 | return 0; | 83 | return 0; |
82 | } | 84 | } |
83 | 85 | ||
86 | static int update(struct hash_desc *desc, | ||
87 | struct scatterlist *sg, unsigned int nbytes) | ||
88 | { | ||
89 | if (WARN_ON_ONCE(in_irq())) | ||
90 | return -EDEADLK; | ||
91 | return update2(desc, sg, nbytes); | ||
92 | } | ||
93 | |||
84 | static int final(struct hash_desc *desc, u8 *out) | 94 | static int final(struct hash_desc *desc, u8 *out) |
85 | { | 95 | { |
86 | struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); | 96 | struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm); |
@@ -118,8 +128,11 @@ static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen) | |||
118 | static int digest(struct hash_desc *desc, | 128 | static int digest(struct hash_desc *desc, |
119 | struct scatterlist *sg, unsigned int nbytes, u8 *out) | 129 | struct scatterlist *sg, unsigned int nbytes, u8 *out) |
120 | { | 130 | { |
131 | if (WARN_ON_ONCE(in_irq())) | ||
132 | return -EDEADLK; | ||
133 | |||
121 | init(desc); | 134 | init(desc); |
122 | update(desc, sg, nbytes); | 135 | update2(desc, sg, nbytes); |
123 | return final(desc, out); | 136 | return final(desc, out); |
124 | } | 137 | } |
125 | 138 | ||
diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 9347eb6bcf69..317e9f08fc04 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include <linux/crypto.h> | 22 | #include <linux/crypto.h> |
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <linux/hardirq.h> | ||
24 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
25 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
26 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
@@ -108,9 +109,9 @@ static int crypto_xcbc_digest_init(struct hash_desc *pdesc) | |||
108 | return 0; | 109 | return 0; |
109 | } | 110 | } |
110 | 111 | ||
111 | static int crypto_xcbc_digest_update(struct hash_desc *pdesc, | 112 | static int crypto_xcbc_digest_update2(struct hash_desc *pdesc, |
112 | struct scatterlist *sg, | 113 | struct scatterlist *sg, |
113 | unsigned int nbytes) | 114 | unsigned int nbytes) |
114 | { | 115 | { |
115 | struct crypto_hash *parent = pdesc->tfm; | 116 | struct crypto_hash *parent = pdesc->tfm; |
116 | struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); | 117 | struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent); |
@@ -183,6 +184,15 @@ static int crypto_xcbc_digest_update(struct hash_desc *pdesc, | |||
183 | return 0; | 184 | return 0; |
184 | } | 185 | } |
185 | 186 | ||
187 | static int crypto_xcbc_digest_update(struct hash_desc *pdesc, | ||
188 | struct scatterlist *sg, | ||
189 | unsigned int nbytes) | ||
190 | { | ||
191 | if (WARN_ON_ONCE(in_irq())) | ||
192 | return -EDEADLK; | ||
193 | return crypto_xcbc_digest_update2(pdesc, sg, nbytes); | ||
194 | } | ||
195 | |||
186 | static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) | 196 | static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) |
187 | { | 197 | { |
188 | struct crypto_hash *parent = pdesc->tfm; | 198 | struct crypto_hash *parent = pdesc->tfm; |
@@ -234,8 +244,11 @@ static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out) | |||
234 | static int crypto_xcbc_digest(struct hash_desc *pdesc, | 244 | static int crypto_xcbc_digest(struct hash_desc *pdesc, |
235 | struct scatterlist *sg, unsigned int nbytes, u8 *out) | 245 | struct scatterlist *sg, unsigned int nbytes, u8 *out) |
236 | { | 246 | { |
247 | if (WARN_ON_ONCE(in_irq())) | ||
248 | return -EDEADLK; | ||
249 | |||
237 | crypto_xcbc_digest_init(pdesc); | 250 | crypto_xcbc_digest_init(pdesc); |
238 | crypto_xcbc_digest_update(pdesc, sg, nbytes); | 251 | crypto_xcbc_digest_update2(pdesc, sg, nbytes); |
239 | return crypto_xcbc_digest_final(pdesc, out); | 252 | return crypto_xcbc_digest_final(pdesc, out); |
240 | } | 253 | } |
241 | 254 | ||