bnxt_en: Handle partially initialized auxiliary devices

bnxt_aux_devices_init() calls auxiliary_device_init() before all fields
used by bnxt_aux_dev_release() are initialized.  After
auxiliary_device_init() succeeds, later errors must unwind with
auxiliary_device_uninit(), which invokes the release callback.

The release callback assumes that aux_priv->id, aux_priv->edev,
edev->net and edev->ulp_tbl are all populated.  If allocation fails
after auxiliary_device_init(), the release path can otherwise dereference
or clear partially initialized state.

Allocate and attach the bnxt_en_dev and ULP table before calling
auxiliary_device_init(), so the release callback only sees a fully
initialized auxiliary private object.  If auxiliary_device_init() itself
fails, free those allocations directly because device_initialize() has not
run and the release callback will not be invoked.

This issue was found by a static analysis checker and confirmed by manual
source review.

Fixes: 194fad5b27 ("bnxt_en: Refactor bnxt_rdma_aux_device_init/uninit functions")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Link: https://patch.msgid.link/20260711163716.3996929-1-ruoyuw560@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Ruoyu Wang
2026-07-12 00:37:16 +08:00
committed by Paolo Abeni
parent e0b5252a59
commit 1cb8553c02

View File

@@ -566,6 +566,18 @@ void bnxt_aux_devices_init(struct bnxt *bp)
if (!aux_priv)
goto next_auxdev;
edev = kzalloc_obj(*edev);
if (!edev)
goto aux_priv_free;
aux_priv->edev = edev;
bnxt_set_edev_info(edev, bp);
ulp = kzalloc_obj(*ulp);
if (!ulp)
goto edev_free;
edev->ulp_tbl = ulp;
aux_priv->id = idx;
aux_dev = &aux_priv->aux_dev;
aux_dev->id = bp->auxdev_id;
aux_dev->name = bnxt_aux_devices[idx].name;
@@ -573,37 +585,26 @@ void bnxt_aux_devices_init(struct bnxt *bp)
aux_dev->dev.release = bnxt_aux_dev_release;
rc = auxiliary_device_init(aux_dev);
if (rc) {
kfree(aux_priv);
goto next_auxdev;
}
if (rc)
goto ulp_free;
bp->aux_priv[idx] = aux_priv;
/* From this point, all cleanup will happen via the .release
* callback & any error unwinding will need to include a call
* to auxiliary_device_uninit.
*/
edev = kzalloc_obj(*edev);
if (!edev)
goto aux_dev_uninit;
aux_priv->edev = edev;
bnxt_set_edev_info(edev, bp);
ulp = kzalloc_obj(*ulp);
if (!ulp)
goto aux_dev_uninit;
edev->ulp_tbl = ulp;
bp->edev[idx] = edev;
if (idx == BNXT_AUXDEV_RDMA)
bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
aux_priv->id = idx;
bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
continue;
aux_dev_uninit:
auxiliary_device_uninit(aux_dev);
ulp_free:
kfree(ulp);
edev_free:
kfree(edev);
aux_priv_free:
kfree(aux_priv);
next_auxdev:
if (idx == BNXT_AUXDEV_RDMA)
bp->flags &= ~BNXT_FLAG_ROCE_CAP;