[V2,1/6] bus/pci: fix a segfault when call callback

Message ID 20220915124522.5407-2-lihuisong@huawei.com (mailing list archive)
State Changes Requested, archived
Delegated to: Andrew Rybchenko
Headers
Series app/testpmd: support attach and detach port for MP |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

lihuisong (C) Sept. 15, 2022, 12:45 p.m. UTC
  After the driver probe is executed, the callback in application will
be called. The callback in application may call some APIs which access the
rte_pci_driver::driver by the device::driver pointer to get driver
information. If the rte_pci_device::device::driver pointer isn't pointed to
rte_pci_driver::driver in rte_pci_probe_one_driver, a segfault will occur.
For example, when ethdev driver probe completes, the callback in
application call rte_eth_dev_info_get which use dev->device->driver->name.
So rte_pci_device::device::driver should point to rte_pci_driver::driver
before executing the driver probe.

Fixes: c752998b5e2e ("pci: introduce library and driver")
Cc: stable@dpdk.org

Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
 drivers/bus/pci/pci_common.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
  

Comments

Thomas Monjalon Oct. 10, 2022, 7:49 p.m. UTC | #1
15/09/2022 14:45, Huisong Li:
> After the driver probe is executed, the callback in application will
> be called. The callback in application may call some APIs which access the
> rte_pci_driver::driver by the device::driver pointer to get driver
> information. If the rte_pci_device::device::driver pointer isn't pointed to
> rte_pci_driver::driver in rte_pci_probe_one_driver, a segfault will occur.
> For example, when ethdev driver probe completes, the callback in
> application call rte_eth_dev_info_get which use dev->device->driver->name.
> So rte_pci_device::device::driver should point to rte_pci_driver::driver
> before executing the driver probe.
> 
> Fixes: c752998b5e2e ("pci: introduce library and driver")
> Cc: stable@dpdk.org

To be more precise, it is reverting
391797f04208 ("drivers/bus: move driver assignment to end of probing")

dev->device.driver is used by rte_dev_is_probed():

int
rte_dev_is_probed(const struct rte_device *dev)
{
    /* The field driver should be set only when the probe is successful. */
    return dev->driver != NULL;
}

And the field comment is clear in rte_device:

const struct rte_driver *driver; /**< Driver assigned after probing */

That's why I am not enthusiastic about setting this pointer before probing.

I understand it is more convenient to use this pointer
in a probing callback.
We need to check it is not breaking rte_dev_is_probed() usage.
It may be OK if there is no parallel probing,
and rte_dev_is_probed() is not called inside probing.

At the very minimum, we need to update some comments in the code,
to mention that the pointer is set before probing,
and reset if probing failed.
  
lihuisong (C) Oct. 25, 2022, 3:25 a.m. UTC | #2
Hi Thomas,

I missed this e-mail, I'm sorry for late reply.

在 2022/10/11 3:49, Thomas Monjalon 写道:
> 15/09/2022 14:45, Huisong Li:
>> After the driver probe is executed, the callback in application will
>> be called. The callback in application may call some APIs which access the
>> rte_pci_driver::driver by the device::driver pointer to get driver
>> information. If the rte_pci_device::device::driver pointer isn't pointed to
>> rte_pci_driver::driver in rte_pci_probe_one_driver, a segfault will occur.
>> For example, when ethdev driver probe completes, the callback in
>> application call rte_eth_dev_info_get which use dev->device->driver->name.
>> So rte_pci_device::device::driver should point to rte_pci_driver::driver
>> before executing the driver probe.
>>
>> Fixes: c752998b5e2e ("pci: introduce library and driver")
>> Cc: stable@dpdk.org
> To be more precise, it is reverting
> 391797f04208 ("drivers/bus: move driver assignment to end of probing")
>
> dev->device.driver is used by rte_dev_is_probed():
>
> int
> rte_dev_is_probed(const struct rte_device *dev)
> {
>      /* The field driver should be set only when the probe is successful. */
>      return dev->driver != NULL;
> }
>
> And the field comment is clear in rte_device:
>
> const struct rte_driver *driver; /**< Driver assigned after probing */
>
> That's why I am not enthusiastic about setting this pointer before probing.
+1
>
> I understand it is more convenient to use this pointer
> in a probing callback.
> We need to check it is not breaking rte_dev_is_probed() usage.
> It may be OK if there is no parallel probing,
> and rte_dev_is_probed() is not called inside probing.
 From all the places where it's used, first of all, it is a internal 
interface
and only used when scan device on bus, remove device and hotplug device.

In process of scanning or probing device, the core code checks whether the
device is already probed by calling rte_dev_is_probed(). So I think it is ok
for parallel probing(if exist) to set dev->device.driver before probing 
successful.
The Concurrency between probing and removing should not be possible. The 
application
removes a device after device probing successful.

Currently, rte_dev_is_probed() isn't called inside probing.
>
> At the very minimum, we need to update some comments in the code,
> to mention that the pointer is set before probing,
> and reset if probing failed.
If it is ok for you, I will update some comments and add this 
modification to
other bus type in next version.
>
>
> .
  

Patch

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 37ab879779..831a9cd8c7 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -265,11 +265,22 @@  rte_pci_probe_one_driver(struct rte_pci_driver *dr,
 			dr->driver.name, dev->id.vendor_id, dev->id.device_id,
 			loc->domain, loc->bus, loc->devid, loc->function,
 			dev->device.numa_node);
+
+	/*
+	 * After the driver probe is executed, the callback in application will
+	 * be called. The callback in application may call some APIs which use
+	 * dev->device.driver to get some driver information. If the driver
+	 * pointer isn't pointed to driver->driver here, a segfault will occur.
+	 */
+	if (!already_probed)
+		dev->device.driver = &dr->driver;
+
 	/* call the driver probe() function */
 	ret = dr->probe(dr, dev);
 	if (already_probed)
 		return ret; /* no rollback if already succeeded earlier */
 	if (ret) {
+		dev->device.driver = NULL;
 		dev->driver = NULL;
 		if ((dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) &&
 			/* Don't unmap if device is unsupported and
@@ -282,8 +293,6 @@  rte_pci_probe_one_driver(struct rte_pci_driver *dr,
 		dev->vfio_req_intr_handle = NULL;
 		rte_intr_instance_free(dev->intr_handle);
 		dev->intr_handle = NULL;
-	} else {
-		dev->device.driver = &dr->driver;
 	}
 
 	return ret;