mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
RDMA/cxgb4: Fix dereg_skb leak and double free in write_tpt_entry()
When the device is in the fatal error state, write_tpt_entry() returns -EIO
before handing the caller's preallocated skb to the transmit path; its
allocation-failure returns do the same. c4iw_dereg_mr() ignores the error
and frees mhp, leaking mhp->dereg_skb. c4iw_get_dma_mr() instead frees the
skb a second time after dereg_mem() already consumed it, a double free.
Make write_tpt_entry() the sole owner of a non-NULL skb, freeing it on
every return preceding handoff to c4iw_ofld_send(): fatal error, tpt and
stag allocation failure. c4iw_ofld_send() consumes the skb on success and
error alike, so drop the redundant kfree_skb() in c4iw_get_dma_mr() after
dereg_mem().
Fixes: 0f8ab0b6e9 ("RDMA/iw_cxgb4: Low resource fixes for Memory registration")
Link: https://patch.msgid.link/20260726-leaked-mhp-dereg-skb-in-c4iw-dereg-m-v1-1-ebd6df364d53@nvidia.com
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
This commit is contained in:
parent
229b42d745
commit
373f3716a2
|
|
@ -193,7 +193,8 @@ static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len,
|
|||
|
||||
daddr = dma_map_single(&rdev->lldi.pdev->dev, data, len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(&rdev->lldi.pdev->dev, daddr))
|
||||
return -1;
|
||||
return _c4iw_write_mem_inline(rdev, addr, len, data, skb,
|
||||
wr_waitp);
|
||||
save = daddr;
|
||||
|
||||
while (remain > inline_threshold) {
|
||||
|
|
@ -229,30 +230,12 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
|
|||
void *data, struct sk_buff *skb,
|
||||
struct c4iw_wr_wait *wr_waitp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl) {
|
||||
ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
|
||||
if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl ||
|
||||
len <= inline_threshold)
|
||||
return _c4iw_write_mem_inline(rdev, addr, len, data, skb,
|
||||
wr_waitp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len <= inline_threshold) {
|
||||
ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
|
||||
wr_waitp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
|
||||
if (ret) {
|
||||
pr_warn_ratelimited("%s: dma map failure (non fatal)\n",
|
||||
pci_name(rdev->lldi.pdev));
|
||||
ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
|
||||
wr_waitp);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
|
||||
return _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -273,12 +256,16 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
|
|||
u32 stag_idx;
|
||||
static atomic_t key;
|
||||
|
||||
if (c4iw_fatal_error(rdev))
|
||||
if (c4iw_fatal_error(rdev)) {
|
||||
kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
tpt = kmalloc_obj(*tpt);
|
||||
if (!tpt)
|
||||
if (!tpt) {
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
stag_state = stag_state > 0;
|
||||
stag_idx = (*stag) >> 8;
|
||||
|
|
@ -290,6 +277,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
|
|||
rdev->stats.stag.fail++;
|
||||
mutex_unlock(&rdev->stats.lock);
|
||||
kfree(tpt);
|
||||
kfree_skb(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
mutex_lock(&rdev->stats.lock);
|
||||
|
|
@ -463,8 +451,10 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
|
|||
FW_RI_STAG_NSMR, mhp->attr.perms,
|
||||
mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0,
|
||||
NULL, mhp->wr_waitp);
|
||||
if (ret)
|
||||
goto err_free_skb;
|
||||
if (ret) {
|
||||
kfree_skb(mhp->dereg_skb);
|
||||
goto err_free_wr_wait;
|
||||
}
|
||||
|
||||
ret = finish_mem_reg(mhp, stag);
|
||||
if (ret)
|
||||
|
|
@ -473,8 +463,6 @@ struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
|
|||
err_dereg_mem:
|
||||
dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
|
||||
mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
|
||||
err_free_skb:
|
||||
kfree_skb(mhp->dereg_skb);
|
||||
err_free_wr_wait:
|
||||
c4iw_put_wr_wait(mhp->wr_waitp);
|
||||
err_free_mhp:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user