[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>
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 6e93004f..cbb4c4e 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -16,6 +16,7 @@
 
 #include <linux/crypto.h>
 #include <linux/errno.h>
+#include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
@@ -313,6 +314,9 @@
 	struct crypto_blkcipher *tfm = desc->tfm;
 	unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
 
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+
 	walk->nbytes = walk->total;
 	if (unlikely(!walk->total))
 		return 0;
diff --git a/crypto/digest.c b/crypto/digest.c
index 8f45932..bc47af6 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -14,7 +14,9 @@
 
 #include <linux/mm.h>
 #include <linux/errno.h>
+#include <linux/hardirq.h>
 #include <linux/highmem.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/scatterlist.h>
 
@@ -29,8 +31,8 @@
 	return 0;
 }
 
-static int update(struct hash_desc *desc,
-		  struct scatterlist *sg, unsigned int nbytes)
+static int update2(struct hash_desc *desc,
+		   struct scatterlist *sg, unsigned int nbytes)
 {
 	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
 	unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
@@ -81,6 +83,14 @@
 	return 0;
 }
 
+static int update(struct hash_desc *desc,
+		  struct scatterlist *sg, unsigned int nbytes)
+{
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+	return update2(desc, sg, nbytes);
+}
+
 static int final(struct hash_desc *desc, u8 *out)
 {
 	struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
@@ -118,8 +128,11 @@
 static int digest(struct hash_desc *desc,
 		  struct scatterlist *sg, unsigned int nbytes, u8 *out)
 {
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+
 	init(desc);
-	update(desc, sg, nbytes);
+	update2(desc, sg, nbytes);
 	return final(desc, out);
 }
 
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 9347eb6..317e9f0 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -21,6 +21,7 @@
 
 #include <linux/crypto.h>
 #include <linux/err.h>
+#include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/rtnetlink.h>
@@ -108,9 +109,9 @@
 	return 0;
 }
 
-static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
-				     struct scatterlist *sg,
-				     unsigned int nbytes)
+static int crypto_xcbc_digest_update2(struct hash_desc *pdesc,
+				      struct scatterlist *sg,
+				      unsigned int nbytes)
 {
 	struct crypto_hash *parent = pdesc->tfm;
 	struct crypto_xcbc_ctx *ctx = crypto_hash_ctx_aligned(parent);
@@ -183,6 +184,15 @@
 	return 0;
 }
 
+static int crypto_xcbc_digest_update(struct hash_desc *pdesc,
+				     struct scatterlist *sg,
+				     unsigned int nbytes)
+{
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+	return crypto_xcbc_digest_update2(pdesc, sg, nbytes);
+}
+
 static int crypto_xcbc_digest_final(struct hash_desc *pdesc, u8 *out)
 {
 	struct crypto_hash *parent = pdesc->tfm;
@@ -234,8 +244,11 @@
 static int crypto_xcbc_digest(struct hash_desc *pdesc,
 		  struct scatterlist *sg, unsigned int nbytes, u8 *out)
 {
+	if (WARN_ON_ONCE(in_irq()))
+		return -EDEADLK;
+
 	crypto_xcbc_digest_init(pdesc);
-	crypto_xcbc_digest_update(pdesc, sg, nbytes);
+	crypto_xcbc_digest_update2(pdesc, sg, nbytes);
 	return crypto_xcbc_digest_final(pdesc, out);
 }