Re: [RFC 6/6] usb: check usb_hub_to_struct_hub() return value

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 24 May 2013, Sarah Sharp wrote:

> From: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
> 
> usb_hub_to_struct_hub() can return NULL in the unlikely cases a hub
> without active configuration, or a hub without ports is found.

I think the proper way to fix the last part is to prevent the hub
driver from binding to a hub with no ports.  Then it will be guaranteed
that usb_hub_to_struct_hub() will never return NULL whenever the hub
driver is bound to the device in question.

Even now, we are guaranteed that the return value will not be NULL if
the device has any child USB devices or any ports (i.e., if its
maxchild value is larger than 0).  Therefore almost all of the checks
added in this patch are not necessary.

> Even if unlikely we need to handle those cases properly.

However, we don't have to if they are not just unlikely but impossible.

> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -730,7 +730,12 @@ int usb_hub_set_port_power(struct usb_device *hdev, int port1,
>  {
>  	int ret;
>  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
> -	struct usb_port *port_dev = hub->ports[port1 - 1];
> +	struct usb_port *port_dev;
> +
> +	if (!hub)
> +		return -EINVAL;

This routine is called from only two places, and in both places it is 
known that the return value isn't NULL.  On the other hand, it might 
make more sense to pass the hub pointer as an additional argument to 
usb_hub_set_port_power(), so the issue doesn't arise at all.

> @@ -964,6 +969,10 @@ int usb_remove_device(struct usb_device *udev)
>  	if (!udev->parent)	/* Can't remove a root hub */
>  		return -EINVAL;
>  	hub = usb_hub_to_struct_hub(udev->parent);
> +
> +	if (!hub)
> +		return -EINVAL;

Not needed since we know there is a child device.

> @@ -1733,6 +1742,9 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
>  	struct usb_device *hdev = interface_to_usbdev (intf);
>  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
>  
> +	if (!hub)
> +		return -EINVAL;

This should be fixed by not binding to hubs with no ports.

> @@ -1769,15 +1781,17 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
>  static int find_port_owner(struct usb_device *hdev, unsigned port1,
>  		struct dev_state ***ppowner)
>  {
> +	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
> +
>  	if (hdev->state == USB_STATE_NOTATTACHED)
>  		return -ENODEV;
> -	if (port1 == 0 || port1 > hdev->maxchild)
> +	if (port1 == 0 || port1 > hdev->maxchild || !hub)
>  		return -EINVAL;

The test is not needed since the hdev->maxchild cannot be larger than 0
if the hub driver isn't bound.

>  	/* This assumes that devices not managed by the hub driver
>  	 * will always have maxchild equal to 0.
>  	 */
> -	*ppowner = &(usb_hub_to_struct_hub(hdev)->ports[port1 - 1]->port_owner);
> +	*ppowner = &(hub->ports[port1 - 1]->port_owner);

This change is okay.  The comment should be updated as well, since the
fact it refers to is not an assumption but is guaranteed.

Most of the remaining changes in this patch aren't needed, for reasons
already mentioned.

> @@ -5323,7 +5367,8 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1,
>  {
>  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
>  
> -	hub->ports[port1 - 1]->connect_type = type;
> +	if (hub)
> +		hub->ports[port1 - 1]->connect_type = type;
>  }
>  
>  /**
> @@ -5339,6 +5384,9 @@ usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
>  {
>  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
>  
> +	if (!hub)
> +		return USB_PORT_CONNECT_TYPE_UNKNOWN;
> +
>  	return hub->ports[port1 - 1]->connect_type;
>  }
>  
> @@ -5397,6 +5445,9 @@ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
>  {
>  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
>  
> +	if (!hub)
> +		return NULL;
> +
>  	return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev);
>  }

These three changes probably aren't needed either, but verifying it is 
a little more complicated since the callers are in a different source 
file.  I guess it won't hurt to keep them.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux