* [PATCH v2 1/2] usb: roles: fix NULL pointer issue when put module's reference
@ 2024-01-24 6:45 Xu Yang
2024-01-24 6:45 ` [PATCH v2 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
0 siblings, 1 reply; 4+ messages in thread
From: Xu Yang @ 2024-01-24 6:45 UTC (permalink / raw)
To: gregkh, benjamin.tissoires, hdegoede, ivan.orlov0322,
heikki.krogerus
Cc: linux-usb, linux-imx, jun.li, stern
In current design, usb role class driver will get usb_role_switch parent's
module reference after the user get usb_role_switch device and put the
reference after the user put the usb_role_switch device. However, the
parent device of usb_role_switch may be removed before the user put the
usb_role_switch. If so, then, NULL pointer issue will be met when the user
put the parent module's reference.
This will save the module pointer in structure of usb_role_switch. Then,
we don't need to find module by iterating long relations.
Fixes: 5c54fcac9a9d ("usb: roles: Take care of driver module reference counting")
cc: <stable@vger.kernel.org>
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
Changes in v2:
- save module pointer as a member of usb_role_switch as suggested by Alan
---
drivers/usb/roles/class.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index ae41578bd014..2bad038fb9ad 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -21,6 +21,7 @@ static const struct class role_class = {
struct usb_role_switch {
struct device dev;
struct mutex lock; /* device lock*/
+ struct module *module; /* the module this device depends on */
enum usb_role role;
/* From descriptor */
@@ -135,7 +136,7 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev)
usb_role_switch_match);
if (!IS_ERR_OR_NULL(sw))
- WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
+ WARN_ON(!try_module_get(sw->module));
return sw;
}
@@ -157,7 +158,7 @@ struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *fwnode)
sw = fwnode_connection_find_match(fwnode, "usb-role-switch",
NULL, usb_role_switch_match);
if (!IS_ERR_OR_NULL(sw))
- WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
+ WARN_ON(!try_module_get(sw->module));
return sw;
}
@@ -172,7 +173,7 @@ EXPORT_SYMBOL_GPL(fwnode_usb_role_switch_get);
void usb_role_switch_put(struct usb_role_switch *sw)
{
if (!IS_ERR_OR_NULL(sw)) {
- module_put(sw->dev.parent->driver->owner);
+ module_put(sw->module);
put_device(&sw->dev);
}
}
@@ -189,15 +190,18 @@ struct usb_role_switch *
usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode)
{
struct device *dev;
+ struct usb_role_switch *sw = NULL;
if (!fwnode)
return NULL;
dev = class_find_device_by_fwnode(&role_class, fwnode);
- if (dev)
- WARN_ON(!try_module_get(dev->parent->driver->owner));
+ if (dev) {
+ sw = to_role_switch(dev);
+ WARN_ON(!try_module_get(sw->module));
+ }
- return dev ? to_role_switch(dev) : NULL;
+ return sw;
}
EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode);
@@ -338,6 +342,7 @@ usb_role_switch_register(struct device *parent,
sw->set = desc->set;
sw->get = desc->get;
+ sw->module = parent->driver->owner;
sw->dev.parent = parent;
sw->dev.fwnode = desc->fwnode;
sw->dev.class = &role_class;
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered
2024-01-24 6:45 [PATCH v2 1/2] usb: roles: fix NULL pointer issue when put module's reference Xu Yang
@ 2024-01-24 6:45 ` Xu Yang
2024-01-24 12:38 ` Greg KH
0 siblings, 1 reply; 4+ messages in thread
From: Xu Yang @ 2024-01-24 6:45 UTC (permalink / raw)
To: gregkh, benjamin.tissoires, hdegoede, ivan.orlov0322,
heikki.krogerus
Cc: linux-usb, linux-imx, jun.li, stern
There is a possibility that usb_role_switch device is unregistered before
the user put usb_role_switch. In this case, the user may still want to
get/set_role() since the user can't sense the changes of usb_role_switch.
This will add a flag to show if usb_role_switch is already registered and
avoid unwanted behaviors.
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
Changes in v2:
- new patch during test patch 1
- add registered flag
---
drivers/usb/roles/class.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index 2bad038fb9ad..70165dd86b5d 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -23,6 +23,7 @@ struct usb_role_switch {
struct mutex lock; /* device lock*/
struct module *module; /* the module this device depends on */
enum usb_role role;
+ bool registered;
/* From descriptor */
struct device *usb2_port;
@@ -49,6 +50,9 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
if (IS_ERR_OR_NULL(sw))
return 0;
+ if (!sw->registered)
+ return -EOPNOTSUPP;
+
mutex_lock(&sw->lock);
ret = sw->set(sw, role);
@@ -74,7 +78,7 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
{
enum usb_role role;
- if (IS_ERR_OR_NULL(sw))
+ if (IS_ERR_OR_NULL(sw) || !sw->registered)
return USB_ROLE_NONE;
mutex_lock(&sw->lock);
@@ -357,6 +361,8 @@ usb_role_switch_register(struct device *parent,
return ERR_PTR(ret);
}
+ sw->registered = true;
+
/* TODO: Symlinks for the host port and the device controller. */
return sw;
@@ -371,8 +377,10 @@ EXPORT_SYMBOL_GPL(usb_role_switch_register);
*/
void usb_role_switch_unregister(struct usb_role_switch *sw)
{
- if (!IS_ERR_OR_NULL(sw))
+ if (!IS_ERR_OR_NULL(sw)) {
+ sw->registered = false;
device_unregister(&sw->dev);
+ }
}
EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered
2024-01-24 6:45 ` [PATCH v2 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
@ 2024-01-24 12:38 ` Greg KH
2024-01-26 3:23 ` [EXT] " Xu Yang
0 siblings, 1 reply; 4+ messages in thread
From: Greg KH @ 2024-01-24 12:38 UTC (permalink / raw)
To: Xu Yang
Cc: benjamin.tissoires, hdegoede, ivan.orlov0322, heikki.krogerus,
linux-usb, linux-imx, jun.li, stern
On Wed, Jan 24, 2024 at 02:45:54PM +0800, Xu Yang wrote:
> There is a possibility that usb_role_switch device is unregistered before
> the user put usb_role_switch. In this case, the user may still want to
> get/set_role() since the user can't sense the changes of usb_role_switch.
>
> This will add a flag to show if usb_role_switch is already registered and
> avoid unwanted behaviors.
>
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
>
> ---
> Changes in v2:
> - new patch during test patch 1
> - add registered flag
> ---
> drivers/usb/roles/class.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
> index 2bad038fb9ad..70165dd86b5d 100644
> --- a/drivers/usb/roles/class.c
> +++ b/drivers/usb/roles/class.c
> @@ -23,6 +23,7 @@ struct usb_role_switch {
> struct mutex lock; /* device lock*/
> struct module *module; /* the module this device depends on */
> enum usb_role role;
> + bool registered;
>
> /* From descriptor */
> struct device *usb2_port;
> @@ -49,6 +50,9 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
> if (IS_ERR_OR_NULL(sw))
> return 0;
>
> + if (!sw->registered)
> + return -EOPNOTSUPP;
What's to prevent this from changing right after you check it?
And why is this patch not cc: stable and have a fixes tag if it resolves
a real issue for people?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 4+ messages in thread
* RE: [EXT] Re: [PATCH v2 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered
2024-01-24 12:38 ` Greg KH
@ 2024-01-26 3:23 ` Xu Yang
0 siblings, 0 replies; 4+ messages in thread
From: Xu Yang @ 2024-01-26 3:23 UTC (permalink / raw)
To: Greg KH
Cc: benjamin.tissoires@redhat.com, hdegoede@redhat.com,
ivan.orlov0322@gmail.com, heikki.krogerus@linux.intel.com,
linux-usb@vger.kernel.org, dl-linux-imx, Jun Li,
stern@rowland.harvard.edu
Hi Greg,
>
> On Wed, Jan 24, 2024 at 02:45:54PM +0800, Xu Yang wrote:
> > There is a possibility that usb_role_switch device is unregistered before
> > the user put usb_role_switch. In this case, the user may still want to
> > get/set_role() since the user can't sense the changes of usb_role_switch.
> >
> > This will add a flag to show if usb_role_switch is already registered and
> > avoid unwanted behaviors.
> >
> > Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
> >
> > ---
> > Changes in v2:
> > - new patch during test patch 1
> > - add registered flag
> > ---
> > drivers/usb/roles/class.c | 12 ++++++++++--
> > 1 file changed, 10 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
> > index 2bad038fb9ad..70165dd86b5d 100644
> > --- a/drivers/usb/roles/class.c
> > +++ b/drivers/usb/roles/class.c
> > @@ -23,6 +23,7 @@ struct usb_role_switch {
> > struct mutex lock; /* device lock*/
> > struct module *module; /* the module this device depends on */
> > enum usb_role role;
> > + bool registered;
> >
> > /* From descriptor */
> > struct device *usb2_port;
> > @@ -49,6 +50,9 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
> > if (IS_ERR_OR_NULL(sw))
> > return 0;
> >
> > + if (!sw->registered)
> > + return -EOPNOTSUPP;
>
> What's to prevent this from changing right after you check it?
Usually , the usb_role_switch device is unregistered after usb controller
device is removed.
Such as dwc3 platform, if the usb controller is in device mode at first,
dwc3_gadget_exit() will be called when removing dwc3 controller device
by unbind the device. If typec port changes to DFP, tcpm will set usb role
to host mode and usb_role_switch_set_role() is called. Then dwc3 controller
driver will call dwc3_gadget_exit() again to switch from gadget to host mode.
But this time kernel will dump NULL pointer issue since gadget resource is
already released.
[ 46.065015] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000008
[ 46.074030] Mem abort info:
[ 46.076915] ESR = 0x0000000096000045
[ 46.080742] EC = 0x25: DABT (current EL), IL = 32 bits
[ 46.086155] SET = 0, FnV = 0
...
[ 46.272542] Call trace:
[ 46.274986] usb_del_gadget+0x44/0xac
[ 46.278651] dwc3_gadget_exit+0x20/0x7c
[ 46.282490] __dwc3_set_mode+0x280/0x3ec
[ 46.286408] process_one_work+0x138/0x248
[ 46.290421] worker_thread+0x320/0x438
[ 46.294173] kthread+0x110/0x114
[ 46.297406] ret_from_fork+0x10/0x20
[ 46.300992] Code: f94186a4 d2802002 f9418aa3 f2fbd5a2 (f9000483)
[ 46.307079] ---[ end trace 0000000000000000 ]---
In chipidea platform, I also get below kernel dump.
[ 78.499672] Unable to handle kernel paging request at virtual address ffff8000822a51a4
[ 78.507588] Mem abort info:
[ 78.510366] ESR = 0x0000000096000007
[ 78.514102] EC = 0x25: DABT (current EL), IL = 32 bits
[ 78.519397] SET = 0, FnV = 0
...
[ 78.705713] Call trace:
[ 78.708149] hw_read_otgsc+0x8/0xf4
[ 78.711632] ci_usb_role_switch_set+0x94/0x2c4
[ 78.716069] usb_role_switch_set_role+0x44/0x98
[ 78.720593] tcpm_mux_set+0x5c/0x80
[ 78.724069] tcpm_set_roles+0x64/0xd4
[ 78.727717] tcpm_state_machine_work+0x2350/0x2ff4
[ 78.732502] kthread_worker_fn+0xc4/0x174
[ 78.736506] kthread+0x110/0x114
[ 78.739721] ret_from_fork+0x10/0x20
[ 78.743295] Code: 88dffc21 88dffc00 f9405c02 aa0003e3 (b9400042)
[ 78.749377] ---[ end trace 0000000000000000 ]---
Maybe these platforms lack some checks about the resources. But, first of all,
->set_role() should not be called at all when usb_role_switch device is
Unregistered.
>
> And why is this patch not cc: stable and have a fixes tag if it resolves
> a real issue for people?
Sorry, I forget that. Will add it in next version.
Thanks,
Xu Yang
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-01-26 3:23 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-24 6:45 [PATCH v2 1/2] usb: roles: fix NULL pointer issue when put module's reference Xu Yang
2024-01-24 6:45 ` [PATCH v2 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
2024-01-24 12:38 ` Greg KH
2024-01-26 3:23 ` [EXT] " Xu Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).