]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bnxt_en: Handle partially initialized auxiliary devices
authorRuoyu Wang <ruoyuw560@gmail.com>
Sat, 11 Jul 2026 16:37:16 +0000 (00:37 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Fri, 17 Jul 2026 10:43:57 +0000 (12:43 +0200)
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: 194fad5b2781 ("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>
drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c

index 5c751933da6a9d9852f08cd54a50f1bf98e5d56f..a515c368bac0153e1c33298e5a0f025a11dd70e1 100644 (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;