Return-Path: Received: from mta-p4.oit.umn.edu ([134.84.196.204]:54886 "EHLO mta-p4.oit.umn.edu" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725969AbeJ3D2P (ORCPT ); Mon, 29 Oct 2018 23:28:15 -0400 MIME-Version: 1.0 References: <1539910247-9250-1-git-send-email-wang6495@umn.edu> In-Reply-To: <1539910247-9250-1-git-send-email-wang6495@umn.edu> From: Wenwen Wang Date: Mon, 29 Oct 2018 13:37:45 -0500 Message-ID: Subject: Re: [PATCH] crypto: cavium/nitrox - fix a DMA pool free failure To: Wenwen Wang Cc: Kangjie Lu , herbert@gondor.apana.org.au, "David S. Miller" , kstewart@linuxfoundation.org, tglx@linutronix.de, pombredanne@nexb.com, Greg Kroah-Hartman , baijiaju1990@gmail.com, Jampala.Srikanth@cavium.com, sgadam@cavium.com, linux-crypto@vger.kernel.org, open list Content-Type: text/plain; charset="UTF-8" Sender: linux-crypto-owner@vger.kernel.org List-ID: Hello, Can anyone confirm this bug? Thanks! Wenwen On Thu, Oct 18, 2018 at 7:51 PM Wenwen Wang 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 > --- > 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 >