Commit 23ad69aa authored by Herbert Xu's avatar Herbert Xu

crypto: nx/842 - Fix context corruption

The transform context is shared memory and must not be written
to without locking.  This patch adds locking to nx-842 to prevent
context corruption.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 2c11a3f9
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sw842.h> #include <linux/sw842.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/spinlock.h>
#include "nx-842.h" #include "nx-842.h"
...@@ -125,6 +126,8 @@ static int update_param(struct nx842_crypto_param *p, ...@@ -125,6 +126,8 @@ static int update_param(struct nx842_crypto_param *p,
} }
struct nx842_crypto_ctx { struct nx842_crypto_ctx {
spinlock_t lock;
u8 *wmem; u8 *wmem;
u8 *sbounce, *dbounce; u8 *sbounce, *dbounce;
...@@ -136,6 +139,7 @@ static int nx842_crypto_init(struct crypto_tfm *tfm) ...@@ -136,6 +139,7 @@ static int nx842_crypto_init(struct crypto_tfm *tfm)
{ {
struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm);
spin_lock_init(&ctx->lock);
ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL); ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL);
ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER);
...@@ -315,6 +319,8 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, ...@@ -315,6 +319,8 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm,
DIV_ROUND_UP(p.iremain, c.maximum)); DIV_ROUND_UP(p.iremain, c.maximum));
hdrsize = NX842_CRYPTO_HEADER_SIZE(groups); hdrsize = NX842_CRYPTO_HEADER_SIZE(groups);
spin_lock_bh(&ctx->lock);
/* skip adding header if the buffers meet all constraints */ /* skip adding header if the buffers meet all constraints */
add_header = (p.iremain % c.multiple || add_header = (p.iremain % c.multiple ||
p.iremain < c.minimum || p.iremain < c.minimum ||
...@@ -331,8 +337,9 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, ...@@ -331,8 +337,9 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm,
while (p.iremain > 0) { while (p.iremain > 0) {
n = hdr->groups++; n = hdr->groups++;
ret = -ENOSPC;
if (hdr->groups > NX842_CRYPTO_GROUP_MAX) if (hdr->groups > NX842_CRYPTO_GROUP_MAX)
return -ENOSPC; goto unlock;
/* header goes before first group */ /* header goes before first group */
h = !n && add_header ? hdrsize : 0; h = !n && add_header ? hdrsize : 0;
...@@ -342,12 +349,13 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, ...@@ -342,12 +349,13 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm,
ret = compress(ctx, &p, &hdr->group[n], &c, &ignore, h); ret = compress(ctx, &p, &hdr->group[n], &c, &ignore, h);
if (ret) if (ret)
return ret; goto unlock;
} }
if (!add_header && hdr->groups > 1) { if (!add_header && hdr->groups > 1) {
pr_err("Internal error: No header but multiple groups\n"); pr_err("Internal error: No header but multiple groups\n");
return -EINVAL; ret = -EINVAL;
goto unlock;
} }
/* ignore indicates the input stream needed to be padded */ /* ignore indicates the input stream needed to be padded */
...@@ -358,13 +366,15 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, ...@@ -358,13 +366,15 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm,
if (add_header) if (add_header)
ret = nx842_crypto_add_header(hdr, dst); ret = nx842_crypto_add_header(hdr, dst);
if (ret) if (ret)
return ret; goto unlock;
*dlen = p.ototal; *dlen = p.ototal;
pr_debug("compress total slen %x dlen %x\n", slen, *dlen); pr_debug("compress total slen %x dlen %x\n", slen, *dlen);
return 0; unlock:
spin_unlock_bh(&ctx->lock);
return ret;
} }
static int decompress(struct nx842_crypto_ctx *ctx, static int decompress(struct nx842_crypto_ctx *ctx,
...@@ -494,6 +504,8 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, ...@@ -494,6 +504,8 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm,
hdr = (struct nx842_crypto_header *)src; hdr = (struct nx842_crypto_header *)src;
spin_lock_bh(&ctx->lock);
/* If it doesn't start with our header magic number, assume it's a raw /* If it doesn't start with our header magic number, assume it's a raw
* 842 compressed buffer and pass it directly to the hardware driver * 842 compressed buffer and pass it directly to the hardware driver
*/ */
...@@ -506,26 +518,31 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, ...@@ -506,26 +518,31 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm,
ret = decompress(ctx, &p, &g, &c, 0, usehw); ret = decompress(ctx, &p, &g, &c, 0, usehw);
if (ret) if (ret)
return ret; goto unlock;
*dlen = p.ototal; *dlen = p.ototal;
return 0; ret = 0;
goto unlock;
} }
if (!hdr->groups) { if (!hdr->groups) {
pr_err("header has no groups\n"); pr_err("header has no groups\n");
return -EINVAL; ret = -EINVAL;
goto unlock;
} }
if (hdr->groups > NX842_CRYPTO_GROUP_MAX) { if (hdr->groups > NX842_CRYPTO_GROUP_MAX) {
pr_err("header has too many groups %x, max %x\n", pr_err("header has too many groups %x, max %x\n",
hdr->groups, NX842_CRYPTO_GROUP_MAX); hdr->groups, NX842_CRYPTO_GROUP_MAX);
return -EINVAL; ret = -EINVAL;
goto unlock;
} }
hdr_len = NX842_CRYPTO_HEADER_SIZE(hdr->groups); hdr_len = NX842_CRYPTO_HEADER_SIZE(hdr->groups);
if (hdr_len > slen) if (hdr_len > slen) {
return -EOVERFLOW; ret = -EOVERFLOW;
goto unlock;
}
memcpy(&ctx->header, src, hdr_len); memcpy(&ctx->header, src, hdr_len);
hdr = &ctx->header; hdr = &ctx->header;
...@@ -537,14 +554,19 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, ...@@ -537,14 +554,19 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm,
ret = decompress(ctx, &p, &hdr->group[n], &c, ignore, usehw); ret = decompress(ctx, &p, &hdr->group[n], &c, ignore, usehw);
if (ret) if (ret)
return ret; goto unlock;
} }
*dlen = p.ototal; *dlen = p.ototal;
pr_debug("decompress total slen %x dlen %x\n", slen, *dlen); pr_debug("decompress total slen %x dlen %x\n", slen, *dlen);
return 0; ret = 0;
unlock:
spin_unlock_bh(&ctx->lock);
return ret;
} }
static struct crypto_alg alg = { static struct crypto_alg alg = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment