usb: setup authorized_default attributes using usb_bus_notify
Currently, the authorized_default and interface_authorized_default attributes for HCD are set up after the uevent has been sent to userland. This creates a race condition where userland may fail to access this file when processing the event. Move the appending of these attributes earlier relying on the usb_bus_notify dispatcher. Signed-off-by: Thiébaud Weksteen <tweek@google.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20190806110050.38918-1-tweek@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
c468a8aa79
Коммит
27709ae4e2
|
@ -103,11 +103,6 @@ static DEFINE_SPINLOCK(hcd_urb_unlink_lock);
|
|||
/* wait queue for synchronous unlinks */
|
||||
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
|
||||
|
||||
static inline int is_root_hub(struct usb_device *udev)
|
||||
{
|
||||
return (udev->parent == NULL);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
@ -880,101 +875,6 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Show & store the current value of authorized_default
|
||||
*/
|
||||
static ssize_t authorized_default_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *rh_usb_dev = to_usb_device(dev);
|
||||
struct usb_bus *usb_bus = rh_usb_dev->bus;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy);
|
||||
}
|
||||
|
||||
static ssize_t authorized_default_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
ssize_t result;
|
||||
unsigned val;
|
||||
struct usb_device *rh_usb_dev = to_usb_device(dev);
|
||||
struct usb_bus *usb_bus = rh_usb_dev->bus;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
result = sscanf(buf, "%u\n", &val);
|
||||
if (result == 1) {
|
||||
hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ?
|
||||
val : USB_DEVICE_AUTHORIZE_ALL;
|
||||
result = size;
|
||||
} else {
|
||||
result = -EINVAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static DEVICE_ATTR_RW(authorized_default);
|
||||
|
||||
/*
|
||||
* interface_authorized_default_show - show default authorization status
|
||||
* for USB interfaces
|
||||
*
|
||||
* note: interface_authorized_default is the default value
|
||||
* for initializing the authorized attribute of interfaces
|
||||
*/
|
||||
static ssize_t interface_authorized_default_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
|
||||
return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
|
||||
}
|
||||
|
||||
/*
|
||||
* interface_authorized_default_store - store default authorization status
|
||||
* for USB interfaces
|
||||
*
|
||||
* note: interface_authorized_default is the default value
|
||||
* for initializing the authorized attribute of interfaces
|
||||
*/
|
||||
static ssize_t interface_authorized_default_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
int rc = count;
|
||||
bool val;
|
||||
|
||||
if (strtobool(buf, &val) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val)
|
||||
set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RW(interface_authorized_default);
|
||||
|
||||
/* Group all the USB bus attributes */
|
||||
static struct attribute *usb_bus_attrs[] = {
|
||||
&dev_attr_authorized_default.attr,
|
||||
&dev_attr_interface_authorized_default.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group usb_bus_attr_group = {
|
||||
.name = NULL, /* we want them in the same directory */
|
||||
.attrs = usb_bus_attrs,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
|
@ -2894,32 +2794,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||
if (retval != 0)
|
||||
goto err_register_root_hub;
|
||||
|
||||
retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
|
||||
retval);
|
||||
goto error_create_attr_group;
|
||||
}
|
||||
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
|
||||
return retval;
|
||||
|
||||
error_create_attr_group:
|
||||
clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
|
||||
if (HC_IS_RUNNING(hcd->state))
|
||||
hcd->state = HC_STATE_QUIESCING;
|
||||
spin_lock_irq(&hcd_root_hub_lock);
|
||||
hcd->rh_registered = 0;
|
||||
spin_unlock_irq(&hcd_root_hub_lock);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
cancel_work_sync(&hcd->wakeup_work);
|
||||
#endif
|
||||
cancel_work_sync(&hcd->died_work);
|
||||
mutex_lock(&usb_bus_idr_lock);
|
||||
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
|
||||
mutex_unlock(&usb_bus_idr_lock);
|
||||
err_register_root_hub:
|
||||
hcd->rh_pollable = 0;
|
||||
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
|
||||
|
@ -2963,8 +2842,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)
|
|||
dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
|
||||
|
||||
usb_get_dev(rhdev);
|
||||
sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group);
|
||||
|
||||
clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
|
||||
if (HC_IS_RUNNING (hcd->state))
|
||||
hcd->state = HC_STATE_QUIESCING;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/quirks.h>
|
||||
#include <linux/of.h>
|
||||
#include "usb.h"
|
||||
|
@ -922,6 +923,116 @@ static struct bin_attribute dev_bin_attr_descriptors = {
|
|||
.size = 18 + 65535, /* dev descr + max-size raw descriptor */
|
||||
};
|
||||
|
||||
/*
|
||||
* Show & store the current value of authorized_default
|
||||
*/
|
||||
static ssize_t authorized_default_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *rh_usb_dev = to_usb_device(dev);
|
||||
struct usb_bus *usb_bus = rh_usb_dev->bus;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy);
|
||||
}
|
||||
|
||||
static ssize_t authorized_default_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
ssize_t result;
|
||||
unsigned int val;
|
||||
struct usb_device *rh_usb_dev = to_usb_device(dev);
|
||||
struct usb_bus *usb_bus = rh_usb_dev->bus;
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
result = sscanf(buf, "%u\n", &val);
|
||||
if (result == 1) {
|
||||
hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ?
|
||||
val : USB_DEVICE_AUTHORIZE_ALL;
|
||||
result = size;
|
||||
} else {
|
||||
result = -EINVAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static DEVICE_ATTR_RW(authorized_default);
|
||||
|
||||
/*
|
||||
* interface_authorized_default_show - show default authorization status
|
||||
* for USB interfaces
|
||||
*
|
||||
* note: interface_authorized_default is the default value
|
||||
* for initializing the authorized attribute of interfaces
|
||||
*/
|
||||
static ssize_t interface_authorized_default_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
|
||||
return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd));
|
||||
}
|
||||
|
||||
/*
|
||||
* interface_authorized_default_store - store default authorization status
|
||||
* for USB interfaces
|
||||
*
|
||||
* note: interface_authorized_default is the default value
|
||||
* for initializing the authorized attribute of interfaces
|
||||
*/
|
||||
static ssize_t interface_authorized_default_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct usb_device *usb_dev = to_usb_device(dev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus);
|
||||
int rc = count;
|
||||
bool val;
|
||||
|
||||
if (strtobool(buf, &val) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (val)
|
||||
set_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_INTF_AUTHORIZED, &hcd->flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
static DEVICE_ATTR_RW(interface_authorized_default);
|
||||
|
||||
/* Group all the USB bus attributes */
|
||||
static struct attribute *usb_bus_attrs[] = {
|
||||
&dev_attr_authorized_default.attr,
|
||||
&dev_attr_interface_authorized_default.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group usb_bus_attr_group = {
|
||||
.name = NULL, /* we want them in the same directory */
|
||||
.attrs = usb_bus_attrs,
|
||||
};
|
||||
|
||||
|
||||
static int add_default_authorized_attributes(struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (is_usb_device(dev))
|
||||
rc = sysfs_create_group(&dev->kobj, &usb_bus_attr_group);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void remove_default_authorized_attributes(struct device *dev)
|
||||
{
|
||||
if (is_usb_device(dev)) {
|
||||
sysfs_remove_group(&dev->kobj, &usb_bus_attr_group);
|
||||
}
|
||||
}
|
||||
|
||||
int usb_create_sysfs_dev_files(struct usb_device *udev)
|
||||
{
|
||||
struct device *dev = &udev->dev;
|
||||
|
@ -938,7 +1049,14 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
|
|||
retval = add_power_attributes(dev);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
if (is_root_hub(udev)) {
|
||||
retval = add_default_authorized_attributes(dev);
|
||||
if (retval)
|
||||
goto error;
|
||||
}
|
||||
return retval;
|
||||
|
||||
error:
|
||||
usb_remove_sysfs_dev_files(udev);
|
||||
return retval;
|
||||
|
@ -948,6 +1066,9 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
|
|||
{
|
||||
struct device *dev = &udev->dev;
|
||||
|
||||
if (is_root_hub(udev))
|
||||
remove_default_authorized_attributes(dev);
|
||||
|
||||
remove_power_attributes(dev);
|
||||
remove_persist_attributes(dev);
|
||||
device_remove_bin_file(dev, &dev_bin_attr_descriptors);
|
||||
|
|
|
@ -153,6 +153,11 @@ static inline int is_usb_port(const struct device *dev)
|
|||
return dev->type == &usb_port_device_type;
|
||||
}
|
||||
|
||||
static inline int is_root_hub(struct usb_device *udev)
|
||||
{
|
||||
return (udev->parent == NULL);
|
||||
}
|
||||
|
||||
/* Do the same for device drivers and interface drivers. */
|
||||
|
||||
static inline int is_usb_device_driver(struct device_driver *drv)
|
||||
|
|
Загрузка…
Ссылка в новой задаче