[PATCH v2 0/9] can: usb: remove all usb_set_intfdata(intf, NULL) in drivers' disconnect()

Vincent Mailhol
2022-12-10T09:03:18Z

Many of the can usb drivers set their driver's priv data to NULL in
their disconnect function using below pattern:

struct driver_priv *priv = usb_get_intfdata(intf);

usb_set_intfdata(intf, NULL);

if (priv)
/* ... */

The pattern comes from other drivers which have a secondary interface
and for which disconnect() may be called twice. However, usb can
drivers do not have such secondary interface.

On the contrary, if a driver set the driver's priv data to NULL before
all actions relying on the interface-data pointer complete, there is a
risk of NULL pointer dereference. Typically, this is the case if there
are outstanding urbs which have not yet completed when entering
disconnect().

Finally, even if there is a valid reason to set the driver's priv
data, it would still be useless to do it in usb_driver::disconnect()
because the core sets the driver's data to NULL in [1] (and this
operation is done in within locked context, so that race conditions
should not occur).

The first seven patches fix all drivers which set their usb_interface
to NULL while outstanding URB might still exists. There is one patch
per driver in order to add the relevant "Fixes:" tag to each of them.

The eighth patch removes the check toward the driver data being
NULL. This just reduces the kernel size so no fixes tag here and all
changes are done in bulk in one single patch.

Finally, the last patch removes in bulk the remaining benign calls to
usb_set_intfdata(intf, NULL) in etas_es58x and peak_usb.

N.B. some other usb drivers outside of the can tree also have the same
issue, but this is out of scope of this series.

[1] function usb_unbind_interface() from drivers/usb/core/driver.c
Link: https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/core/driver.c#L497
---
* Changelog *

v1 -> v2

* add explanation in the cover letter on the origin of this pattern
and why it does not apply to can usb drivers.

* v1 claimed that usb_set_intfdata(intf, NULL) sets the
usb_interface to NULL. This is incorrect, it is the pointer to
driver's private data which set to NULL. Fix this point of
confusion in commit message.

* add a patch to clean up the useless check on the driver's private
data being NULL.

Vincent Mailhol (9):
can: ems_usb: ems_usb_disconnect(): fix NULL pointer dereference
can: esd_usb: esd_usb_disconnect(): fix NULL pointer dereference
can: gs_usb: gs_usb_disconnect(): fix NULL pointer dereference
can: kvaser_usb: kvaser_usb_disconnect(): fix NULL pointer dereference
can: mcba_usb: mcba_usb_disconnect(): fix NULL pointer dereference
can: ucan: ucan_disconnect(): fix NULL pointer dereference
can: usb_8dev: usb_8dev_disconnect(): fix NULL pointer dereference
can: usb: remove useless check on driver data
can: etas_es58x and peak_usb: remove useless call to
usb_set_intfdata()

drivers/net/can/usb/ems_usb.c | 16 ++++++----------
drivers/net/can/usb/esd_usb.c | 18 +++++++-----------
drivers/net/can/usb/etas_es58x/es58x_core.c | 1 -
drivers/net/can/usb/gs_usb.c | 7 -------
.../net/can/usb/kvaser_usb/kvaser_usb_core.c | 9 +--------
drivers/net/can/usb/mcba_usb.c | 2 --
drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 --
drivers/net/can/usb/ucan.c | 8 ++------
drivers/net/can/usb/usb_8dev.c | 13 ++++---------
9 files changed, 20 insertions(+), 56 deletions(-)

--
2.37.4