All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference
@ 2024-01-29  9:37 Xu Yang
  2024-01-29  9:37 ` [PATCH v3 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
  2024-01-30 14:19 ` [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference Heikki Krogerus
  0 siblings, 2 replies; 4+ messages in thread
From: Xu Yang @ 2024-01-29  9:37 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
Changes in v3:
 - no changes
---
 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 v3 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered
  2024-01-29  9:37 [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference Xu Yang
@ 2024-01-29  9:37 ` Xu Yang
  2024-01-30 14:19   ` Heikki Krogerus
  2024-01-30 14:19 ` [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference Heikki Krogerus
  1 sibling, 1 reply; 4+ messages in thread
From: Xu Yang @ 2024-01-29  9:37 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.

Fixes: fde0aa6c175a ("usb: common: Small class for USB role switches")
cc: <stable@vger.kernel.org>
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>

---
Changes in v2:
 - new patch during test patch 1
 - add registered flag
Changes in v3:
 - add fix tag and stable list
---
 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 v3 1/2] usb: roles: fix NULL pointer issue when put module's reference
  2024-01-29  9:37 [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference Xu Yang
  2024-01-29  9:37 ` [PATCH v3 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
@ 2024-01-30 14:19 ` Heikki Krogerus
  1 sibling, 0 replies; 4+ messages in thread
From: Heikki Krogerus @ 2024-01-30 14:19 UTC (permalink / raw)
  To: Xu Yang
  Cc: gregkh, benjamin.tissoires, hdegoede, ivan.orlov0322, linux-usb,
	linux-imx, jun.li, stern

On Mon, Jan 29, 2024 at 05:37:38PM +0800, Xu Yang wrote:
> 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>

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
> Changes in v2:
>  - save module pointer as a member of usb_role_switch as suggested by Alan
> Changes in v3:
>  - no changes
> ---
>  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

-- 
heikki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered
  2024-01-29  9:37 ` [PATCH v3 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
@ 2024-01-30 14:19   ` Heikki Krogerus
  0 siblings, 0 replies; 4+ messages in thread
From: Heikki Krogerus @ 2024-01-30 14:19 UTC (permalink / raw)
  To: Xu Yang
  Cc: gregkh, benjamin.tissoires, hdegoede, ivan.orlov0322, linux-usb,
	linux-imx, jun.li, stern

On Mon, Jan 29, 2024 at 05:37:39PM +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.
> 
> Fixes: fde0aa6c175a ("usb: common: Small class for USB role switches")
> cc: <stable@vger.kernel.org>
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
> Changes in v2:
>  - new patch during test patch 1
>  - add registered flag
> Changes in v3:
>  - add fix tag and stable list
> ---
>  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

-- 
heikki

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-01-30 14:19 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-29  9:37 [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference Xu Yang
2024-01-29  9:37 ` [PATCH v3 2/2] usb: roles: don't get/set_role() when usb_role_switch is unregistered Xu Yang
2024-01-30 14:19   ` Heikki Krogerus
2024-01-30 14:19 ` [PATCH v3 1/2] usb: roles: fix NULL pointer issue when put module's reference Heikki Krogerus

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.