2019-06-25 04:03:34

by Alan Mikhak

[permalink] [raw]
Subject: [PATCH] nvme-pci: Avoid leak if pci_p2pmem_virt_to_bus() returns null

Modify nvme_alloc_sq_cmds() to call pci_free_p2pmem()
to free the memory it allocated using pci_alloc_p2pmem()
in case pci_p2pmem_virt_to_bus() returns null.

Make sure not to call pci_free_p2pmem() if pci_alloc_p2pmem()
returned null which can happen if CONFIG_PCI_P2PDMA is not
configured.

Signed-off-by: Alan Mikhak <[email protected]>
---
drivers/nvme/host/pci.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 524d6bd6d095..5dfa067f6506 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1456,11 +1456,15 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,

if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
- nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
- nvmeq->sq_cmds);
- if (nvmeq->sq_dma_addr) {
- set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
- return 0;
+ if (nvmeq->sq_cmds) {
+ nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
+ nvmeq->sq_cmds);
+ if (nvmeq->sq_dma_addr) {
+ set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
+ return 0;
+ }
+
+ pci_free_p2pmem(pdev, nvmeq->sq_cmds, SQ_SIZE(depth));
}
}

--
2.7.4


2019-06-25 07:50:15

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH] nvme-pci: Avoid leak if pci_p2pmem_virt_to_bus() returns null

On Mon, Jun 24, 2019 at 04:57:22PM -0700, Alan Mikhak wrote:
> Modify nvme_alloc_sq_cmds() to call pci_free_p2pmem()
> to free the memory it allocated using pci_alloc_p2pmem()
> in case pci_p2pmem_virt_to_bus() returns null.
>
> Make sure not to call pci_free_p2pmem() if pci_alloc_p2pmem()
> returned null which can happen if CONFIG_PCI_P2PDMA is not
> configured.

Can you

>
> Signed-off-by: Alan Mikhak <[email protected]>
> ---
> drivers/nvme/host/pci.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 524d6bd6d095..5dfa067f6506 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -1456,11 +1456,15 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
>
> if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
> nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
> - nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> - nvmeq->sq_cmds);
> - if (nvmeq->sq_dma_addr) {
> - set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> - return 0;
> + if (nvmeq->sq_cmds) {
> + nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> + nvmeq->sq_cmds);
> + if (nvmeq->sq_dma_addr) {
> + set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> + return 0;
> + }
> +
> + pci_free_p2pmem(pdev, nvmeq->sq_cmds, SQ_SIZE(depth));

pci_p2pmem_virt_to_bus should only fail when
pci_p2pmem_virt_to_bus failed. That being said I think doing the
error check on pci_alloc_p2pmem instead of relying on
pci_p2pmem_virt_to_bus "passing through" the error seems odd, I'd
rather check the pci_alloc_p2pmem return value directly.

2019-06-25 19:45:07

by Alan Mikhak

[permalink] [raw]
Subject: Re: [PATCH] nvme-pci: Avoid leak if pci_p2pmem_virt_to_bus() returns null

On Tue, Jun 25, 2019 at 12:09 AM Christoph Hellwig <[email protected]> wrote:
>
> On Mon, Jun 24, 2019 at 04:57:22PM -0700, Alan Mikhak wrote:
> > Modify nvme_alloc_sq_cmds() to call pci_free_p2pmem()
> > to free the memory it allocated using pci_alloc_p2pmem()
> > in case pci_p2pmem_virt_to_bus() returns null.
> >
> > Make sure not to call pci_free_p2pmem() if pci_alloc_p2pmem()
> > returned null which can happen if CONFIG_PCI_P2PDMA is not
> > configured.
>
> Can you
>

I mean this patch makes sure not to call pci_free_p2pmem() if nothing
was allocated by pci_alloc_p2pmem().

> >
> > Signed-off-by: Alan Mikhak <[email protected]>
> > ---
> > drivers/nvme/host/pci.c | 14 +++++++++-----
> > 1 file changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> > index 524d6bd6d095..5dfa067f6506 100644
> > --- a/drivers/nvme/host/pci.c
> > +++ b/drivers/nvme/host/pci.c
> > @@ -1456,11 +1456,15 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
> >
> > if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
> > nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
> > - nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> > - nvmeq->sq_cmds);
> > - if (nvmeq->sq_dma_addr) {
> > - set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> > - return 0;
> > + if (nvmeq->sq_cmds) {
> > + nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> > + nvmeq->sq_cmds);
> > + if (nvmeq->sq_dma_addr) {
> > + set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> > + return 0;
> > + }
> > +
> > + pci_free_p2pmem(pdev, nvmeq->sq_cmds, SQ_SIZE(depth));
>
> pci_p2pmem_virt_to_bus should only fail when
> pci_p2pmem_virt_to_bus failed. That being said I think doing the
> error check on pci_alloc_p2pmem instead of relying on
> pci_p2pmem_virt_to_bus "passing through" the error seems odd, I'd
> rather check the pci_alloc_p2pmem return value directly.

Thanks Christoph. I could see the existing code should not leak but only after
inspecting pci_p2pmem_virt_to_bus() and gen_pool_virt_to_phys(). I wondered
what if these functions changed and broke the relation but that seems unlikely.
Checking the return value directly may require less from the reader,
if that's a good
outcome.

Alan

2019-06-25 19:45:09

by Heitke, Kenneth

[permalink] [raw]
Subject: Re: [PATCH] nvme-pci: Avoid leak if pci_p2pmem_virt_to_bus() returns null



On 6/24/2019 5:57 PM, Alan Mikhak wrote:
> Modify nvme_alloc_sq_cmds() to call pci_free_p2pmem()
> to free the memory it allocated using pci_alloc_p2pmem()
> in case pci_p2pmem_virt_to_bus() returns null.
>
> Make sure not to call pci_free_p2pmem() if pci_alloc_p2pmem()
> returned null which can happen if CONFIG_PCI_P2PDMA is not
> configured.
>
> Signed-off-by: Alan Mikhak <[email protected]>
> ---
> drivers/nvme/host/pci.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 524d6bd6d095..5dfa067f6506 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -1456,11 +1456,15 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
>
> if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
> nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
> - nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> - nvmeq->sq_cmds);
> - if (nvmeq->sq_dma_addr) {
> - set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> - return 0;
> + if (nvmeq->sq_cmds) {
> + nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> + nvmeq->sq_cmds);
> + if (nvmeq->sq_dma_addr) {
> + set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> + return 0;
> + }
> +
> + pci_free_p2pmem(pdev, nvmeq->sq_cmds, SQ_SIZE(depth));

Should the pointer be set to NULL here, just in case?

> }
> }
>
>

2019-06-25 19:46:26

by Alan Mikhak

[permalink] [raw]
Subject: Re: [PATCH] nvme-pci: Avoid leak if pci_p2pmem_virt_to_bus() returns null

On Tue, Jun 25, 2019 at 10:10 AM Heitke, Kenneth
<[email protected]> wrote:
>
>
>
> On 6/24/2019 5:57 PM, Alan Mikhak wrote:
> > Modify nvme_alloc_sq_cmds() to call pci_free_p2pmem()
> > to free the memory it allocated using pci_alloc_p2pmem()
> > in case pci_p2pmem_virt_to_bus() returns null.
> >
> > Make sure not to call pci_free_p2pmem() if pci_alloc_p2pmem()
> > returned null which can happen if CONFIG_PCI_P2PDMA is not
> > configured.
> >
> > Signed-off-by: Alan Mikhak <[email protected]>
> > ---
> > drivers/nvme/host/pci.c | 14 +++++++++-----
> > 1 file changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> > index 524d6bd6d095..5dfa067f6506 100644
> > --- a/drivers/nvme/host/pci.c
> > +++ b/drivers/nvme/host/pci.c
> > @@ -1456,11 +1456,15 @@ static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
> >
> > if (qid && dev->cmb_use_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
> > nvmeq->sq_cmds = pci_alloc_p2pmem(pdev, SQ_SIZE(depth));
> > - nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> > - nvmeq->sq_cmds);
> > - if (nvmeq->sq_dma_addr) {
> > - set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> > - return 0;
> > + if (nvmeq->sq_cmds) {
> > + nvmeq->sq_dma_addr = pci_p2pmem_virt_to_bus(pdev,
> > + nvmeq->sq_cmds);
> > + if (nvmeq->sq_dma_addr) {
> > + set_bit(NVMEQ_SQ_CMB, &nvmeq->flags);
> > + return 0;
> > + }
> > +
> > + pci_free_p2pmem(pdev, nvmeq->sq_cmds, SQ_SIZE(depth));
>
> Should the pointer be set to NULL here, just in case?

Thanks Kenneth. The pointer gets immediately reassigned by the return
value of the
code that follows. There is no intervening reference to it between the calls to
pci_free_p2pmem() and dma_alloc_coherent(). It should be safe without
setting it to NULL.

nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, nvmeq->cq_size,
&nvmeq->sq_dma_addr, GFP_KERNEL);

>
> > }
> > }
> >
> >