Re: [PATCH] crypto: cavium/nitrox - fix a DMA pool free failure

From: Wenwen Wang
Date: Mon Oct 29 2018 - 14:38:26 EST


Hello,

Can anyone confirm this bug? Thanks!

Wenwen

On Thu, Oct 18, 2018 at 7:51 PM Wenwen Wang <wang6495@xxxxxxx> wrote:
>
> In crypto_alloc_context(), a DMA pool is allocated through dma_pool_alloc()
> to hold the crypto context. The meta data of the DMA pool, including the
> pool used for the allocation 'ndev->ctx_pool' and the base address of the
> DMA pool used by the device 'dma', are then stored to the beginning of the
> pool. These meta data are eventually used in crypto_free_context() to free
> the DMA pool through dma_pool_free(). However, given that the DMA pool can
> also be accessed by the device, a malicious device can modify these meta
> data, especially when the device is controlled to deploy an attack. This
> can cause an unexpected DMA pool free failure.
>
> To avoid the above issue, this patch introduces a new structure
> crypto_ctx_hdr and a new field chdr in the structure nitrox_crypto_ctx hold
> the meta data information of the DMA pool after the allocation. Note that
> the original structure ctx_hdr is not changed to ensure the compatibility.
>
> Signed-off-by: Wenwen Wang <wang6495@xxxxxxx>
> ---
> drivers/crypto/cavium/nitrox/nitrox_algs.c | 12 +++++++-----
> drivers/crypto/cavium/nitrox/nitrox_lib.c | 22 +++++++++++++++++-----
> drivers/crypto/cavium/nitrox/nitrox_req.h | 7 +++++++
> 3 files changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/crypto/cavium/nitrox/nitrox_algs.c b/drivers/crypto/cavium/nitrox/nitrox_algs.c
> index 2ae6124..5d54ebc 100644
> --- a/drivers/crypto/cavium/nitrox/nitrox_algs.c
> +++ b/drivers/crypto/cavium/nitrox/nitrox_algs.c
> @@ -73,7 +73,7 @@ static int flexi_aes_keylen(int keylen)
> static int nitrox_skcipher_init(struct crypto_skcipher *tfm)
> {
> struct nitrox_crypto_ctx *nctx = crypto_skcipher_ctx(tfm);
> - void *fctx;
> + struct crypto_ctx_hdr *chdr;
>
> /* get the first device */
> nctx->ndev = nitrox_get_first_device();
> @@ -81,12 +81,14 @@ static int nitrox_skcipher_init(struct crypto_skcipher *tfm)
> return -ENODEV;
>
> /* allocate nitrox crypto context */
> - fctx = crypto_alloc_context(nctx->ndev);
> - if (!fctx) {
> + chdr = crypto_alloc_context(nctx->ndev);
> + if (!chdr) {
> nitrox_put_device(nctx->ndev);
> return -ENOMEM;
> }
> - nctx->u.ctx_handle = (uintptr_t)fctx;
> + nctx->chdr = chdr;
> + nctx->u.ctx_handle = (uintptr_t)((u8 *)chdr->vaddr +
> + sizeof(struct ctx_hdr));
> crypto_skcipher_set_reqsize(tfm, crypto_skcipher_reqsize(tfm) +
> sizeof(struct nitrox_kcrypt_request));
> return 0;
> @@ -102,7 +104,7 @@ static void nitrox_skcipher_exit(struct crypto_skcipher *tfm)
>
> memset(&fctx->crypto, 0, sizeof(struct crypto_keys));
> memset(&fctx->auth, 0, sizeof(struct auth_keys));
> - crypto_free_context((void *)fctx);
> + crypto_free_context((void *)nctx->chdr);
> }
> nitrox_put_device(nctx->ndev);
>
> diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c
> index 4d31df0..28baf1a 100644
> --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c
> +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c
> @@ -146,12 +146,19 @@ static void destroy_crypto_dma_pool(struct nitrox_device *ndev)
> void *crypto_alloc_context(struct nitrox_device *ndev)
> {
> struct ctx_hdr *ctx;
> + struct crypto_ctx_hdr *chdr;
> void *vaddr;
> dma_addr_t dma;
>
> + chdr = kmalloc(sizeof(*chdr), GFP_KERNEL);
> + if (!chdr)
> + return NULL;
> +
> vaddr = dma_pool_alloc(ndev->ctx_pool, (GFP_KERNEL | __GFP_ZERO), &dma);
> - if (!vaddr)
> + if (!vaddr) {
> + kfree(chdr);
> return NULL;
> + }
>
> /* fill meta data */
> ctx = vaddr;
> @@ -159,7 +166,11 @@ void *crypto_alloc_context(struct nitrox_device *ndev)
> ctx->dma = dma;
> ctx->ctx_dma = dma + sizeof(struct ctx_hdr);
>
> - return ((u8 *)vaddr + sizeof(struct ctx_hdr));
> + chdr->pool = ndev->ctx_pool;
> + chdr->dma = dma;
> + chdr->vaddr = vaddr;
> +
> + return chdr;
> }
>
> /**
> @@ -168,13 +179,14 @@ void *crypto_alloc_context(struct nitrox_device *ndev)
> */
> void crypto_free_context(void *ctx)
> {
> - struct ctx_hdr *ctxp;
> + struct crypto_ctx_hdr *ctxp;
>
> if (!ctx)
> return;
>
> - ctxp = (struct ctx_hdr *)((u8 *)ctx - sizeof(struct ctx_hdr));
> - dma_pool_free(ctxp->pool, ctxp, ctxp->dma);
> + ctxp = ctx;
> + dma_pool_free(ctxp->pool, ctxp->vaddr, ctxp->dma);
> + kfree(ctxp);
> }
>
> /**
> diff --git a/drivers/crypto/cavium/nitrox/nitrox_req.h b/drivers/crypto/cavium/nitrox/nitrox_req.h
> index d091b6f..19f0a20 100644
> --- a/drivers/crypto/cavium/nitrox/nitrox_req.h
> +++ b/drivers/crypto/cavium/nitrox/nitrox_req.h
> @@ -181,12 +181,19 @@ struct flexi_crypto_context {
> struct auth_keys auth;
> };
>
> +struct crypto_ctx_hdr {
> + struct dma_pool *pool;
> + dma_addr_t dma;
> + void *vaddr;
> +};
> +
> struct nitrox_crypto_ctx {
> struct nitrox_device *ndev;
> union {
> u64 ctx_handle;
> struct flexi_crypto_context *fctx;
> } u;
> + struct crypto_ctx_hdr *chdr;
> };
>
> struct nitrox_kcrypt_request {
> --
> 2.7.4
>