If auxiliary_device_add() fails, idpf_plug_core_aux_dev() calls
auxiliary_device_uninit(adev), whose release callback
idpf_core_adev_release() frees the containing
struct iidc_rdma_core_auxiliary_dev.

The current error path then accesses adev->id and later frees iadev
again, which may lead to a use-after-free and double free.

Fix it by storing the allocated auxiliary device id in a local
variable and avoiding direct freeing of iadev after
auxiliary_device_uninit().

Fixes: f4312e6bfa2a ("idpf: implement core RDMA auxiliary dev create, init, and 
destroy")
Cc: [email protected]
Signed-off-by: Guangshuo Li <[email protected]>
---
 drivers/net/ethernet/intel/idpf/idpf_idc.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c 
b/drivers/net/ethernet/intel/idpf/idpf_idc.c
index 6dad0593f7f2..0fcbf9f1ddbb 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
@@ -197,6 +197,7 @@ static int idpf_plug_core_aux_dev(struct 
iidc_rdma_core_dev_info *cdev_info)
        char name[IDPF_IDC_MAX_ADEV_NAME_LEN];
        struct auxiliary_device *adev;
        int ret;
+       int id;
 
        iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
        if (!iadev)
@@ -211,12 +212,16 @@ static int idpf_plug_core_aux_dev(struct 
iidc_rdma_core_dev_info *cdev_info)
                pr_err("failed to allocate unique device ID for Auxiliary 
driver\n");
                goto err_ida_alloc;
        }
-       adev->id = ret;
+       id = ret;
+       adev->id = id;
        adev->dev.release = idpf_core_adev_release;
        adev->dev.parent = &cdev_info->pdev->dev;
        sprintf(name, "%04x.rdma.core", cdev_info->pdev->vendor);
        adev->name = name;
 
+       /* iadev is owned by the auxiliary device */
+       iadev = NULL;
+
        ret = auxiliary_device_init(adev);
        if (ret)
                goto err_aux_dev_init;
@@ -230,7 +235,7 @@ static int idpf_plug_core_aux_dev(struct 
iidc_rdma_core_dev_info *cdev_info)
 err_aux_dev_add:
        auxiliary_device_uninit(adev);
 err_aux_dev_init:
-       ida_free(&idpf_idc_ida, adev->id);
+       ida_free(&idpf_idc_ida, id);
 err_ida_alloc:
        cdev_info->adev = NULL;
        kfree(iadev);
-- 
2.43.0

Reply via email to